Подтвердить что ты не робот

Rails 3: Нужно ли возвращать true в обратном вызове before_save для объекта. Как работать?

Class User  
  before_save :set_searchable

  def set_searchable  
    self.searchable = true if self.status == :active  
  end  
end  

>> u = User.last  
>> u.save  
false  

u.save всегда возвращает false. Если я удалю before_save, он будет работать также, если я верю true в before_save, он работает

так мне нужно давать операторы return в before_save? будет ли ActiveRecord сохранять объект, если before_save возвращает false?

Где я могу увидеть полную документацию относительно обратных вызовов и рабочего процесса.

Заранее спасибо

4b9b3361

Ответ 1

От: http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html

Если обратный вызов before_ * возвращает false, все последующие обратные вызовы и связанное с ним действие отменены. Если обратный вызов after_ * возвращает false, все последующие обратные вызовы будут отменены. Обратные вызовы обычно выполняются в том порядке, в котором они определены, за исключением обратных вызовов, определенных как методы в модели, которые называются последними.

Итак, да.

Ответ 2

Нет, вам не нужно возвращать true из обратных вызовов Rails. Вы ничего не можете вернуть, или true, или 3.141592, и он будет сохранен. Единственное, что имеет значение, - это вернуть false, и это относится только к Rails 5. Возврат false отменяет сохранение до Rails 5. Возврат true никогда не имел никакого эффекта.

Для Rails 5+ новый способ блокировки обновления - это исключение: throw(:abort).. Это более интуитивно понятное и менее подверженное ошибкам. Возвращаемое значение не влияет на его сохранение, если вы не настроите унаследованное поведение.

Это действительно - и imo хорошая сухая практика - просто заниматься своим бизнесом и ничего не возвращать; просто обязательно избегайте случайного возврата false неявно, если используете более ранние Rails. Например:

# This is fine, record will be saved
def before_save
  self.foo = 'bar' # Implicitly returns 'bar'
end

# This is an accidental veto, record will not be saved
def before_save
  Rails.logger.info 'user requested save'
  self.fresh = false # Oops! Implicitly returns false
end

# One way to rectify the above example (another would be to re-order if it possible)
def before_save
  Rails.logger.info 'user requested save'
  self.fresh = false
  return # Implicitly returns nil. Could also do `return true`
end

В результате здесь вы можете забыть, что некоторые "процедурные" функции типа возвращают логическое значение как своего рода код состояния или просто потому, что реализация заканчивается логическим как побочным эффектом. Вы можете подумать, что вы мутируете строку или что-то в этом роде, но в конечном итоге случайно наложили вето на обратный вызов. Поэтому, хотя я считаю, что обычно слишком шумно, чтобы явно возвращаться от обратных вызовов, вам нужно позаботиться о неявных доходах. Одна из причин, по которой люди выступали за возвращение истины, заключалась в том, чтобы защищать эту добычу.

Ответ 3

В документации указано

Если обратный вызов before_ * возвращает false, все последующие обратные вызовы и связанные действия отменены. Если обратный вызов after_ * возвращает false, все последующие обратные вызовы отменены. Обратные вызовы обычно запускаются в порядок, который они определены, за исключением обратных вызовов, определенных как методы на модели, которые называются последними.

НО

вы можете проверить этот out (я сам тестировал это, и проблема на 100% достоверна)

Плюс также есть ошибка, связанная с before_save, которую вы, возможно, захотите узнать, проверьте комментарий здесь

enter image description here

Как говорится в комментарии, это наблюдается иногда.

Независимо от того, что вы просто знаете, есть некоторые проблемы с обратным вызовом rails. Это сэкономит ваше время, когда вы столкнетесь с одним из этих

Ответ 4

Другим более чистым способом установки булевых столбцов без return является использование tap

  def set_searchable
    self.tap{|u| u.searchable = status.eql?(:active) }
  end