Rails 3 пропускает проверки и обратные вызовы - PullRequest
70 голосов
/ 27 сентября 2011

У меня есть особенно сложная модель с определенными валидациями и обратными вызовами. В настоящее время бизнес нуждается в конкретном сценарии, когда добавление новой записи требует пропуска проверок и обратных вызовов. Какой лучший способ сделать это?

Ответы [ 9 ]

118 голосов
/ 27 сентября 2011

Это работает в Rails 3:

Model.skip_callback(:create)
model.save(:validate => false)
Model.set_callback(:create)

( API документы и связанный вопрос )

29 голосов
/ 02 августа 2012

Использовать ActiveRecord :: Persistence # update_column , например:

Model.update_column(field, value)
10 голосов
/ 10 декабря 2015

Если цель состоит в том, чтобы просто вставить или обновить запись без обратных вызовов или проверок, и вы хотели бы сделать это, не прибегая к дополнительным гемам, не добавляя условные проверки, не используя RAW SQL, или каким-либо образом возившись с выходящим кодом, может быть возможно использовать «теневой объект», который указывает на вашу существующую таблицу БД. Вот так:

class ImportedUser < ActiveRecord::Base
  # To import users with no validations or callbacks
  self.table_name = 'users'
end

Это работает с каждой версией Rails, является поточно-ориентированным и полностью исключает все проверки и обратные вызовы без каких-либо изменений в существующем коде. Просто не забудьте использовать новый класс для вставки объекта, например:

ImportedUser.new( person_attributes )
2 голосов
/ 06 июня 2012

Мой дубль был таким (примечание: это отключает обратные вызовы при создании, обновлении, удалении и других, вам нужно добавить их в массив).

    begin
      [:create, :save].each{|a| self.class.skip_callback(a) } # We disable callbacks on save and create

      # create new record here without callbacks, tou can also disable validations with 
      # .save(:validate => false)
    ensure
      [:create, :save].each{|a| self.class.set_callback(a) }  # and we ensure that callbacks are restored
    end
1 голос
/ 25 июня 2015

Я бы рекомендовал НЕ использовать подход skip_callback, так как он не безопасен для потоков.Тем не менее, хитрый спасбросок так как он работает прямо sql.Обратите внимание, что это не вызовет проверки, поэтому вам придется вызывать их самостоятельно (например, my_model.valid?).

Вот несколько примеров из их документов:

# Update. Returns true on success, false otherwise.
existing_record.sneaky_save

# Insert. Returns true on success, false otherwise.
Model.new.sneaky_save

# Raise exception on failure.
record.sneaky_save!
1 голос
/ 22 ноября 2012

Я написал простой гем для пропуска проверок adhoc, но, вероятно, его можно было бы обновить, включив также пропуск обратных вызовов.

https://github.com/npearson72/validation_skipper

Вы можете взять can_skip_validation_for в драгоценном камне и добавить функциональность для пропуска обратных вызовов. Может быть, вызвать метод can_skip_validation_and_callbacks_for

Все остальное будет работать так же. Если вам нужна помощь в этом, дайте мне знать.

1 голос
/ 27 сентября 2011

Как насчет добавления метода к вашей модели, который позволяет пропускать обратные вызовы?

class Foo < ActiveRecord::Base
  after_save :do_stuff

  def super_secret_create(attrs)
    self.skip_callback(:create)
    self.update_attributes(attrs)
    self.save(:validate => false)
    self.set_callback(:create)
  end
end

Если вы в конечном итоге используете что-то подобное, я бы рекомендовал использовать в методе self вместо имени модели, чтобыизбегать навязывания имени.

Я также натолкнулся на суть Свена Фукса, которая выглядит красиво, это здесь

0 голосов
/ 12 января 2016

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

+------------------------------------+--------------------------------------------------+------+-----+--------------------+----------------+
| Field                              | Type                                             | Null | Key | Default            | Extra          |
+------------------------------------+--------------------------------------------------+------+-----+--------------------+----------------+
| status                             | enum('Big','Small','Ugly','Stupid','Apologetic') | NO   |     | Stupid             |                |
0 голосов
/ 10 августа 2012

Этот хак наконец сработал для меня (переопределен _notify_comment_observer_for_after_create метод для объекта):

if no_after_create_callback
  def object._notify_comment_observer_for_after_create; nil; end
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...