Как проверить атрибут с помощью «validates: attribute», ссылающегося на значение атрибута родительского объекта? - PullRequest
5 голосов
/ 29 июля 2011

В этом упражнении из «Первые рельсы О'Рейли» (изд. 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

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

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

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

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

Спасибо.

--- EDIT ---

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

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 Ответ

8 голосов
/ 29 июля 2011

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

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

EDIT

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

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

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

...