尝试从Rails控制器调用辅助方法时出现NoMethodError


75

NoMethodError尝试从我的一个控制器类访问在我的帮助器模块之一中定义的方法时遇到错误。我的Rails应用程序使用helper带有:all符号的class方法,如下所示:

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

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

如果我include在控制器中明确地建立了辅助模块,那么一切都会正常工作。


有问题的控制器是否继承自ApplicationController?
Michael Sepcot 09年

是。我在使用有问题的方法的两个控制器中都遇到问题,并且两个控制器都从ApplicationController继承。
约翰·托普利

Answers:


50

helper :all 使所有助手(是的,全部)在视图中可用,但不将其包括在控制器中。

如果您希望在辅助程序和控制器之间共享一些代码,这不是很理想,因为辅助程序是UI代码,而控制器则是控制器代码,则可以在控制器中包含辅助程序,也可以创建单独的模块并将其包含在控制器中控制器和助手也是如此。


1
谢谢,这很有意义。我有一些要在两个控制器之间共享的代码。我将创建一个新模块并将其包括在内。
约翰·托普利2009年

这确实是最好的方法
ggomeze

2
这真的是关于两个控制器之间的共享吗?还是在控制器和视图之间?我认为是后者。所以gamecreature的方式(@template,view_context)在我看来是正确的。
帕斯卡

我时髦的重定向方法在助手中。我需要我的控制器提供它们。我不认为这很糟糕。
维克多·普德耶夫

2
您说不希望在控制器中包含辅助方法,因为UI代码和控制器代码应该分开。但是,如果您正在执行过滤并且显然需要访问控制器和视图中的params哈希,并且有时您需要在视图和控制器中调用方法以访问params变量,该怎么办?那么在这种情况下您会怎么做?
JohnMerlino

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 2012年

8
对于Rails 3.这是答案。
胡安

没有说明如何使用view_context
萨拉·

3
另一个解决方案(在两个rails版本中都适用)是使用:ApplicationController.helpers.number_to_currency(42.0)
gamecreature 2012年

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)

这会将来自该帮助程序模块的所有方法带入控制器的作用域。这并不总是一件好事。要使范围分开,请创建一个对象,使其具有该助手的功能,然后使用它来调用方法:

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

帮手:全部

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



5

我发现最需要此时间的时间是编写闪存或自定义错误检查器。在某些情况下,最好在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

结束


2

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



1

如果将application_controller.rb文件更改为此...

class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception
  include SessionsHelper
end

...那么所有助手将对所有控制器可用。


0

如果app/helpers文件夹中仅包含ApplicationHelper ,则必须使用将该文件加载到控制器中include ApplicationHelper。默认情况下,Rails仅加载与控制器同名的帮助程序模块。(例如ArticlesController将加载ArticlesHelper)。如果您有许多模型(例如,文章,帖子,类别),则必须在控制器中上载每个模型。文档

帮手

module PostsHelper
    def find_category(number)
        return 'kayak-#{number}'
    end
    def find_other_sport(number)
        "basketball" #specifying 'return' is optional in ruby
    end
end

module ApplicationHelper
    def check_this_sentence
        'hello world'
    end

end

控制器实例

class ArticlesController < ApplicationController
    include ApplicationHelper
    include PostsHelper
    #...and so on...

  def show#rails 4.1.5
    #here I'm using the helper from PostsHelper to use in a Breadcrumb for the view
    add_breadcrumb find_other_sport(@articles.type_activite), articles_path, :title => "Back to the Index"
    #add_breadcrumb is from a gem ... 
    respond_with(@articles)
  end
end

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.