新手问题 关于 Rails 中 Helper 作用域的困惑

wcc526 · 2014年05月20日 · 最后由 zdsunshine0640 回复于 2014年05月20日 · 6589 次阅读

我对那个 Rails 中的 helper 有点困惑,为什么我的 Helper 里面的方法对所有的 view 是可见的? 比如我在 pages_helper.rb 中定义了一个 def testhelper end 那个这个 testhelper 不仅对 view 中的 pages 可见,对 view 中的 user 也是可见的?这样的话作用域不是太大了?谢谢!

是啊,Helper 只是为了分清那个方法在哪里

我看 CodeSchool 里面关于 Helper 这样说 Issues with Rails view helpers

  • Pollute the global namespace with methods specific to a model
  • Forces a functional approach within an object oriented domain model

举个例子 app/helpers/posts_helper.rb

module PostsHelper
  def publication_date(post)
    post.created_at.strftime '%Y-%m-%d'
  end
end

app/views/posts/show.html.erb

<span><%= publication_date @post %></span>

上面的都是没问题的,但是如果下面这样

<span><%= publication_date @user %></span>

上面的代码是允许的,但是显然是错误的

他们的建议是使用 Decorators 来处理这些视图中的输出,楼主可以查查,我觉得挺麻烦的。

#2 楼 @teddy_1004 谢谢您的回答,但是我的困惑是 Helpers 对于所有的 View 是可见的,这样作用域会不会太大了,容易有冲突,比如说我在 PagesHelper 和 UsersHelper 中有两个相同名字的 method,这样的话 views 中看到的 method 到底是哪个?

module PagesHelper
  def testpage
    "testpagehelper"
  end
end

module UsersHelper
  def testpage
    "testuserhelper"
  end
end

#3 楼 @wcc526 会冲突,推荐所有 helper 方法加前缀 page_testpage user_testpage

可能是维护者觉得很多 helper 都要跨 Controller 用的,就默认全 include 了。有配置可以关掉。

其实我也觉得默认全部加载很奇怪,和 controller 不对应

现在我很少用具体到 controller 的 helpers,不过记得在 Rails3 里面是不行的。PageHelpers 只能作用到 views/pages,这也符合 Rails 的统一命名。楼主你确定是真的全部可见?

#2 楼 @teddy_1004 我觉得对于这个例子,更典雅的方法是在 Post 的 class 里面 def publication_date

#7 楼 @billy 大概 3.0 前后改的。

我认为这也是一个约定吧 首先,每个 view 都有自己对应的 helper 模块,如果遵守这样的约定,那么 view 使用的 helper 方法就在对应的 helper 模块中查找,这样看起来也比较整洁。 其次,如果 view1 需要使用 view2 中的 helper 方法,那么我也可以直接调用,这样我就可以不用再 view1 的 helper 模块中再次重写此方法了,这样也避免了代码的重复。

#7 楼 @billy #9 楼 @Rei 我也有印象以前是一一对应的,但是到某个版本后,就全部加载了。

@Rei @zgm @wcc526

找到答案了,确实后来默认是全部包括了,就像楼主和 Rei 所说的情况。

By default, each controller will include all helpers. These helpers are only accessible on the controller through .helpers

但是,如果确实想要一一对应,也可以更改 Rails 设置

In previous versions of Rails the controller will include a helper whose name matches that of the controller, e.g., MyController will automatically include MyHelper. To return old behavior set config.action_controller.include_all_helpers to false.

http://api.rubyonrails.org/classes/ActionController/Helpers.html

#12 楼 @billy 👍 厉害,不过 helper 这东西好像招人待见,我也用的少。

@zgm 查个文档而已,谈不上厉害 :) 我也觉得在尽量少用的前提下,helper 放在全局在一些时候还是有意义的,但分开 controller 实在没有必要,容易造成重名污染,就像楼主所说的不知道哪个起了作用。这个改动还是挺好的,强迫所有的 helper 放在同一地方减少污染机会。

#14 楼 @billy 谢谢!虽然 helpers 里的方法是对全局的 views 可见,helper 方法还是需要 include 才能在 controller 中使用,对于这种需要在 controller 和 view 中都要使用的方法,一般的作法是什么?

@wcc526 直接在 controller 里面 include MyHelperModule

#14 楼 @billy 嗯,之前对应的时候,经常为了用一些通用的 helper method,到每个 controller 里面去 include,到最后形成 helper 和 controller 多对多的关系,自己也搞不清哪个是哪个了。现在这样方便不少,避免冲突也只要自己命名的时候稍微注意一点就行。可能 Rails 本身定位于中小型互联网项目的实践,所以尽量考虑这种规模下的方便。

#16 楼 @billy 直接通过view_context调用好像就行了吧

个人也感觉使用 view helper 范围太大了,而且在使用过程中,会发现有时候看到一个 helper 方法,但是一下子找不到对应的文件。后来用 draper这个 gem,用 decorator 取代原来的 helper 方法,这样作用范围就小很多,而且找对应文件的时候也能方便些。感觉比较好的一个 gem

需要 登录 后方可回复, 如果你还没有账号请 注册新账号