Как я могу написать проверку, которая гарантирует, что существующая ассоциация не может быть изменена в Rails 3?

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