How to skip before filter in model with ruby on rails 5.2?

1.6k Views Asked by At

My application manages a hierarchy of documents. Each document has a hierarchycal index, which is calculated at creation only. File document.rb starts with

class BusinessRule < ActiveRecord::Base
### before filter
  before_create :set_hierarchy

and the hierarchy is calculated based on parent and brothers so that self.hierarchy = last_one.next is evaluated in the scope of the parent.

Now, I add the version management feature. Thanks to a new_version method added to the controller, a document is duplicated using the @document.dup method, and then it is saved: the hierarchy is supposed to remain the same, and only the version number needs to be incremented.

Fine. But the before_create filter is triggered by the save action in the model, and the hierarchy is incremented, which does not fit the requirements.

How can I prevent the before filter in the model from triggering in the case of the new_version action in the controller?

2

There are 2 best solutions below

0
Ilya Konyukhov On BEST ANSWER

I think this is the good case to use skip_callback method:

BusinessRule.skip_callback(:create, :before, :set_hierarchy)

# your code to create BusinessRule objects without setting hierarchy
# ...

BusinessRule.set_callback(:create, :before, :set_hierarchy)

If you're going to skip/set callbacks quite often you could simplify it using special helping method:

# config/initializers/without_callback.rb

module ActiveSupport::Callbacks::ClassMethods
  def without_callback(*args, &block)
    skip_callback(*args)
    yield
    set_callback(*args)
  end
end

And you will be able to skip a callback like this:

BusinessRule.without_callback(:create, :before, :set_hierarchy) do 
  # your code to create BusinessRule objects without setting hierarchy
  # ...
end
0
arieljuod On

I'm not sure if this is the best way to do this, but I'd do something like this.

class BusinessRule < ActiveRecord::Base
  attr_accessor :skip_set_hierarchy

  before_action :set_hierarchy, unless: :skip_set_hierarchy

  ...
end

Now, if you don't want the callback to be triggered, you can set that to true on demand:

def new_version
  business_rule = BusinessRule.new business_rule_params
  business_rule.skip_set_hierarchy = true
  business_rule.save
  #this can be refactored a lot (set the skip_set_hierarchy to true inside params, use create instead of new, I made it verbose on purpose to make it clearer)
end

ActiveRecord will skip the callback because skip_set_hierarchy will return true. You don't need to change the rest of the code, since by default it will return nil.