当尝试从Rails控制器调用helper方法时出现NoMethodError错误

75

在我的控制器类中尝试访问一个帮助器模块中定义的方法时,我遇到了NoMethodError。我的Rails应用程序使用以下方式的helper类方法和:all符号:

class ApplicationController < ActionController::Base
  helper :all
  .
  .
end

我的理解是,这应该使得所有的控制器类自动包含在app/helpers目录中的所有帮助器模块,因此将所有方法混合到控制器中。这个理解正确吗?

如果我在控制器中明确地include帮助器模块,那么一切都能正常工作。


该控制器是否继承自ApplicationController? - Michael Sepcot
是的。我在使用该方法的两个控制器中遇到了问题,这两个控制器都继承自ApplicationController。 - John Topley
14个回答

133

要使用模板引擎中已经包含的辅助方法:

  • Rails 2:使用@template变量。
  • Rails 3:有一个不错的控制器方法view_context

在控制器方法中调用 'number_to_currency' 的示例用法:

# rails 3 sample
def controller_action
  @price = view_context.number_to_currency( 42.0 ) 
end

# rails 2 sample
def controller_action
  @price = @template.number_to_currency( 42.0 ) 
end

3
这是一堆答案中最好的回答 - 应该置于顶部。 - Obie
8
对于Rails 3,这就是答案。 - Juanin
不提供如何使用 view_context 的解释。 - Sarah Vessels
3
另一个解决方案(适用于Rails版本)是使用:ApplicationController.helpers.number_to_currency( 42.0)。 - gamecreature

51

helper :all使得所有的辅助函数(没错,就是全部)都可以在视图中使用,但并不会将它们包含在控制器中。

如果你希望在控制器和辅助函数之间共享一些代码(虽然这并不是很理想,因为辅助函数是UI代码,而控制器属于控制器代码),可以在控制器中包含该辅助函数,或者创建一个单独的模块,在控制器和辅助函数中都包含该模块。


1
谢谢,很有道理。我有一些代码想要在两个控制器之间共享。我会创建一个新的模块并将其包含进去。 - John Topley
这确实是最好的方法。 - ggomeze
2
这真的是关于两个控制器之间的共享吗?还是控制器和视图之间的共享?我认为是后者。因此,gamecreature的方式(@template,view_context)对我来说是正确的。 - Pascal
我的独特的重定向方法在helpers中。我需要从我的控制器中调用它们。我认为这并不是坏事。 - Victor Pudeyev
2
你说在控制器中包含帮助方法是不可取的,因为UI代码和控制器代码应该分离。但是如果您正在进行过滤操作并且显然需要在控制器和视图中访问params哈希表,并且有时需要调用视图和控制器中的方法来访问params变量。那么在这种情况下你会怎么做? - JohnMerlino

31

如果你需要在控制器和帮助程序/视图之间共享一个方法,你可以在控制器顶部通过'helper_method'进行定义:

class ApplicationController < ActionController::Base
  helper_method :my_shared_method
  ...

  def my_shared_method
    #do stuff
  end
end

希望这能帮到您


2
helper_method :my_shared_method 这一行代码不需要放在“顶部”.. 它可以放在任何地方,我最喜欢它放在定义 (def my_shared_method) 的正上方。 - user664833

29

从控制器中获取辅助方法

获取您的辅助方法的一种方法是直接包含您的辅助文件。

include LoginHelper
cool_login_helper_method(x,y,z)

这将在控制器中引入来自 helper 模块的所有方法。但这并不总是一件好事。为了保持作用域的分离,创建一个对象,赋予它该 helper 的能力,并使用它来调用方法:

login_helper = Object.new.extend(LoginHelper)
login_helper.cool_login_helper_method(x,y,z)

帮助器:全部

helper :all 可以使得所有辅助模块中的辅助方法在所有视图中都可以使用,但它对控制器无效。这是因为辅助方法设计用于视图中并且通常不应该从控制器中访问。在较新版本的Rails中,默认情况下此选项始终对每个控制器启用。


7

5

使用 helpers 方法可能更为简洁:

class FooController < ActionController::Base
  def action
    self.class.helpers.helper_method arg
  end
end

5

我觉得最需要翻译的时候是在编写flash或自定义错误检查器时,有时候在flash消息中使用link_to帮助程序非常方便。我使用以下解决方案将ActionView帮助程序引入控制器。请注意,正如上面提到的那样,这会破坏MVC分离,如果有更好的想法,请告诉我!

在ApplicationController下面添加以下内容:

class Something
  include Singleton
  include ActionView::Helpers::UrlHelper
end

在ApplicationController中添加以下内容:

def foo
  Something.instance
end

最后,在你想要访问辅助函数代码的控制器中:

messages << "<li class='error'>Your have an Error!<%= foo.link_to('Fix This', some_path) %></li>"

希望这能在某种程度上有所帮助!

4

在控制器中,可以使用@template变量访问任何助手。

@template.my_super_helper


3

控制器无法自动访问帮助方法。我们必须将它们包含在应用程序控制器中。

模块ApplicationHelper

 def hello_message
    "Hello World"
 end

最近

ApplicationController类继承自ActionController::Base类

  include ApplicationHelper

  def message
     hello_message
  end

end


2

Helper是用于模板(即视图),而不是控制器。这就是为什么您无法访问该方法。如果您想在两个控制器之间共享一个方法,您必须在ApplicationController中定义它。helper :all表示您在app/helpers目录中定义的任何helper文件中定义的任何方法都将可用于任何模板。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接