How to invoke method once per page reload? defining before_filter in ApplicationController is failed because of multiple controllers used to perform action
When you say multiple controllers are used in one action, could you be more specific? Normally a before_filter in the controller responsible for the action would suffice.
If you want your before filter to affect specific methods in multiple controllers then place the method itself in the ApplicationController but the before_filter in each of the controllers that contain the action.
class ApplicationController
def foo
#bar = 'bar'
end
end
class UserController
before_filter :foo, :only => [:method1]
def method1
...
end
def method2
...
end
end
class StuffController
before_filter :foo, :only => [:method2]
def method1
...
end
def method2
...
end
end
class UnimportantController
# No before filter, neither of these methods will call :foo
def method1
...
end
def method2
...
end
end
Related
how can I filter a second before_action?, I have two controllers, and when I call the method A, a before_action executes a methodB, but before executing this second method I would like to execute a general methodC, but in this method I need to pass a parameter to know where is coming from, but if I use a second before_action this doesn't work, because "only" in before_action filters using the first method method (which is methodA), what can I do?
class FirstController < SecondController
before_action :methodB
def methodA
#some code
end
end
class SecondController < ApplicationController
before_action only: [:methodB] do
methodC('methodB')
end
def methodB
#some code new
end
end
class ApplicationController < ActionController::Base
def methodC(method)
#general method
end
end
This is the structure that I have:
I'm out of practice with rails but would the following be acceptable?
class FirstController < SecondController
before_action :methodB
def methodA
#some code
end
private
def should_call_C
action_name == :methodA
end
end
class SecondController < ApplicationController
before_action do |controller|
methodC if controller.should_call_C
end
def methodB
#some code new
end
private
def should_call_C
action_name == :methodB
end
end
class ApplicationController < ActionController::Base
def methodC
#general method
# can use action name to get method rather than passing it?
end
end
I have to change the value of keys inside params of a controller. I don't want to do it each method but do it at a constructor level. But when I access it inside initialize I get this error
"NoMethodError (undefined method `parameters' for nil:NilClass):"
class MyController < ApplicationController
def initialize
puts params.inspect #params is nil!
end
end
I also tried to do that using before_action but the same error
class MyController < ApplicationController
before_action :my_initializer
def initialize
puts params.inspect #params is nil!
end
def my_initializer
puts params.inspect #params is nil!
end
end
Thanks
You should use before_action without initialize to make it work:
class MyController < ApplicationController
before_action :my_initializer
def my_initializer
puts params.inspect
end
end
i have some actions in controller and put authorize for 3 actions,
class TestController
def test1
authorize! :view, :testcase1
#do things1
end
def test2
authorize! :view, :testcase2
#do things2
end
def test3
authorize! :view, :testcase3
#do things3
end
end
and in the corresponding action's view, i am checking like this
if can? :view, :test_case1
#do things
end
So the problem is i am calling the authorize in 3 functions, can i put it like a single, same as before_filter
I'm not quite sure what you're getting at, but load_and authorize_resource is typically the best way to go. If you need to skip a controller action, you can do something like this:
class TestController
load_and_authorize_resource
skip_authorize_resource :only => :new
end
Add this to the class
class TestController
load_and_authorize_resource
end
and you dont need to use authorize in every action
https://github.com/ryanb/cancan/wiki/authorizing-controller-actions
I have made the following validation method:
def if_admin(&block)
if #current_user.administrator?
yield
else
redirect_to '/go_away'
end
end
and i find my classes are increasingly looking like:
class Foo < ApplicationsController
def index
if_admin do
.....
end
end
def show
if_admin do
.....
end
end
def new
if_admin do
.....
end
end
def edit
if_admin do
.....
end
end
.......
end
I want to know if there is anything similar to before_action which would pass the method into the if_admin method, thus DRYing up the code?
Just like you wrote, there is before_action. You can use it like this:
class Foo < ApplicationsController
before_action :if_admin
# ...
private
def if_admin
redirect_to '/go/away' unless #current_user.administrator?
end
end
I'm trying to implement a Cache Sweeper which would filter a specific controller action.
class ProductsController < ActionController
caches_action :index
cache_sweeper :product_sweeper
def index
#products = Product.all
end
def update_some_state
#... do some stuff which doesn't trigger a product save, but invalidates cache
end
end
Sweeper Class:
class ProductSweeper < ActionController::Caching::Sweeper
observe Product
#expire fragment after model update
def after_save
expire_fragment('all_available_products')
end
#expire different cache after controller method modifying state is called.
def after_update_some_state
expire_action(:controller => 'products', :action => 'index')
end
end
The ActiveRecord callback 'after_save' will work fine, but the callback on the controller action 'after_update_some_state' never seems to be called.
Looks like I was just missing the controller name when trying to get the callbacks for controller actions working. My Sweeper should be:
class ProductSweeper < ActionController::Caching::Sweeper
observe Product
#expire fragment after model update
def after_save
expire_fragment('all_available_products')
end
#expire different cache after controller method modifying state is called.
def after_products_update_some_state
expire_action(:controller => 'products', :action => 'index')
end
#can also use before:
def before_products_update_some_state
#do something before.
end
end
I think your sweeper should look like this:
class ProductSweeper < ActionController::Caching::Sweeper
observe Product
def after_save(product)
expire_cache(product)
end
def after_destroy(product)
expire_cache(product)
end
private
def expire_cache(product)
expire_fragment('all_available_products')
expire_page(:controller => 'products', :action => 'index')
end
after_index isn't a callback unless you define it.
In the controller you should specify those actions in which the sweeper should be triggered, in a restful way those actions should be create, update, destroy, so your controller declaration should look like:
class ProductsController < ActionController
caches_action :index
cache_sweeper :product_sweeper, :only => [:create, :update, :destroy]
def index
#products = Product.all
end
def create
#product = Product.new(params[:product])
if #product.save # triggers the sweeper.
# do something
else
# do something else
end
end
# update and stuff ...
end
I hope it helps you!