Reputation: 8240
I'm trying to make a custom validator work on my app.
I have already configured my config.autoload.paths
and it is loading fine.
The problem is with the validator itself.
Result of binding pry
instance variables: @attributes @options @with
locals: _ _dir_ _ex_ _file_ _in_ _out_ _pry_ attribute record value
[12] pry(#<FileCountValidator>)> value
=> [#<Attachment id: 60, description: nil, file: "cache_600_1__img_948867_5770137d84a6c79ac825886938e...", attachable_type: "Post", attachable_id: 15, created_at: "2012-03-10 14:50:54", updated_at: "2012-03-10 14:50:54">,
#<Attachment id: 61, description: nil, file: "cache_600_1__img_948867_90f64e01b9c871ec656a884e015...", attachable_type: "Post", attachable_id: 15, created_at: "2012-03-10 14:50:54", updated_at: "2012-03-10 14:50:54">,
#<Attachment id: 62, description: nil, file: "cache_600_1__img_948867_85eda3946c27fa90566403ac941...", attachable_type: "Post", attachable_id: 15, created_at: "2012-03-10 14:50:54", updated_at: "2012-03-10 14:50:54">,
#<Attachment id: nil, description: nil, file: nil, attachable_type: "Post", attachable_id: 15, created_at: nil, updated_at: nil>]
[13] pry(#<FileCountValidator>)> value > @with
TypeError: compared with non class/module
from /home/kleber/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.1/lib/active_record/relation/delegation.rb:20:in `>'
[14] pry(#<FileCountValidator>)> value.size > @with
=> true
[15] pry(#<FileCountValidator>)> value.size
=> 4
[16] pry(#<FileCountValidator>)> @with
=> 3
[17] pry(#<FileCountValidator>)>
So, I trying to make this comparisson exactly like I did on the pry debug console.
def validate_each(record, attribute, value)
#binding.pry
record.errors.add(attribute,"#{@with} attachments per post only. #{attribute['file'].size} detected.") if value.size > @with
end
But doing this, return me the error:
NoMethodError (undefined method `size' for nil:NilClass):
lib/validators/file_count_validator.rb:11:in `validate_each'
app/controllers/posts_controller.rb:61:in `block in update'
app/controllers/posts_controller.rb:60:in `update'
Are there any way to catch the value
before it get enters the validate_each
method?
Upvotes: 0
Views: 2713
Reputation: 3009
Sorry, but the value being passed seems to be correct. value
is meant to be the value of that attribute for that record, i.e. record.send(attribute)
should be equal to the value.
Calling validates :attachments, :photo_count => 2
does not send 2 to the validate_each
method as argument value
. You could do :photo_count => true
, which is what I generally do, or even :photo_count => "foo"
. The photo_count
in your validates
statement serves to provide that the validator is to be called by passing the value(i.e. 2 or true or "foo" for stated examples) embedded in the options hash.
Here's a way without passing a limit to the validator.
Create a Constants
class and define MAX_ATTACHMENTS
constant. I usually have it at models/constants.rb.
class Constants
MAX_ATTACHMENTS = 1
end
Then, in the validator, you could do
class PhotoCountValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
record.errors.add(attribute,"#{Constants::MAX_ATTACHMENTS} attachments per post only.") if record.send(attribute).size > Constants::MAX_ATTACHMENTS
end
end
Another way that passes a parameter to a validator:
validates :attachments, :photo_count => 3 #desired_limit
Override the initialize method for PhotoCountValidator class, and initialize a class variable :
def initialize(options)
@@max_objects = options[:with] # the options hash will be as {:attributes=>[:attachments], :with=>3}, where :with contains the desired limit passed
super
end
Then within the validate_each
method :
record.errors.add(attribute,"#{@@max_objects} attachments per post only.") if record.send(attribute).size > @@max_objects
Upvotes: 2