问题
am struggling with Ruby validates :confirmation => true in my Rails app. Consider the following code:
# == Schema Information
#
# Table name: things
#
# id :integer not null, primary key
# pin :integer(8)
# created_at :datetime
# updated_at :datetime
#
class Things < ActiveRecord::Base
#attr_accessor :pin
attr_accessible :pin, :pin_confirmation
validates :pin,
:confirmation => true,
:length => { :within => 7..15 },
:numericality => { :only_integer => true }
end
As the code is above, my validation works fine from the Rails console:
1.9.3-p0 :002 > l2 = Thing.create! :pin => 1234567, :pin_confirmation => 1111111
ActiveRecord::RecordInvalid: Validation failed: Pin doesn't match confirmation
....
1.9.3-p0 :003 > l2 = Thing.create! :pin => 1234567, :pin_confirmation => 1234567
=> #<Thing id: 2, pin: 1234567, created_at: "2012-01-30 22:03:29", updated_at: "2012-01-30 22:03:29">
but testing both through rspec and manually from rails server causes the validation to fail, saying they don't match when they darn well do. If I uncomment the attr_accessor for :pin, the validations will pass but the :pin of course will not be written to the database.
I'm completely sure I'm missing something obvious and vital- just running into a brick wall.
回答1:
Like Frederick said above, the issue is comparing an instance of String with an instance of Integer.
More than likely, here's what you have in your controller:
Thing.new(params[:thing]) # note all these params come in as a string
What's happening is that since #pin is an integer column, you will get the following behaviour:
my_thing = Thing.new
my_thing.pin = "123456"
my_thing.pin # Will be the integer 123456, the attribute has been auto-cast for you
But since #pin_confirmed is just a regular attribute, not an integer column, here's the weirdness you will see:
my_thing = Thing.new
my_thing.pin_confirmation = "123456"
my_thing.pin_confirmation # Will be the *string* "123456", the attribute has been set as is
So naturally, in that case, no matter what values you have, since they come in through the "params" hash (which is always a set of strings), you will end up assigning string values to both attributes, but they will be cast to different types.
There are several ways to fix this.
One, you could create #pin_confirmation as an integer column in the database.
The other is you could add an attribute setter for #pin_confirmation of the following form:
def pin_confirmation=(val)
@pin_confirmation = val.to_i
end
来源:https://stackoverflow.com/questions/9071590/validates-something-confirmation-true-attr-accessor-confusion