validates :something, :confirmation => true & attr_accessor confusion

馋奶兔 提交于 2019-12-10 11:38:34

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!