In this exercise from O'Reilly's "Head first Rails" (ed. 2009) there are 2 related objects.
The "Flight" object [I used annotate gem to show every attribute]:
# == 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
Ant the "Seat" object:
# == 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
As you may guess the seat.baggage value should always be less than or equal to seat.flight.baggage_allowance.
So I wrote this validator, which works well:
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
Then I tried to refactor it with this prettier one:
validates :baggage, :numericality => { :less_than_or_equal_to => flight.baggage_allowance }, :presence => true
But it causes a NameError in SeatsController:
undefined local variable or method `flight' for #<Class:0x68ac3d8>"
Than I also tried with "self.flight.baggage_allowance":
validates :baggage, :numericality => { :less_than_or_equal_to => self.flight.baggage_allowance }, :presence => true
But it throws a NoMethodError Exception:
undefined method `flight' for #<Class:0x67e9b40>
Is there a way to make the prettier validator work?
Which is the best practice to do this kind of validation?
Thank you.
---EDIT---
As Maurício Linhares kindly suggested hereafter, the problem is solvable defining a :bagging_allowance symbol. I'd like to understand better where custom validation is really needed. What about this one, is it possible to convert even this to a "validates" method or not? and why?
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
Thank you again.
:less_than_or_equal_to => Proc.new { |flight| flight.baggage_allowance }
– Metacarpusvalidates :baggage, :numericality => { :less_than_or_equal_to => Proc.new { |flight| flight.baggage_allowance }}, :presence => true
It throws:NoMethodError in SeatsController#create undefined method 'baggage_allowance' for #<Seat:0x6a8be38>
Thank you anyway! – Joinder