【问题标题】:Rails 3 skip validations and callbacksRails 3 跳过验证和回调
【发布时间】:2011-11-26 05:22:13
【问题描述】:

我有一个特别复杂的模型,其中定义了验证和回调。业务需求现在需要特定场景,其中添加新记录需要跳过验证和回调。最好的方法是什么?

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3 activerecord


    【解决方案1】:

    这适用于 Rails 3:

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

    API docsrelated question

    【讨论】:

    • 您不需要再次使用set_callback(:create) 吗?我的印象是skip_callback 在重新启用之前会禁用它。
    • 我想是的,我从不使用这种方法,更多信息api.rubyonrails.org/classes/ActiveSupport/Callbacks/…
    • 这不是线程安全的吗?能够在实例级别设置它会很好..
    • 以防万一有人遇到与我相同的问题:在 rails 3 中,这并没有禁用观察者回调。为了做到这一点,我做了stackoverflow.com/questions/707615/… 所说的
    • 最近我们的项目出现了问题。我们已经用相当简单的方法解决了这个问题。它对我们很有效。该解决方案适用于任何版本的 Rails。在我的博文中查看:railsguides.net/2014/03/25/skip-callbacks-in-tests
    【解决方案2】:

    向你的模型添加一个让你跳过回调的方法怎么样?

    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 而不是模型名称,以避免名称的一致性。

    我还从 Sven Fuchs 看到了一个看起来不错的要点,它是 here

    【讨论】:

    • 我喜欢这种方法,但skip_callback 显示为类方法,而update_attributes 是实例方法,这是您的意图吗?嗯,我不明白,API 文档说 skip_callback 是实例方法,但在 Rails 控制台中不是这样,奇怪。
    【解决方案3】:

    我的看法是这样的(注意:这会禁用创建、更新、删除和其他需要将它们添加到数组的回调)。

        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
    

    【讨论】:

    • 赞成,但后来它不适用于我的 3.2.6 应用程序。我正在调用 Model.skip_callback(:create, :after)
    • 这是 3.0+ 的解决方案 它不适用于 2.x - 但我记得当我在寻找解决方案时,我偶然发现 2.x 的解决方案不起作用对于 3.x
    【解决方案4】:

    使用ActiveRecord::Persistence#update_column,像这样:

    Model.update_column(field, value)
    

    【讨论】:

    • 根据您链接的文档:“回调被调用。”
    • 我认为您查看了update_attribute 的文档,而不是update_column 的文档。如果您查看update_column 的文档,它相当于update_columns 的单个列。 update_columns 的文档清楚地指出验证和回调被跳过。
    • 救我一命!我尝试了skip_callback和其他方法,没有运气。这行得通!
    【解决方案5】:

    这个 hack 终于为我工作了(为对象重新定义了 _notify_comment_observer_for_after_create 方法):

    if no_after_create_callback
      def object._notify_comment_observer_for_after_create; nil; end
    end
    

    【讨论】:

      【解决方案6】:

      我编写了一个简单的 gem 用于跳过临时验证,但它可能会被更新为包括跳过回调。

      https://github.com/npearson72/validation_skipper

      您可以在 gem 中使用 can_skip_validation_for 并添加功能以跳过回调。也许调用方法can_skip_validation_and_callbacks_for

      其他一切都一样。如果您在这方面需要帮助,请告诉我。

      【讨论】:

        【解决方案7】:

        我建议不要使用 skip_callback 方法,因为它不是线程安全的。但是,sneaky save gem 是因为它只是直接运行 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!
        

        【讨论】:

          【解决方案8】:

          如果目标是在没有回调或验证的情况下简单地插入或更新记录,并且您希望在不使用其他 gem、添加条件检查、使用 RAW SQL 或以任何方式处理现有代码的情况下执行此操作,可以使用指向现有数据库表的“影子对象”。像这样:

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

          这适用于 Rails 的每个版本,是线程安全的,并且完全消除了所有验证和回调,无需修改现有代码。请记住使用您的新类插入对象,例如:

          ImportedUser.new( person_attributes )
          

          【讨论】:

          • 这太聪明了。救了我的头痛!
          【解决方案9】:

          如果您的验证被写入数据库本身,这些都不会起作用。

          +------------------------------------+--------------------------------------------------+------+-----+--------------------+----------------+
          | Field                              | Type                                             | Null | Key | Default            | Extra          |
          +------------------------------------+--------------------------------------------------+------+-----+--------------------+----------------+
          | status                             | enum('Big','Small','Ugly','Stupid','Apologetic') | NO   |     | Stupid             |                |
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-06-09
            • 2012-09-21
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-05-22
            • 1970-01-01
            相关资源
            最近更新 更多