1
\$\begingroup\$

I have a form for an item (Job Item), that has sets of 2 fields based on a type.

field and field + _dolar

e.g: cogs_paid and cogs_paid_dollar

validation example: cogs_paid or cogs_paid_dollar, if both are empty, validation fails. This goes for all sub-fields.

What I did, my current Model:

 class JobItem < ActiveRecord::Base

  COGS_REQUIRED_TYPES = [
    ContentType::Brief,
    ContentType::Feature,
    ContentType::Fish,
    ContentType::Paid,
    ContentType::Print,
    ContentType::Target
  ].freeze

  include MessageBroker
  message_broker model_name: 'JobItem'

  belongs_to :job

  validates :weekly_budget, presence: { if: -> { COGS_REQUIRED_TYPES.include?(content_type) } }

  validates :cogs_brief_write_lead,
    presence: {
      if: -> { content_type == ContentType::Brief && cogs_brief_write_lead_dollar.blank? },
      message: 'cant be empty or provide COGS Actual Cost matching entry',
    }

  validates :cogs_brief_write_copy,
    presence: {
      if: -> { content_type == ContentType::Brief && cogs_brief_write_copy_dollar.blank? },
      message: 'cant be empty or provide COGS Actual Cost matching entry',
    }

  validates :cogs_brief_copy_edit,
    presence: {
      if: -> { content_type == ContentType::Brief && cogs_brief_copy_edit_dollar.blank? },
      message: 'cant be empty or provide COGS Actual Cost matching entry',
    }

  validates :cogs_write_lead,
    presence: {
      if: -> { content_type == ContentType::Feature && cogs_write_lead_dollar.blank? },
      message: 'cant be empty or provide COGS Actual Cost matching entry',
    }

  validates :cogs_interview,
    presence: {
      if: -> { content_type == ContentType::Feature && cogs_interview_dollar.blank? },
      message: 'cant be empty or provide COGS Actual Cost matching entry',
    }

  validates :cogs_write_feature,
    presence: {
      if: -> { content_type == ContentType::Feature && cogs_write_feature_dollar.blank? },
      message: 'cant be empty or provide COGS Actual Cost matching entry',
    }

  validates :cogs_content_edit,
    presence: {
      if: -> { content_type == ContentType::Feature && cogs_content_edit_dollar.blank? },
      message: 'cant be empty or provide COGS Actual Cost matching entry',
    }

  validates :cogs_copy_edit,
    presence: {
      if: -> { content_type == ContentType::Feature && cogs_copy_edit_dollar.blank? },
      message: 'cant be empty or provide COGS Actual Cost matching entry',
    }

  validates :cogs_paid_write_lead,
    presence: {
      if: -> { content_type == ContentType::Paid && cogs_paid_write_lead_dollar.blank? },
      message: 'cant be empty or provide COGS Actual Cost matching entry',
    }

  validates :cogs_paid_interview_research,
    presence: {
      if: -> { content_type == ContentType::Paid && cogs_paid_interview_research_dollar.blank? },
      message: 'cant be empty or provide COGS Actual Cost matching entry',
    }

  validates :cogs_paid_write_copy,
    presence: {
      if: -> { content_type == ContentType::Paid && cogs_paid_write_copy_dollar.blank? },
      message: 'cant be empty or provide COGS Actual Cost matching entry',
    }

  validates :cogs_paid_copy_edit,
    presence: {
      if: -> { content_type == ContentType::Paid && cogs_paid_copy_edit_dollar.blank? },
      message: 'cant be empty or provide COGS Actual Cost matching entry',
    }

  validates :cogs_paid_review,
    presence: {
      if: -> { content_type == ContentType::Paid && cogs_paid_review_dollar.blank? },
      message: 'cant be empty or provide COGS Actual Cost matching entry',
    }

  validates :cogs_paid_publish,
    presence: {
      if: -> { content_type == ContentType::Paid && cogs_paid_publish_dollar.blank? },
      message: 'cant be empty or provide COGS Actual Cost matching entry',
    }

  validates :cogs_design,
    presence: {
      if: -> { content_type == ContentType::Print && cogs_design_dollar.blank? },
      message: 'cant be empty or provide COGS Actual Cost matching entry',
    }

  validates :cogs_page_edit,
    presence: {
      if: -> { content_type == ContentType::Print && cogs_page_edit_dollar.blank? },
      message: 'cant be empty or provide COGS Actual Cost matching entry',
    }

  validates :cogs_page_proof,
    presence: {
      if: -> { content_type == ContentType::Print && cogs_page_proof_dollar.blank? },
      message: 'cant be empty or provide COGS Actual Cost matching entry',
    }

  validates :cogs_photo_toning,
    presence: {
      if: -> { content_type == ContentType::Print && cogs_photo_toning_dollar.blank? },
      message: 'cant be empty or provide COGS Actual Cost matching entry',
    }

  def content_type=(value)
    new_type = ContentType.find(value)
    self[:content_type] = new_type ? new_type.id.to_s : nil
  end

  ContentType.types.each do |method, klass|
    define_method :"#{method}?" do
      content_type == klass
    end
  end


end


I currently have 20+ validations like the one above on my model, (for each sub-field and its type) which looks pretty ugly.

Any suggestions on how one would improve this, and reduce repetition?

What changes on every validation is:

field ; field+_dollar

content_type being compared: e.g ContentType::Paid

\$\endgroup\$
1
\$\begingroup\$

Changed to, on the model


  COGS_FIELDS_PRESENCE = [
    [content_type: 'brief', cogs_field: 'cogs_brief_write_lead', cogs_field_dollar: 'cogs_brief_write_lead_dollar'],
    [content_type: 'brief', cogs_field: 'cogs_brief_write_copy', cogs_field_dollar: 'cogs_brief_write_copy_dollar'],
    .
    .
    . + 20 entries

  ]


  def cogs_fields_presence
    COGS_FIELDS_PRESENCE.flatten.each do |field|
      if content_type.to_s == field[:content_type] && self[field[:cogs_field]].blank? && self[field[:cogs_field_dollar]].blank?
        errors.add(field[:cogs_field], 'cant be empty or provide COGS Actual Cost matching entry')
      end
    end
  end
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.