Rails/ActiveModel passing arguments to EachValidator
Asked Answered
A

1

13

I have a very generic validator and I want to pass it arguments.

Here is an example model:

class User
  include Mongoid::Document

  field :order_type
  has_many :orders, inverse_of :user
  validates: orders, generic: true #i want to pass argument (order_type)

  field :task_type
  has_many :tasks, inverse_of :user
  validates: tasks, generic: true #i want to pass argument (task_type)
end

and Example validator:

class GenericValidator < ActiveModel::EachValidator
  def validate_each(object, attribute, value)
    if some_validation?(object)
      object.errors[attribute] << (options[:message] || "is not formatted properly") 
    end
  end
end

Is there any way to pass arguments to the validator dependant on which field it is validating?

thanks

Anders answered 24/10, 2012 at 1:59 Comment(4)
What are you trying to achieve by doing this? This doesn't strike me as the best way to do this given the Rails API.Pancreatotomy
In my original code I want to find if there is a cyclic dependency in my model. ModelA has many Model B. Model B has one Model A. I want to validate there is no cycle from Model A back to itself. The thing is, I have two different relations which need to validate cycles and there is a very minimal difference in the validator between them. I wanted to see if I could do it generically passing which fields to search for cycles as opposed to rewriting the same cycle logic and validator.Anders
I think you may be better off using subclassing for that instead of parameterization.Pancreatotomy
I am using subclasses for now however I'm still interested if parameters can be passed through validators. There are other places in my code I can use this ability and I'm just curiousAnders
J
22

I wasn't aware of this either, but if you want to pass an argument, then pass a hash to generic: instead of true. This post details the exact process you're wanting to follow:

class User
  include Mongoid::Document

  field :order_type
  has_many :orders, inverse_of :user
  validates: orders, generic: { :order_type => order_type }

  field :task_type
  has_many :tasks, inverse_of :user
  validates: tasks, generic: { :task_type => task_type }
end

GenericValidator should now have access to both arguments you're wanting to pass in validation: options[:order_type] and options[:task_type].

It might make more sense, however, to divide these up into two validators, with both inheriting the shared behavior as mentioned by dpassage:

  class User
    include Mongoid::Document

    field :order_type
    has_many :orders, inverse_of :user
    validates: orders, order: { type: order_type }

    field :task_type
    has_many :tasks, inverse_of :user
    validates: tasks, task: { type: task_type }
  end
Juvenal answered 28/10, 2012 at 11:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.