【问题标题】:SessionsHelper in railstutorial.org: Should helpers be general-purpose modules for code not needed in views?railstutorial.org 中的 SessionsHelper:助手应该是视图中不需要的代码的通用模块吗?
【发布时间】:2011-07-26 21:34:10
【问题描述】:

railstutorial.org 有一个让我觉得有点奇怪的建议。

It suggests this code

class ApplicationController < ActionController::Base 
  protect_from_forgery 
  include SessionsHelper 
end 

include SessionsHelper 使ApplicationController 中的方法可用,是的,但它也使它们在任何视图中都可用。我知道身份验证/授权是跨领域的,但这真的是最好的地方吗?

在我看来,范围可能过于广泛。将实现例如 before_filter 的代码放入一个更常见的包含视图助手的模块中,该模块有条件地重定向(如 railstutorial.org 示例所做的那样),这似乎令人惊讶。

视图中不需要的功能是否最好放在 ApplicationController 或其他地方?

还是我想太多了?

【问题讨论】:

    标签: ruby-on-rails ruby encapsulation helpers railstutorial.org


    【解决方案1】:

    确实,你的感觉是对的。

    我会以相反的方式实现这个:将函数 sign_incurrent_user 添加到 ApplicationController (或者如果你真的想要:在 lib 中定义的单独模块中并包含它),然后确保 current_user 方法在视图中可用。

    简而言之:

    class ApplicationController
    
      helper_method :current_user
    
      def sign_in
    
      end
    
      def current_user
        @current_user ||= user_from_remember_token
      end
    end
    

    当然,如果您要在ApplicationController 中放置大量代码,它可能会变得混乱。在这种情况下,我会创建一个文件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
    

    然后你可以在你的控制器里面写:

    class ApplicationController
      include SessionManagement
    end
    

    【讨论】:

    • base.helper :current_user code不正确,应该是base.send :helper_method, : current_user
    • 谢谢@kain,小错字。应该是helper_method。但是你可以写base.helper_method, :current_user
    • 小问题:在这种情况下,使用 SessionHelper 和使用 SessionManagment 模块有什么区别?助手不就是另一个模块吗?
    • 帮助文件,位于app/helpers 下会自动包含在视图中。因此,它有望包含简单的视图功能。这就是为什么我建议将它放在一个单独的模块中:它包含的不仅仅是查看功能。在 Rails 4 术语中,这种方法已经正式化:它们现在称为concerns
    【解决方案2】:

    FWIW,我将当前用户存储在 User 类中:

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

    这可以在所有 3 个 MVC 层中引用;它是这样在控制器中设置的(当然在登录时也是如此):

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

    除其他外,这使我可以在 ActiveRecord 级别拥有捕获当前用户的审核日志(如果适用)。

    【讨论】:

    • 这会造成并发问题吗?
    • 只要在 ApplicationController 中设置了 User.current,我就没有任何并发​​问题。有一次我在 AuthenticatedSystem 的模块文件中的 lib 中设置 User.current - 并且确实存在并发问题(可能与更改代码中的错误有关 - 我恢复而没有费心进行太多调查)。现在我有一个检查并发问题的集成测试:)。
    【解决方案3】:

    这是一个哲学问题,与质疑脚手架中提供的 REST 方法以及脚手架是否值得拥有的论点处于同一水平。您必须考虑这样一个事实,即 RailsTutorial.org 中的教程书是一本入门的 Rails 指导性指南。因此,就它所服务的目的而言,我认为它可以胜任。

    但是,有没有更好的地方来跨控制器和视图放置所需的代码?就在这里。

    • 有些人可能会遵循 Michael Hartl 的 Railstutorial 格式并将整个 SessionHelper 包含在 ApplicationController
    • 其他人可能决定只公开视图所需的基本帮助程序,即sign_insign_outcurrent_user 等。
    • 我看到有人建议将此类代码放在 /lib 目录中,并在需要的地方包含它。

    都是可行的选择。无论您采用哪种方式,性能都可能无关紧要,因为 Ruby 必须解析您要从中调用(或包含)类、模块或方法的文件。实际情况是,在一个类中执行任何代码之前,Ruby 会遍历整个类一次以了解其中的内容。这一切都取决于一个人的需求和他们的应用程序的设计

    【讨论】:

      【解决方案4】:

      他们似乎正在(偷偷摸摸地)利用这样一个事实,即在 Rails 中,Helper 只是 ruby​​ 模块。

      在我看来,将控制器共享的行为放在一个模块中是一种很好的做法。另一方面,将它放在 Helper 中可能会产生误导,我会避免它。将其放在“标准”模块中。

      【讨论】:

        猜你喜欢
        • 2015-04-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-25
        相关资源
        最近更新 更多