app/models/vote_post.rb

Summary

Maintainability
A
45 mins
Test Coverage
# frozen_string_literal: true

# Holds a users vote for a specific voting
class VotePost < ApplicationRecord
  acts_as_paranoid

  belongs_to :vote
  belongs_to :user

  has_many :audits, as: :auditable

  attr_accessor :vote_option_ids, :votecode

  validates :votecode, presence: true
  validates :user_id, uniqueness: { scope: :vote_id,
                                    message: I18n.t('model.vote_post.already_voted') }
  validate :vote_open, :user_details, :option_details

  after_create :log_create
  after_update :log_update
  after_destroy :log_destroy

  def log_create
    Audit.create!(auditable: self, user_id: user_id, vote_id: vote_id,
                  audited_changes: create_changes,
                  action: 'create', updater_id: updater)
  end

  def log_update
    log('update') if log_changes.present?
  end

  def log_destroy
    log('destroy')
  end

  def log(action)
    Audit.create!(auditable: self, user_id: user_id, vote_id: vote_id,
                  audited_changes: log_changes,
                  action: action, updater_id: updater)
  end

  def create_changes
    saved_changes.except(:created_at, :updated_at, :deleted_at, :id, :selected)
  end

  def log_changes
    saved_changes.except(:created_at, :updated_at, :deleted_at, :id)
  end

  def updater
    User.current.id if User.current && !destroyed?
  end

  def trim_votecode
    self.votecode = votecode.gsub(/[^0-9a-zA-Z]/, '')
  end

  private

  def user_details
    return if User.exists?(id: user_id, votecode: votecode, presence: true)
    errors.add(:votecode, I18n.t('model.vote_post.bad_votecode_or_presence'))
  end

  def vote_open
    return if vote.present? && vote.open?
    errors.add(:votecode, I18n.t('model.vote_post.vote_closed'))
  end

  def option_details
    return unless vote_option_ids.present?
    unless vote_option_ids.count <= vote.choices
      errors.add(:vote_option_ids, I18n.t('model.vote_post.too_many_options'))
    end
    unless vote_option_ids.uniq.count == vote_option_ids.count
      errors.add(:vote_option_ids, I18n.t('model.vote_post.same_option_twice'))
    end
    unless (vote_option_ids.map(&:to_i) - vote.vote_option_ids).empty?
      errors.add(:vote_option_ids, I18n.t('model.vote_post.unallowed_options'))
    end
  end
end