Reputation: 33
Ruby Version
ruby 2.1.3p242 (2014-09-19 revision 47630)
Rails Version
rails-4.1.6
Example Object:
Job(id: integer, job_number: string, reviewed: boolean)
Example Model:
class Job < ActiveRecord::Base
validates :job_number, presence: true, if: -> { self.reviewed }
end
I'm trying to write something that helps with form input. For each input I call Job.validators_on(column). In this case Job.validators_on(:job_number) which returns
[#<ActiveRecord::Validations::PresenceValidator:0x007fc5c2a464f8
@attributes=[:job_number],
@options=
{:if=>
#<Proc:0x007fc5c2a46c50@blahblah/app/models/job.rb:2 (lambda)>}>
]
Now I take that validator and get the :if option so I can call the lambda and get true/false.
>Job.validators_on(:job_number).first.options[:if].call(Job.first)
ArgumentError: wrong number of arguments (1 for 0)
from blahblah/app/models/job.rb:2:in `block in <class:Job>'
Now I understand the fact that this lambda doesn't have any arguments and an arity of 0. I could also just fix this problem and add a param like:
validates :job_number, presence: true, if: -> (job) { job.reviewed }
or
validates :job_number, presence: true, if: Proc.new{ |job| job.reviewed }
I would like to avoid having to change all of the validations in the project to account for an argument, since I have A LOT of them. But how does the if: get executed within the scope of any Job object when you run .valid? and there are not any arguments on the lambda? If .valid? can do it, I can find a way to do it.
Upvotes: 3
Views: 293
Reputation: 4171
If you have a block that you want to execute in the context of an object, you can call obj.instance_exec(&block)
.
So in your case:
job = Job.first
lamb = Job.validators_on(:job_number).first.options[:if]
job.instance_exec(&lamb)
This looks like a hack, and it is. Rails does not expect you to need to call validators manually. That is, this sounds like a problem that should be solved by the frontend, leaving Rails to just validate before saving and returning any errors for the frontend to display.
Upvotes: 4