Как проверить атрибут с помощью "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, чтобы иметь возможность доступа к значению.