質問

railstutorial.org has a suggestion which strikes me as a little odd.

It suggests this code:

class ApplicationController < ActionController::Base 
  protect_from_forgery 
  include SessionsHelper 
end 

The include SessionsHelper makes the methods available from ApplicationController, yes, but it makes them available in any view, as well. I understand that authentication/authorization is cross-cutting, but is this really the best place?

That seems to me to be potentially too broad of a scope. Putting code which implements, say, a before_filter which conditionally redirects (as the railstutorial.org example does) in a module which more commonly contains view helpers seems surprising.

Would functionality not strictly needed in views be better placed in ApplicationController or elsewhere?

Or am I just thinking too much about this?

役に立ちましたか?

解決

Indeed, your feeling is correct.

I would implement this the other way around: add the functions sign_in and current_user to ApplicationController (or if you really want to: in a separate module defined in lib and include it), and then make sure that the current_user method is available in the view.

In short:

class ApplicationController

  helper_method :current_user

  def sign_in

  end

  def current_user
    @current_user ||= user_from_remember_token
  end
end

Of course, if you have a lot of code to place into your ApplicationController it can get messy. In that case I would create a file lib\session_management.rb:

module SessionManagement
  def self.included(base)
    base.helper_method :current_user
  end

  def sign_in
    ..
  end

  def current_user
    ..
  end
end

and inside your controller you can then just write:

class ApplicationController
  include SessionManagement
end

他のヒント

They seem to be taking (sneaky) advantage of the fact that, in Rails, Helpers are just ruby Modules.

Placing behavior that is shared across Controllers in a Module is, in my opinion, good practice. Putting it in a Helper, on the other hand, is potentially misleading and I would avoid it. Place it in a “standard” Module.

This is a philosophical question on the same level as the argument that questions the REST method provided in scaffolding and if A scaffold is worth having at all. You have to consider the fact that the tutorial book in RailsTutorial.org is a get-up-and-go Rails instructive guide. So for the purpose which it serves, I think it does the job.

However, is there a better place to put code needed across controllers and views? Yes, there is.

  • Some may follow Michael Hartl form Railstutorial and include the entire SessionHelper into the ApplicationController
  • Others may decide to expose only the essential helpers needed for the view i.e. sign_in, sign_out, current_user and the like.
  • I see a suggestion to put such code in the /lib directory and include it where needed.

All are viable options. Whichever you take may not matter that much in performance because Ruby would have to parse the file which you want to call (or include) a class, module or method from. What happens is, before any code is executed in a class, Ruby goes through the whole class once to know what's in it. It all depends on what one needs and the design of their app

FWIW, I store the current user in the User class:

class User < ActiveRecord::Base
  cattr_accessor :current
  ...
end

This can be referenced in all 3 MVC tiers; it is set in the controller like so (and likewise on login, of course):

def set_current_user
  User.current = (session[:user_id]) ? User.find_by_id(session[:user_id]) : nil
end

Among other things, this allows me to have audit logs at the ActiveRecord level that capture the current user (when applicable).

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top