before_filter question

If one places a before_filter in class ApplicationController, when is
the before filter called and for which methods.

I believe it gets called before any "action" ... but how does rails know
that the method is an action?

Ralph Shnelvar wrote:

If one places a before_filter in class ApplicationController, when is
the before filter called and for which methods.

Does
http://www.railsapi.com/doc/rails-v2.3.8/classes/ActionController/Filters/ClassMethods.html
answer your question?

I believe it gets called before any "action" ... but how does rails know
that the method is an action?

All (public) controller methods are in principle actions in Rails. If
you have ones that aren't, get them out of the controller or make them
private.

Best,

Hi Ralph,

Good question. Methods in controllers are considered actions only if
they're connected to a url. Urls are connected to controller methods
by using routes. The routes.rb file lists all of the routes that will
connect urls to controllers and actions.

In your routes, when you use map.connect (in Rails 1.x, 2.x) you
directly connect a url to an action method. In Rails 3.0, this is
done with match() instead of connect, but the idea is the same.

If you use map.resources then you're connecting a whole slew of urls
to a certain actions in your controller. Check the docs for details,
but this is the "restful" style of URL handling, and means that these
methods in your controller will become actions:

index
new
create
edit
update
show
destroy

Finally, be warned that in Rails 1.x and 2.x, when you generate a new
Rails app, by default a pattern-match connector is written for you,
exposing ALL of your methods as actions, which is probably not what
you want. You should remove or comment those out.

Jeff

purpleworkshops.com

Jeff Cohen wrote:
[...]

Good question. Methods in controllers are considered actions only if
they're connected to a url.

That's not true at all. For example, if you have

class PlaysController < ApplicationController
  def write_shakespeare
  ...
  end
end

