How to get request's target controller and action with Rails 3? - ruby-on-rails

In the application controller before filter.
class ApplicationController < ActionController::Base
before_filter :authenticate
def authenticate
# How do we know which controller and action was targetted?
end
end

class ApplicationController < ActionController::Base
before_filter :authenticate
def authenticate
# How do we know which controller and action was targetted?
params[:controller]
params[:action]
# OR
controller.controller_name
controller.action_name
end
end

In Rails 3.2 you no longer need to call controller.action_name explicitly instead just "action_name".
before_filter :check_if_locked
def check_if_locked
puts action_name
puts controller_name
end

You can get full url object using
url = Rails.application.routes.recognize_path(request.env['PATH_INFO'])
now you can get components as
url[:controller]
url[:action]
By default you can also use params[:controller] and params[:action] respectively during request/response life cycle.

request.parameters['controller']
request.parameters['action']

Related

How to get the name of the action in an after_action filter for ActionMailer

In the class below, how do I get the current action name (i.e. email_confirmation, password_reset) in side the after_action callback add_mandril_headers?
class UserMailer < ActionMailer::Base
after_action :add_mandril_headers
def email_confirmation(user)
mail(..)
end
def password_reset(user)
mail(..)
end
private
# how to get the action name?
def add_mandrill_headers
headers['X-MC-Tags'] = [mailer_name, action_name].join('_');
end
end
Turns out action_name returns the current mailer action name. I tried it based on the fact that ActionController has a similar method.
Thanks #HarishShetty!
As you mentioned, the action_name is good for all Controllers, as it is inherited from ApplicationController.
For example, I was using public_activity and wanted some simplification in my controllers:
class SiteDetailsController < ApplicationController
after_action :track_activity, only: [:create, :update, :destroy]
# ...
private
def track_activity
#site_detail.create_activity action_name, owner: current_user
end
end

Redirect all pages except 1 to a single Temporary Unavailable Page in Rails

We have a fully functional website but the backend is going down for maintenance, so we want to redirect all our customers to www.example.com/unavailable. Except for 1 page www.example.com/admin since this is the admin page where we put the unavailable page on and off.
So my question:
Is it possible to turn routes on and off like this:
Example code for routes.rb:
if Settings.unavailable
get "*", to: "/unavailable", except: "/admin"
end
With the help from the post from Michal, I've adapted his answer to the following:
class ApplicationController < ActionController::Base
before_filter :check_maintenance
def check_maintenance
if Settings.first.maintenance && request.fullpath.split("?")[0].gsub("/","") != 'unavailable' && (request.fullpath.split("?")[0].exclude? "admin") # or other conditions
redirect_to '/unavailable'
end
end
end
You can put conditions in your routes.rb but you won't be able to detect what is the current url. You should put this logic in before_filter in ApplicationController (or other top level controller):
class ApplicationController < ActionController::Base
before_filter :check_maintenance
def check_maintenance
if Settings.unavailable && action_name != 'unavailable' # or other conditions
redirect_to '/unavailable'
end
end
end

Class variables with params values in ApplicationController

In appllication controller i have couple of methods that works with requested controller and action name.
To follow DRY principe, i want to define share variables with those params.
class ApplicationController < ActionController::Base
##requested_action = params[:action]
##requested_controller = params[:controller]
end
But i get error: undefined local variable or method "params" for ApplicationController:Class
Why i can't do this and how can i achieve my goal?
I believe you already have controller_name and action_name variables defined by Rails for this purpose.
If you want to do it by your way, you must define it as a before filter as params comes to existence only after the request is made. You can do something like this
class ApplicationController < ActionController::Base
before_filter :set_action_and_controller
def set_action_and_controller
#controller_name = params[:controller]
#action_name = params[:action]
end
end
You can access them as #controller_name and #action_name. But controller_name and action_name are already defined in Rails. You can use them directly.
Use instance methods instead:
class ApplicationController < ActionController::Base
def requested_action
params[:action] if params
end
end
You can use before_filter option.
class ApplicationController < ActionController::Base
before_filter :set_share_variable
protected
def set_share_variable
#requested_action = params[:action]
#requested_controller = params[:controller]
end
end

How to skip a before_filter for Devise's SessionsController?

I have a before_filter in my ApplicationController; that is, for every controller in my project.
How can I skip_before_filter for Devise's SessionsController create action ?
Here's a method my colleague just showed me:
# In config/application.rb
module YourAppNameHere
class Application < Rails::Application
# Whatever else is already here...
# The part to add
config.to_prepare do
Devise::SessionsController.skip_before_filter :your_before_filter_here
end
end
end
I recently had this problem with filter in my application_controller I solved it using skip_before_filter
skip_before_filter :check_subdomain!, if: :devise_controller?
We did something like this:
First up, create your own session controller, make sure to inherit correctly:
class SessionsController < Devise::SessionsController
skip_before_filter :foobar
Then fix the routes
devise_for :users,
:controllers => {
:sessions => "sessions"
}
Alternatively you could monkey-patch Devise's session controller.
Here's another way in lib/devise_sessions_controller_decorator.rb:
module DeviseSessionsControllerDecorator
extend ActiveSupport::Concern
included do
skip_before_filter :your_filter_name
end
end
Devise::SessionsController.send(:include, DeviseSessionsControllerDecorator)
Because classes are not cached in development mode, you may need to add something like this to config/environments/development.rb:
config.to_prepare do
Devise::SessionsController.send(:include, DeviseSessionsControllerDecorator)
end
Before my colleague showed me the way I posted in my other answer, I did this. I'm posting this in case you think it's simpler.
class ApplicationController < ActionController::Base
# ...
before_filter :do_something
def do_something
unless params[:controller] == 'devise/sessions'
# ...
end
end
end
You can simply check in your filter method whether it is devise controller or not.
if params[:controller] != 'devise/sessions'
new answer
what about wrapping the before_filter in an unless block filtering by params[:controller]
def some_before_action
unless params[:controller] == "sessions_controller_for_devise_name"
... #=> do the stuff here
end
end
old answer
just authorize which actions should use the before filter
before_filter :action, :only => ...
and authorize your others.
found this here

Identifying the caller of a method in ApplicationController (RoR)

I have a method in my ApplicationController that is part of a before_filter. How do I identify which controller is calling that method and can I pass arguments to it?
Presumably worst case, I can create a new object where I use controller names and values, then call it directly in the before_filter method with NewObject.find(:first, :conditions => ['controller_name = ?', controller_name], but that smells very bad.
So I'm open to ideas. Thanks in advance.
psuedo-short-code:
class ApplicationController < ActionController::Base
before_filter :someMethod
....
def someMethod
Do stuff
end
class SomeController < ApplicationController
# presumably the before_filter runs here
#someValueIWantToPass = some.value
...
params[:controller] and params[:action] contain the controller and action requested, and are available from inside a filter.
Using self.class will tell you which controller has called the before_filter.
class HomeController < ApplicationController
before_filter :awesome
def index
render :text => #blah
end
def awesome
#blah = self.class
end
end
will render out "HomeController"

Resources