проверяет: что-то,: подтверждение => истина и путаница attr_accessor - PullRequest
1 голос
/ 31 января 2012

борется с Ruby validates: подтверждением => true в моем приложении Rails. Рассмотрим следующий код:

# == 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 }

конец

Поскольку код выше, моя проверка корректно работает с консоли Rails:

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"> 

, но тестирование через rspec и вручную с сервера rails приводит к сбою проверки, говоря, что они не совпадают, когда они чертовски хороши. Если я раскомментирую attr_accessor для: pin, проверки пройдут, но, конечно,: pin не будет записан в базу данных.

Я полностью уверен, что упускаю что-то очевидное и жизненно важное - просто врезаюсь в кирпичную стену.

1 Ответ

1 голос
/ 02 февраля 2012

Как сказал Фредерик выше, проблема заключается в сравнении экземпляра String с экземпляром Integer.

Скорее всего, вот что у вас есть в вашем контроллере:

Thing.new(params[:thing]) # note all these params come in as a string

Что происходит, так как #pin является целочисленным столбцом, вы получите следующее поведение:

my_thing = Thing.new
my_thing.pin = "123456"
my_thing.pin  # Will be the integer 123456, the attribute has been auto-cast for you

Но поскольку #pin_confirmed является обычным атрибутом, а не целочисленным столбцом, вот странность, которую вы увидите:

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

Естественно, в этом случае, независимо от того, какие значения у вас есть, так как они входят через хэш «params» (который всегда является набором строк), вы в конечном итоге назначите строковые значения для обоих атрибутов, но они будет приведен к разным типам.

Есть несколько способов исправить это.

Во-первых, вы можете создать #pin_confirmation в виде целочисленного столбца в базе данных.

Во-вторых, вы можете добавить установщик атрибутов для #pin_confirmation следующей формы:

def pin_confirmation=(val)
  @pin_confirmation = val.to_i
end
...