How to set default render for all action - ruby-on-rails

My application in many action use render :nothing => true. I want be DRY. How can I say to rails by default render nothing for a particular controller?

You could do something like:
# put this in a module, or your ApplicationController
def self.nothing_for *actions
before_filter :only => actions do
render :nothing => true
end
end
# This would go in your specific controllers
nothing_for :show, :new, :create

This might do what you need:
before_filter :render_nothing
private
def render_nothing
render :nothing => true
end
before_filter and not after_filter because the latter is executed after the action finished, which means, after the content was rendered.
Source: http://ap.rubyonrails.org/classes/ActionController/Filters/ClassMethods.html#M000128

Related

Use action from a controller as filter in another controller in rails

I am trying to create an action that checks if a user is permitted to perform a certain action and if the user isn't then I want to redirect the user to an "Access Denied" view
This is how my current setup is
class PermissionController < ApplicationController
def authorize(permission_id)
is_permitted = is_user_permitted(permission_id)
respond_to do |format|
format.js { render :json => {:is_permitted => is_permitted, :redirect => url_for(:controller => 'welcome', :action => 'index' , notice: "No access")}}
format.all { redirect_to :controller => 'welcome', :action => 'index' , notice: "No access" unless is_permitted == true }
end
end
end
I want to call the authorize action in the :before_filter of another controller.
How do I do that?
I can't put the authorize action in the ApplicationController since I want to define a route to this action in routes.rb
#NickM has covered this in his comment... have OtherController inherit from PermissionController
class PermissionController < ApplicationController
def authorize
...
end
end
class OtherController < PermissionController
before_filter :authorize
end
However I note your authorize method has a parameter?
You'll need to handle that in the before_filter clause. Assuming you can store permission_id in a session variable...
class PermissionController < ApplicationController
def authorize(permission_id)
...
end
end
class OtherController < PermissionController
before_filter { |controller| controller.authorize(session[:permission_id] }
end
Why don't you try something like this, assuming you have the user's id stored in session:
class ApplicationController < ActionController::Base
def current_user
return unless session[:user_id]
#current_user ||= User.find(session[:user_id])
end
def authorize
# If user is NOT permitted
if !is_user_permitted(current_user)
# Response for you ajax here
respond_to do |format|
format.js { render :json => {:is_permitted => false, :redirect => url_for(:controller => 'welcome', :action => 'index' , notice: "No access")}}
format.all { redirect_to :controller => 'welcome', :action => 'index' , notice: "No access" }
end
end
end
end
class SomeOtherChildController < ApplicationController
before_filter :authorize, :only => [:show, :new, :edit]
# or you can use :except => [:index, :create, :destroy, :update] instead of :only.
# No authorization required
def index
end
# Authorization required
def show
end
# Authorization required
def new
end
# No authorization required
def create
end
# Authorization required (Ajax response for your "Edit" button)
def edit
# authorize method in ApplicationController will be called first
# If user is authorized, then the rest of this action will be executed
respond_to do |format|
format.js { render :json => {:is_permitted => true} }
end
end
# No authorization required
def update
end
# No authorization required
def destroy
end
end
Take this as an outline and general concept to what you might want to implement.
This is typically a concept I implement with permissions in my apps. You probably wouldn't want to put the Permissions logic in a separate child class controller, because in order to check permissions, you would either have to create a reference object of the PermissionsController (that is ugly and very un-Rails like) and use it within whatever controller you're trying to check permissions for, or you will have all other controller classes inherit from the PermissionsController, which isn't terrible, but certainly not ideal.
If users can have multiple types of permissions, you are probably better off creating a Permission model and controller, with a User has_many Permissions relationship, where the logic in the authorize method would become a bit easier to implement.

How to customize an Observer to a action of the Controller in Ruby on Rails

my question is: I need to access one action after another Controller action is accessed, completed and rendered and the second reason action will have another rendering. Observers thought to use, but from what I read they deal only with Models.
def action_1
render :xml => {:success => "Msg success."}
end
def action_2
render :nothing => "", :locals => {:scheduling_id => scheduling_id}
end
"Actions" are just method calls. action_1 can call action_2, but you can't call render more than once, so you have a structure problem you'll need to deal with.
Perhaps something like this is what you're going for?
class MyController < ApplicationController
def my_action
# ...
my_shared_stuff
render ...
end
private
def my_shared_stuff
# ... shared things
end
end

How do I define default respond_to for index & show action in application controller?

I was wondering is there any way to define default respond_to for index & show actions in Application Controller with an ability to override in other controllers that need some customization.
I think it's going to be easier with an example.
I'm using InheritedResources, CanCan/Authlogic and WickedPDF gems to generate my pdf and authorize users. I was wondering if I can dry up my code.
Here is what I have
class ProductsController < InheritedResources::Base
load_and_authorize_resource
respond_to :html, :xml, :json, :pdf
def index
#products = Product.page(params[:page])
index! do |format|
format.pdf do
render :pdf => pdf_file_name,
:show_as_html => params[:debug].present?
end
end
end
def show
show! do |format|
format.pdf do
render :pdf => pdf_file_name,
:show_as_html => params[:debug].present?
end
end
end
end
class CustomersController < InheritedResources::Base
def index
index! do |format|
format.pdf do
render :pdf => pdf_file_name,
:show_as_html => params[:debug].present?
end
end
end
def show
show! do |format|
format.pdf do
render :pdf => pdf_file_name,
:show_as_html => params[:debug].present?
end
end
end
end
This works just fine. But it seems redundant that I need to define format.pdf in every controller that I'm want to generate pdf for. Is there any way to move this to application controller or specify somewhere using inherited resources, and then just override this on a per controller basis? Any ideas?
Thank you
Ok I came up with the following solution for anyone else interested.
I figured I can add a controller that will inherit from InheritedResources, which inherits from ApplicationController, and then have all my other controllers inherit from it ( except for a couple of special cases that will inherit directly from application controller ( like the HomeController, that doesn't have any actions other than index, and is not tied to any particular model) - this way I can define certain defaults - that I keep using in all my controllers such as respond_to, and still enjoy the benefits of InheritedResources gem.
class DefaultInheritedResourcesController < InheritedResources::Base
# For CanCan authorization - pretty much makes it application wide, without the need
# to define it in each controller. Can still override it in ability.rb by making
# a resource readable to all users with a session.
# if user
# can :read, [Product]
# end
# Also for controllers that need special treatment, you can just inherit from ApplicationController
# and override with skip_authorization_check - but for my app it's rare (only HomeController),
# most of controllers deal with some kind of resource - so this is a useful convention for 99% of use cases.
load_and_authorize_resource
respond_to :html, :json, :xml, :pdf
# format pdf needs to be redefined on those actions where index! or show! are called.
def index
super do |format|
format.pdf do
render :pdf => pdf_file_name,
:show_as_html => params[:debug].present?
end
end
end
def show
super do |format|
format.pdf do
render :pdf => pdf_file_name,
:show_as_html => params[:debug].present?
end
end
end
end
Then in my ProductController I can do this ( notice where my ProductController is inheriting from.
class ProductsController < DefaultInheritedResourcesController
def index
#products = Product.page(params[:page])
super
end
end
Hope this is going to help someone.

ROR 3 - Specifying specific view file, ignoring application layout

I would like to specify a specific view file to render instead of the default one corresponding the REST architecture, meaning out of my 'create' function in the controller I would like to invoke the 'new' view file - which I believe can be done using:
def create
.
.
render :new
end
But I also need that view file to ignore the cross-site layout specified in layouts/application.html.erb? is there a way to do that?
If it was out of the 'new' function, I could just state "render :layout => false" .. but I need it out of the 'create'
is there something like:
render :new, layout => false
Thanks!
Another way is this:
render :template => :new, :layout => false
I' not sure about that, would have to try it, but i think that you can do this :
layout 'application', :except => :action_name
to exclude the action in your controller.
EDIT : I just tried it, it works indeed :)
You can do what you mentioned
def create
render :new, :layout => false
end
You can then add the conditions like this
def create
render :new, :layout => user_signed_in?
end
or the other way around depending on your need

Rails Caching: Using sweepers for actions which require parameters

I'm trying to use sweepers to handle my page refreshes. For refreshing index actions, etc everything works fine...but I can't seem to sweepers to interpret page parameters. If anyone can tell me what's wrong with the code below, I'd be very appreciative:
Controller:
class PostsController < ApplicationController
load_and_authorize_resource
cache_sweeper :post_sweeper, :only => [:create, :update, :destroy]
caches_page :index
caches_page :show
caches_action :edit, :new
# This refreshes cache correctly
def index
#posts = Post.all
end
# This creates cache, but does not refresh it (ever). If I place the expire_page command directly into the action (instead of the sweeper), it works fine
def update
#post = Post.find(params[:id])
respond_to do |format|
if #post.update_attributes(params[:post])
flash[:notice] = t(:post_updated)
format.html { redirect_to(#post) }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #post.errors, :status => :unprocessable_entity }
end
end
end
The sweeper:
class PostSweeper < ActionController::Caching::Sweeper
observe Post
def after_create(record)
expire_cache_for_index(record)
end
def after_update(record)
expire_cache_for_index(record)
expire_cache_for_post(record)
expire_cache_for_edit(record)
end
def after_destroy(record)
expire_cache_for_index(record)
expire_cache_for_post(record)
expire_cache_for_edit(record)
end
private
def expire_cache_for_index(record)
expire_page :controller => 'posts', :action => 'index'
end
def expire_cache_for_post(record)
expire_page :controller => 'posts', :action => 'show', :id => record.id
end
def expire_case_for_edit(record)
expire_action :controller => 'posts', :action => 'edit', :id => record.id
end
end
If we assume you copy and pasted the code, then the typo is also in your code. Since you did not get flagged with an error by Rails, we can then assume that the sweepers are not being called. (i.e. the after_update is not being called). I would add some logger messages in to verify that that really is the case.
Questions is about Post:
Is it a decedent of ActiveRecord::Base?
Do you have other callbacks that are returning false and thus stopping the chain?
The sweeper examples on the net consistently put the cache_sweeper line after the caches_xxx lines. I'd be surprised if that makes a difference but its worth checking out.

Resources