can anyone tell me how to skip all before filters in rails 3.
In rails 2.x we could do
skip_filter filter_chain
however filter_chain is no longer supported in rails 3.
Thanks
Try this
skip_filter *_process_action_callbacks.map(&:filter)
Method _process_action_callbacks should return CallbackChain instance, which is an array of Callbacks
And since Callback#filter gets the name of the callback, this works:
before_filter :setup
_process_action_callbacks.map(&:filter) #=> [:setup]
Need to skip all filters is likely caused by inheriting from a custom ApplicationController.
class ApplicationController < ActionController::Base
# defines multiple `before_filter`s common to most controllers
class SomeController < ApplicationController
# this controller may be fine with inheriting all filters
class AnotherController < ApplicationController
# but this one not!
In my example scenario, instead of removing the before_filters from AnotherController, just let it inherit from ActionController::Base.
Haven't tried it, but this might work:
[:before, :after, :around].each {|type| reset_callbacks(type)}
If you want to specify :only or :except to skip_filter, use the following :
skip_filter(:only => [:method1, :method2], *_process_action_callbacks.map(&:filter))
Xavier Shay put me on the right direction, but then I struggled a bit to figure out I had to put :only before the list of filters to skip!
Edit : the solution above is for RUby 1.8.7. For Ruby 1.9 you'd do :
skip_filter(*_process_action_callbacks.map(&:filter), :only => [:method1, :method2])
For Rails 5, I've used
class SomeController < ApplicationController
skip_before_action *_process_action_callbacks.map{|callback| callback.filter if callback.kind == :before}.compact
You must check the callback.kind, otherwise _process_action_callbacks will return all callbacks, including after and around, which will raise an exception with skip_before_action method.
The .compact at the end removes nils from the resulting array.
This is certainly hacking deep inside Rails belly and you would be better off specifying the callbacks by hand, but the following line will do the job:
eval %[skip_filter #{_process_action_callbacks.select { |c|
[:before, :after, :around].include? c.kind }.collect{|c|
c.filter.inspect}.join(", ")
}]
You can also add :only => :index etc modifications to the eval just before the ending ] to further modify the call if needed.
skip_before_filters
http://ap.rubyonrails.org/classes/ActionController/Filters/ClassMethods.html#M000132
Related
I've got several before filters similar to:
before_filter :setup_plan, except: :some_action, :another_action, :yet_another_action
But I have a 3 or 4 exceptions to many before filters. At first I was going to change the logic in all of my before_filter methods, but I found myself repeating a lot of code. In a more perfect world I would have a seperate controller for the actions I want to add, but I've got to add the actions in the same controller, and work around the structure that's already in place.
What I want to do is create a constant or variable with the methods I want to skip in my before filters, such as
ACTIONS_TO_SKIP = [:some_action, :another_action, :yet_another_action]
And then simply use before_filter :setup_plan, except: ACTIONS_TO_SKIP
I get an uninitialized constant error when doing this. I tried moving this to a method in a helper and also got an undefined method error.
I know I'm missing something, but can't figure it out. Is there really no way to pass an method or constant that returns an array of methods I want to skip in my before filters? Just trying to make my controller a little bit cleaner and less verbose.
You will need to declare the constant BEFORE the call to skip. The file is interpreted top down.
class FoosController
ACTIONS_TO_SKIP = [:yes, :this, :and, :something, :more]
before_filter :setup_plan, except: ACTIONS_TO_SKIP
end
Note that in recent Rails versions this is now called before_action:
Rails 4: before_filter vs. before_action
(perhaps you want to upgrade...)
You can try something like this:
before_filter :my_before_filter, if: :action_to_skip?
def action_to_skip?
%w[some_action another_action yet_another_action].member?(action_name)
end
I've just upgraded my app to Rails 5.1 and I've been bitten by the new behaviour of skip_before_action callbacks. i.e. if callback is not defined at the time I try to skip it, it raises an error.
I know that I can pass raise: false like
skip_before_action :authorise, raise: false
But wondering if there's a better way to do it.
My main problem is that with eager load set to true, the new behaviour messes up with modular setup of my controllers.
Basically I've got dir app/controllers/api
with module_controller.rb:
module Api
class ModuleController < ActionController::Base
before_action :authorise
end
end
Then I've got app_chats_controller.rb which skips the authorise callback:
module Api
class AppChatsController < ModuleController
skip_before_action :authorise
end
end
With eager load, app_chats_controller.rb gets loaded first, which means callback is not yet defined and without raise: true error is raised.
If I have to bite the bullet and add raise: false to everything, so be it, but surely there's a better way...
Try adding require 'module_controller' to the top of app_chats_controller.rb
Does around_action in ApplicationController::Base include before_action and after_action? I understand that around_action wraps around the specified action, but would like to know if it also wraps around the before, and after callbacks associated with that action.
For instance, let's look at a code modified from Rails documentation:
class ChangesController < ApplicationController
before_action :some_callback, only: show
around_action :wrap_in_transaction, only: :show
...
private
def wrap_in_transaction
yield unless true
end
end
Will some_callback ever be executed?
Yes, some_callback will be executed. These methods are completely unaware of one another, and will be performed in the order they are written.
It may interest you to see the code that rails uses to do this. You can find it at https://github.com/rails/rails/blob/cdaab2c479c819b04cc72a97c52b804832365cef/actionpack/lib/abstract_controller/callbacks.rb#L180. You will notice that they both call the _insert_callbacks method (https://github.com/rails/rails/blob/cdaab2c479c819b04cc72a97c52b804832365cef/actionpack/lib/abstract_controller/callbacks.rb#L87).
Also, why not just try it using console output or something? This type of thing should be very easy to verify with a quick trial (which is, I suspect, the reason behind this question's downvote).
I'm currently developing a couple of modules to reuse code from my controllers on a Rails 3 using InheritedResources (last version) app.
My idea is to have some behavior that should be run after a successful create or update of the resource but, except from redeclaring the "create" or "update" actions, I'm not to sure on how to tackle this.
I'm currently using something like
module SessionStorable
extend ActiveSupport::Concern
include Base
included do
before_filter :setup_resource, :only => :new
after_filter :reset_session_resource_id, :only => [:create, :update]
end
# ....
end
I have a particular resource setup I use which, among other things, adds the id of the resource to the session. After the resource has being successfully saved to the BD, I'd like to remove it's id from the session and that is what the after_filter does.
I've deal with it so far by also saving the updated_at info onto the session and comparing to see if the model was updated (if so, it should have been successfully) and run the method.
However, I'm not to happy with it (kinda hacky) and also I'm planning on having other modules that will work with resources also after they've been updated and wouldn't want to use the same approach twice.
Is there a hook on IR that I should be using? Or any other ideas on how to proceed?
I've solved it by using the "object.errors.empty?" condition. If there are no errors on the object after the create or update action, it should be safe to assume that the model was saved properly, and thus running the code would be fine.
Maybe you could use an inheritance based approach instead:
class BaseController < InheritedResources::Base
before_filter :setup_resource, :only => :new
after_filter :reset_session_resource_id, :only => [:create, :update]
# ...
end
class YourController < BaseController
# ...
end
I'm sorry to use the answer feature for a comment, but since I can not do it under your answer I see no other option.
"object.errors.empty?" condition. If there are no errors on the object after the create or update action, it should be safe to assume that the model was saved properly
I think this is not always true, let me put you and example:
class Project < ActiveRecord:Base
has_many :members
# ...
end
Imagine you got a form for the project where you could also create members for it (nested forms). Errors in the creation of the associated members will make de project object invalid, but the project instance will return true for the method errors.empty?
Does rails make any guarantees about the order that before filters get executed with either of the following usages:
before_filter [:fn1, :fn2]
or
before_filter :fn1
before_filter :fn2
I'd appreciate any help.
If you refer http://api.rubyonrails.org/v2.3.8/classes/ActionController/Filters/ClassMethods.html, there is a subheading called "Filter chain ordering", here is the example code from that:
class ShoppingController < ActionController::Base
before_filter :verify_open_shop
class CheckoutController < ShoppingController
prepend_before_filter :ensure_items_in_cart, :ensure_items_in_stock
According to the explanation:
The filter chain for the CheckoutController is now
:ensure_items_in_cart, :ensure_items_in_stock,
:verify_open_shop.
So you can explicitly give the order of the filter chain like that.
Before_filter Order in Rails
http://b2.broom9.com/?p=806
Filter chain ordering
http://rails.rubyonrails.org/classes/ActionController/Filters/ClassMethods.html
If you need guarantee order, you may do this:
before_filter :fn3
def fn3
fn1
fn2
end
as far as I can tell, you put the first function you want to execute and so forth.
So, something like:
before_filter :fn1, :fn2
def fn1
puts 'foo'
end
def fn2
puts 'bar'
end
Would execute fn1, then fn2.
Hope that helps.
The filter chain for the CheckoutController does not follow this order
:ensure_items_in_cart, :ensure_items_in_stock, :verify_open_shop
Instead, it should be
:ensure_items_in_stock, :ensure_items_in_cart, :verify_open_shop