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?
Где я могу увидеть полную документацию относительно обратных вызовов и рабочего процесса.
Заранее спасибо
Ответы
Ответ 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