then (unless I'm badly mistaken) you can get to the write_shakespeare
method by (say) calling

redirect_to :controller => 'plays', :action => 'write_shakespeare'

regardless of what's in your routes file. There may not be a direct URL
to that action, but that doesn't prevent it from being an action.

Best,

Marnen Laibow-Koser wrote:

Ralph Shnelvar wrote:

If one places a before_filter in class ApplicationController, when is
the before filter called and for which methods.

Does
http://www.railsapi.com/doc/rails-v2.3.8/classes/ActionController/Filters/ClassMethods.html
answer your question?

It certainly helps but it did not address my question directly.

Here's another question:
Is the before_filter ever called before methods in
ApplicationController?

In fact would it be true to say that no method of a controller is
inherently an action or not an action? An action is a verb not a noun
so it is not correct to say that a method is or is not an action. An
action (initiated via a url or redirect_to for example) results in
calling a method of a controller and it is under these circumstances
that the filters are called. Calling a method directly from code will
not result in filters being called.

Colin

Ralph Shnelvar wrote:
[...]

Here's another question:
Is the before_filter ever called before methods in
ApplicationController?

Yes. (Try it and find out!) Most authentication libraries work this
way. Doesn't Devise?

Best,

Colin Law wrote:

Marnen Laibow-Koser wrote:

Ralph Shnelvar wrote:
[...]

Here's another question:
Is the before_filter ever called before methods in
ApplicationController?

Yes. (Try it and find out!) Most authentication libraries work this
way. Doesn't Devise?

Best,
--
Marnen Laibow-Koser
http://www.marnen.org
marnen@marnen.org

Sent from my iPhone

What prevents infinite recursion?

- - - - -
class ApplicationController < ActionController::Base
  before_filter :fetch_logged_user
  before_filter :authenticate, :except => :login

# Filters added to this controller apply to all controllers in the
application.
# Likewise, all the methods added will be available for all controllers.

class ApplicationController < ActionController::Base
  before_filter :fetch_logged_user
  before_filter :authenticate, :except => :login

  helper :all # include all helpers, all the time
  protect_from_forgery

  def fetch_logged_user
    unless session[:user_id].blank?
      @logged_user = User.find(session[:user_id])
    end

  rescue ActiveRecord::RecordNotFound
  end

  def is_logged_in_user?
    !@logged_user.nil?
  end

protected
  def authenticate
    debugger
    unless @logged_user
      #unauthorized access
      redirect_to :controller => :welcome, :status => 401
      return false
    end
  end
end

class ExplanationController < ApplicationController
  def whatIsThisGameAbout
    x = is_logged_in_user?
    debugger
    x
  end

protected
  def authenticate
    debugger
    x=1
  end

end
- - - - -

I am pretty sure that when Rails calls the action whatIsThisGameAbout
that when is_logged_in_user? is invoked that the before_filters are NOT
invoked again before is_logged_in_user? is invoked.

Ralph Shnelvar wrote:
[...]

What prevents infinite recursion?

What would cause infinite recursion?

- - - - -
class ApplicationController < ActionController::Base
  before_filter :fetch_logged_user
  before_filter :authenticate, :except => :login

# Filters added to this controller apply to all controllers in the
application.
# Likewise, all the methods added will be available for all controllers.

class ApplicationController < ActionController::Base
  before_filter :fetch_logged_user
  before_filter :authenticate, :except => :login

  helper :all # include all helpers, all the time
  protect_from_forgery

  def fetch_logged_user
    unless session[:user_id].blank?
      @logged_user = User.find(session[:user_id])
    end

  rescue ActiveRecord::RecordNotFound
  end

  def is_logged_in_user?
    !@logged_user.nil?
  end

protected
  def authenticate
    debugger
    unless @logged_user
      #unauthorized access
      redirect_to :controller => :welcome, :status => 401
      return false
    end
  end
end

class ExplanationController < ApplicationController
  def whatIsThisGameAbout

Hey! Watch the camelCase! That should be what_is_this_game_about .
Actually, it should probably game_info or something.

    x = is_logged_in_user?
    debugger
    x
  end

protected
  def authenticate
    debugger
    x=1
  end

end
- - - - -

I am pretty sure that when Rails calls the action whatIsThisGameAbout
that when is_logged_in_user? is invoked that the before_filters are NOT
invoked again before is_logged_in_user? is invoked.

You're quite right. When you do a straight method call, the filter
chain is not invoked -- after all, it's just a straight method call, and
it works just like it does anywhere else in Ruby. It's only invoked
when you call a controller method *as an action* -- that is, when you go
through the whole Rails stack, as with a Web request or with render
:controller, :action -- that the filter chain is invoked.

Best,

Marnen Laibow-Koser wrote:

Colin Law wrote:

�end
end

then (unless I'm badly mistaken) you can get to the write_shakespeare
method by (say) calling

redirect_to :controller => 'plays', :action => 'write_shakespeare'

regardless of what's in your routes file. �There may not be a direct URL
to that action, but that doesn't prevent it from being an action.

In fact would it be true to say that no method of a controller is
inherently an action or not an action?

No. In Rails, every public controller method is, by definition, an
action. Period. That's all.

OK, I now have to modify my answer. With Ralph's latest question, I see
what you're getting at. So, here's the modified answer:

In Rails, every public controller method can, by definition, *behave as*
an action -- that is, it can be called with suitable use of render
:controller, :action. It can also be called with a regular Ruby-style
method call, in which case it does not behave as an action.

Whether a public controller method behaves as an action depends not on
the method itself but on how it's called.

That said, if you have a controller method (such as Ralph's
fetch_logged_user) that is not meant to be called as an action, it is an
extremely good idea to make it non-public (that is, private or
protected) so that it cannot be called as an action accidentally (or
maliciously).

Best,

Marnen Laibow-Koser wrote:

That said, if you have a controller method (such as Ralph's
fetch_logged_user) that is not meant to be called as an action, it is an
extremely good idea to make it non-public (that is, private or
protected) so that it cannot be called as an action accidentally (or
maliciously).

Ok ... that sent up alarm bells.

So ... how can I prevent Rails from calling, say,
     def fetch_logged_user
       # black blah blah
     end
or
     def is_logged_in_user?
       !@logged_user.nil?
     end
and yet allow all other controllers access to those two functions?

Ralph Shnelvar wrote:

Marnen Laibow-Koser wrote:
> That said, if you have a controller method (such as Ralph's
> fetch_logged_user) that is not meant to be called as an action, it is an
> extremely good idea to make it non-public (that is, private or
> protected) so that it cannot be called as an action accidentally (or
> maliciously).

Ok ... that sent up alarm bells.

So ... how can I prevent Rails from calling, say,
     def fetch_logged_user
       # black blah blah
     end
or
     def is_logged_in_user?
       !@logged_user.nil?
     end
and yet allow all other controllers access to those two functions?

As Marnen said, make it private or protected. Like this:

   protected
     def fetch_logged_user
       ...
     end

Bob