1

The dilemma

I'm using a before_filter in my controller that restricts access to admins. However, I want to allow access public access to some methods based on request format. See the index method to understand what I'm talking about.

application_controller.rb

class ApplicationController < ActionController::Base

  # ...

  def current_user
    @current_user ||= User.find_by_id(session[:user])
  end

  def superuser_required
    redirect_to login_path unless current_user.superuser?
  end


end

items_controller.rb

class ItemsController < ApplicationController

  before_filter :superuser_required
  layout 'superuser'

  def index
    @items = Item.all
    respond_to do |format|
      format.html
      format.js # I want public to have access to this
    end
  end

  def show
    @item = Item.find(params[:id])
    respond_to do |format|
      format.html
    end
  end

  def new
    @item = Item.new
    respond_to do |format|
      format.html
    end
  end

  # remaining controller methods
  # ...

end

2 Answers 2

3

Filters have access to the request object which has a format method you can use to obtain the request format. Change your before filter so that if the format is JavaScript then the request processing is allowed to proceed. Something like:

def superuser_required
  return true if request.format == Mime::JS
  redirect_to login_path unless current_user.superuser?
end
Sign up to request clarification or add additional context in comments.

5 Comments

Technically, the superuser_required method is defined in ApplicationController because it's shared for a lot of my controllers. I updated my post to show this. I have several js format actions that are restricted to admins only, so I don't think modifying superuser_required is a safe bet. The respond_to { |f| f.js } in ItemsController#index should be the only action response that is opened to public.
Can you use skip_before_filter for ItemsControllers#index?
John, but the respond_to { |f| f.html } for ItemsController#index needs to be restricted to admins only.
@smotchkiss If it were me I think I'd take the pragmatic approach and add a new unrestricted collection route to ItemsController for the JavaScript.
John Topley, can you elaborate on that a little bit? I'm not sure what a "collection" route is.
2

Way easier than I expected

2 days later

class FoosController < ActiveRecord::Base

  # use :except to open `show` action for public js access
  before_filter :superuser_required, :except => 'index'

  # before_filter does not apply here
  def index
    @foos = Foo.all

    respond_to do |format|

      # restrict behavior on html access for superusers
      format.html do
        superuser_required  # functions same as before_filter
      end

      # unrestricted on js access for public but only shows foo.id and foo.name
      format.js do
        render :text => @foo.to_json(:only => [:id, :name])
      end

    end
  end

  # restricted to superuser per before_filter
  def new
    @foo = Foo.new
    respond_to do |format|
      format.html
    end
  end

  # restricted to superuser per before_filter
  def show
    @foo = Foo.find(params[:id])
    respond_to do |format|
      format.html
    end
  end

end

Either I totally missed something when I was learning about respond_to or my original question was completely incoherent. I just read it again, though, and it still seems like this only (and most) appropriate way to address my issue.

Surprisingly, I couldn't really find any examples of this kind of behavior on the web either. Oh well. Now I know more about respond_to, right?

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.