I'm new to rails, I have a trip class with three foreign key. Two of these associate it with the same class: Place.
This is my model:
class Trip < ApplicationRecord
belongs_to :from, class_name: "Place", foreign_key: "from_id"
belongs_to :to, class_name: "Place", foreign_key: "to_id"
belongs_to :vehicle, class_name: "Vehicle", foreign_key: "vehicle_id"
validates :price, presence: true
validates :time, presence: true
validates :from_id, presence: true
validates :to_id, presence: true, if: :from_different_to?
def from_different_to?
to_id != from_id
end
end
All model tests pass except for the last one:
class TripTest < ActiveSupport::TestCase
def setup
@place1 = Place.create(name:"NewYork",cap:"11111",lat:"1234",long:"1478")
@place2 = Place.create(name:"Los Angeles", cap:"22222", lat:"1234",long:"1478")
@vehicle = Vehicle.create(targa: "ab123cd",modello:"500",marca:"Fiat", posti:5,alimentazione:"benzina")
@trip = Trip.new(price: 10, time: Time.new(2021, 10, 14, 12,03), from_id: @place1.id, to_id: @place2.id,vehicle_id: @vehicle.id)
end
...
test "Departure id and arrival id should be different" do
@trip.to_id = @place1.id
assert_not @trip.valid?
end
that result in a failure:
Failure:
TripTest#test_Departure_id_and_arrival_id_should_be_different [/media/alessandro/DATA/Universita/Magistrale/1_anno/Programmazione_concorrente/hitchhiker/test/models/trip_test.rb:45]:
Expected true to be nil or false
I'm not able to understand why. Can someone help me?
CodePudding user response:
I'm not able to understand why. Can someone help me?
That if
conditionally enables a validation. Your to_id
is the same as from_id
and so to_id
is not validated at all. But even if it was, to_id
has a value, so there wouldn't be an error from this field.
Overall, I'm not quite sure why are you expecting a validation error here or what that error should be. In my experience, assertions like assert_not @model.valid?
are virtually useless. The record might not be valid because of unrelated reasons and you'll have no idea. Personally, I assert the exact error message I'm expecting. Something along these lines (rspec syntax)
it "requires first_name" do
expected_messages = {
first_name: [:blank],
}
@model.valid?
expect(@model.errors.full_messages).to eq expected_messages
end
CodePudding user response:
It seems like you think validates ... if:
works differently as it actually does. This line
validates :to_id, presence: true, if: :from_different_to?
translates to validate that the to_id
is present if the from_different_to
method returns true
. When from_different_to
evaluates to false
then do not validate. See Rails Guides.
That means when you define
@trip.to_id = @place1.id
assert_not @trip.valid?
in your test then the first line disables the check for the presence of the to_id
. No validation, no error...
I suppose what you really try to achieve is to validate that to to_id
is present and from_id
and to_id
are not equal. This can be done with a custom validation like this:
validates :to_id, presence: true
validate :validates_places_are_different
private
def validates_places_are_different
errors.add(:to_id, "must be different to from_id") if to_id == from_id
end
CodePudding user response:
An alternative to that of @spickermann is that:
class Trip < ApplicationRecord
belongs_to :from, class_name: "Place", foreign_key: "from_id"
belongs_to :to, class_name: "Place", foreign_key: "to_id"
belongs_to :vehicle, class_name: "Vehicle", foreign_key: "vehicle_id"
validates :price, presence: true
validates :time, presence: true
validates :from_id, presence: true
validates :to_id, numericality: {other_than: :from_id}, if: :from_place_id?
def from_place_id
from_id
end
def from_place_id?
!from_id.nil?
end
end
Note that we have to put a control to execute the last validates only if from_id is not null, because if we doesn't do that, we vanificate the control validates :from_id, presence:true
on the superior line.