Обновление атрибута модели во время действия до, когда изменяется другой атрибут

#ruby-on-rails #ruby

Вопрос:

В настоящее время моя модель имеет эти два соответствующих атрибута: first_id , second_id

Я пытаюсь проверить это при обновлении, если first_id оно изменилось, затем установите значение second_id nil , независимо от того , какое значение second_id имеет значение.

Поэтому в настоящее время моя реализация в моей модели выглядит примерно так:

   validates_presence_of :first_id
  before_action :check_if_first_id_changes, only: [:update]
  
  def check_if_first_id_changes
      if self.first_id != first_id
          # What do I insert here?
      end
  end
 

Могу ли я как-нибудь сделать это в модели? Заранее спасибо!

Ответ №1:

before_action это метод контроллера. Вы, вероятно, захотите использовать before_validation или before_save .

Следующее должно соответствовать вашим требованиям:

 before_validation :update_second_id_when_first_id_changed, on: [:update]

private

def update_second_id_when_first_id_changed
  return unless first_id_changed?

  self.second_id = nil
end
 

Комментарии:

1. Хм, в моем случае пользователь может обновить как first_id, так и second_id, но мне просто нужно убедиться, что если first_id изменится, все, что впоследствии будет сохранено в базе данных-second_id должно быть равно нулю. Почему вы используете self.second_id? Не будет ли он обновляться впоследствии, так как я мог бы обновлять с измененным first_id и ненулевым second_id. Спасибо!

2. Я не уверен, что правильно понял ваш комментарий. Что делает этот код: Если first_id он не изменился, то он немедленно возвращается и ничего не делает (см. DirtyAttributes О том, как first_id_changed? работает метод). Но если first_id изменено, то second_id установлено значение nil . Вам нужно self здесь, потому что в противном случае вы бы просто установили second_id локальную переменную, но не переменную экземпляра. Все это происходит до проверки и перед сохранением, что означает second_id = nil , что на следующем шаге оно будет автоматически сохранено в базе данных.

3. Я думаю, что у меня было неправильное представление, которое self.second_id относится к исходному значению, в то время second_id как относится к новому значению, до которого оно будет обновлено, поэтому мне было интересно, почему вы сделали self.second_id = nil бы, если бы оно просто было обновлено second_id после завершения этого before_validation метода. Но да, ваше объяснение делает это ясным для меня!

Ответ №2:

Проверка self.first_id != first_id никогда не сработает, потому что они оба ссылаются на одно и то же значение. Вы можете использовать помощника first_id_changed? , чтобы проверить, были ли внесены изменения. В ActiveModel::Dirty документации приведен список всех помощников, касающихся изменений атрибутов экземпляра модели.

Как уже указывалось, before_action недопустимо в модели. Вы можете проверить доступные обратные вызовы для моделей здесь. Если нет никаких подтверждений second_id , я бы лично пошел на before_update это, что устраняет необходимость в установке on: :update опции.

Лично мне нравится разделять «действие» и «проверку», чтобы вы могли вызывать действие без блокировки проверки. Затем я бы объединил их в определении обратного вызова. Однако это всего лишь личные предпочтения, и вы можете легко перенести проверку в обратный вызов, если это больше соответствует вашим потребностям.

 before_update :clear_second_id, if: :first_id_changed?

private

def clear_second_id
  self.second_id = nil
end