#ruby-on-rails #ruby-on-rails-3 #validation #associations
#ruby-on-rails #ruby-on-rails-3 #проверка #ассоциации
Вопрос:
Я видел много вопросов, спрашивающих, как проверить наличие ассоциации, но этот вопрос немного сложнее.
Допустим, у меня есть три модели: Plane
, a Pilot
и a Flight
.
У Plane
может быть один Pilot
и one Flight
.
Как только a Plane
было присвоено a Pilot
, ему можно затем назначить Flight
.
Я хотел бы написать некоторый код проверки, чтобы гарантировать, что, как только a Plane
имеет оба a Flight
и a Pilot
, Pilot
нельзя изменить.Итак, я хотел бы, чтобы этот тест прошел:
describe Plane do
context "before updating" do
it "ensures that the pilot cannot be changed if the plane has any flights" do
plane = Plane.create!
plane.pilot = Pilot.create!
plane.flight = Flight.create!
hijacker = Pilot.create!
plane.pilot = hijacker
plane.save.should be_false
plane.errors[:base].should include "Can't change the pilot while in-flight"
end
end
end
Я хотел бы получить некоторое представление о том, какие методы доступны для достижения этого. Спасибо всем!
Ответ №1:
Вы могли бы начать с пользовательской проверки, которая проверяет измененную запись (находящуюся в памяти) на соответствие базовой записи, которая фактически находится в базе данных.
class Plane < ActiveRecord::Base
validate_on_update :pilot_cannot_be_changed
def pilot_cannot_be_changed
errors.add(:pilot, "cannot be changed while in-flight.")
if pilot.id != Plane.find(id).pilot.id
end
Комментарии:
1. Спасибо, @Dobry. Это приятно и просто. К вашему сведению, я получил предупреждение об устаревании, когда попытался использовать validate_on_update. По-видимому, новый синтаксис будет:validate :pilot_cannot_be_changed, :on => :update .
Ответ №2:
вы можете написать свою собственную проверку, чтобы гарантировать это .. но это вернет вам false не в момент назначения пилота, а в конце, когда вы сохраните самолет.
Итак, вот более простая версия:
class Plane < ActiveRecord::Base
def pilot=(val)
return false if self.pilot amp;amp; self.flight
@pilot = val
# I'm not sure about this line above, you can use something like this (or both lines)
# write_attribute(:pilot_id, val.id)
end
end
Надеюсь, это поможет (или, по крайней мере, направит вас в правильном направлении).
С уважением, NoICE
Комментарии:
1. Спасибо, @noICE. Когда я снова посмотрел на свой тест, я понял, что мне не нужно, чтобы он сразу возвращал false в конце концов — при сохранении все в порядке. Я отредактировал свой вопрос, чтобы отразить это. Спасибо за ответ, я не думал о переопределении метода setter.