Как проверить атрибут с помощью "validates:attribute", ссылающегося на значение атрибута родительского объекта?

В этом упражнении О'Рейли "Head first Rails" (изд. 2009) есть 2 связанных объекта.

Объект "Полет" [я использовал аннотированный драгоценный камень, чтобы показать каждый атрибут]:

# == Schema Information
#
# Table name: flights
#
#  id                :integer         not null, primary key
#  departure         :datetime
#  arrival           :datetime
#  destination       :string(255)
#  baggage_allowance :decimal(, )
#  capacity          :integer
#  created_at        :datetime
#  updated_at        :datetime
#

class Flight < ActiveRecord::Base
  has_many :seats
end

Муравей "Seat" объект:

# == Schema Information
#
# Table name: seats
#
#  id         :integer         not null, primary key
#  flight_id  :integer
#  name       :string(255)
#  baggage    :decimal(, )
#  created_at :datetime
#  updated_at :datetime
#

class Seat < ActiveRecord::Base
  belongs_to :flight
end

Как вы можете догадаться, значение seat.baggage всегда должно быть меньше или равно seat.flight.baggage_allowance.

Итак, я написал этот валидатор, который хорошо работает:

class Seat < ActiveRecord::Base

  belongs_to :flight

  def validate
      if baggage > flight.baggage_allowance
      errors.add_to_base("Your have to much baggage for this flight!")
    end 
  end  
end

Затем я попытался изменить его с помощью этого более красивого:

      validates :baggage, :numericality => { :less_than_or_equal_to => flight.baggage_allowance }, :presence => true 

Но это вызывает NameError в SeatsController:

undefined local variable or method `flight' for #<Class:0x68ac3d8>"

Чем я также пытался с "self.flight.baggage_allowance":

validates :baggage, :numericality => { :less_than_or_equal_to => self.flight.baggage_allowance }, :presence => true

Но он генерирует исключение NoMethodError:

undefined method `flight' for #<Class:0x67e9b40>

Есть ли способ заставить более симпатичный валидатор работать?

Какова наилучшая практика для такого рода проверки?

Спасибо.

---РЕДАКТИРОВАТЬ---

Как любезно предложил Маурисио Линьярес в дальнейшем, проблему можно решить, определив символ: bagging_allowance. Я хотел бы лучше понять, где действительно требуется пользовательская проверка. Как насчет этого, возможно ли преобразовать даже это в метод "проверки" или нет? и почему?

class Seat < ActiveRecord::Base
.
.
.
def validate
  if flight.capacity <= flight.seats.size
    errors.add_to_base("The flight is fully booked, no more seats available!")
  end
end

Еще раз спасибо

1 ответ

Решение

Вы можете сделать это так:

class Seat < ActiveRecord::Base

  validates :baggage, :numericality => { :less_than_or_equal_to => :baggage_allowance }, :presence => true 

  belongs_to :flight

  def baggage_allowance
    flight.baggage_allowance
  end  
end

РЕДАКТИРОВАТЬ

Вы не можете сделать это:

class Seat < ActiveRecord::Base
        validates :baggage, :numericality => { :less_than_or_equal_to => flight.baggage_allowance }, :presence => true 
end

Поскольку метод validates вызывается на уровне класса, поэтому нет доступной переменной flight, поскольку она является переменной экземпляра. Когда вы настраиваете его с помощью:baggage_allowance, вы указываете Rails вызывать метод:baggage_allowance в экземпляре Seat, чтобы иметь возможность доступа к значению.

Другие вопросы по тегам