【问题标题】:NoMethodError when trying to invoke helper method from Rails controller尝试从 Rails 控制器调用辅助方法时出现 NoMethodError
【发布时间】:2010-10-02 00:16:34
【问题描述】:

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

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

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

如果我明确地include 控制器中的辅助模块,那么一切正常。

【问题讨论】:

  • 有问题的控制器是否继承自 ApplicationController?
  • 是的。我在使用相关方法的两个控制器中遇到问题,并且两个控制器都继承自 ApplicationController。

标签: ruby-on-rails ruby


【解决方案1】:

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

  • 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

【讨论】:

  • 这是最好的答案 - 应该在顶部
  • 对于 Rails 3。这就是答案。
  • 没有解释如何使用view_context
  • 另一种解决方案(适用于两个 Rails 版本)是使用:ApplicationController.helpers.number_to_currency(42.0)
【解决方案2】:

helper :all 使视图中的所有助手(是的,所有助手)都可用,它不将它们包含在控制器中。

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

【讨论】:

  • 谢谢,有道理。我有一些我想在两个控制器之间共享的代码。我将创建一个新模块并将其包含在内。
  • 这确实是最好的方法
  • 真的是两个控制器之间的共享吗?还是在控制器和视图之间?我认为是后者。所以 gamecreature 的方式(@template,view_context)对我来说看起来是正确的。
  • 我时髦的重定向方法在助手中。我需要来自我的控制器的它们。我不认为这很糟糕。
  • 您说在控制器中包含辅助方法是不可取的,因为 UI 代码和控制器代码应该是分开的。但是如果你在做过滤,你显然需要访问控制器和视图中的参数哈希,有时你需要调用视图和控制器中的方法来访问参数变量。那么在这种情况下你会怎么做呢?
【解决方案3】:

如果您需要在控制器和助手/视图之间共享方法,您可以通过控制器顶部的“helper_method”进行定义:

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

  def my_shared_method
    #do stuff
  end
end

希望对你有帮助

【讨论】:

  • helper_method :my_shared_methodnot 需要在“顶部”.. 它可以去任何地方,我最喜欢它在定义上方 (def my_shared_method )。
【解决方案4】:

来自控制器的帮助方法

获得帮助方法的一种方法是简单地包含您的帮助文件。

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】:

    对于 Rails 3,在控制器中使用 view_context 方法:

    def foo
      view_context.helper_method
      ...
    

    这是一个例子:http://www.christopherirish.com/2011/10/13/no-view_context-in-rails-3-1-changes/

    【讨论】:

      【解决方案6】:

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

      希望在某些方面有所帮助!

      【讨论】:

        【解决方案7】:

        使用helpers 方法可能更简洁:

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

        【讨论】:

          【解决方案8】:

          可以使用控制器中的@template 变量访问任何帮助器。

          @template.my_super_helper

          【讨论】:

            【解决方案9】:

            控制器不能自动访问辅助方法。我们必须将它们包含在应用控制器中。

            模块应用程序助手

             def hello_message
                "Hello World"
             end
            

            结束

            类 ApplicationController

              include ApplicationHelper
            
              def message
                 hello_message
              end
            

            结束

            【讨论】:

              【解决方案10】:

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

              【讨论】:

                【解决方案11】:

                有两种方法可以做到这一点:创建模块或使用@template 变量。查看此以获取更多详细信息 http://www.shanison.com/?p=305

                【讨论】:

                  【解决方案12】:

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

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

                  ...那么所有控制器都可以使用所有助手。

                  【讨论】:

                    【解决方案13】:

                    如果您的 app/helpers 文件夹中只有 ApplicationHelper,则必须使用 include ApplicationHelper 将其加载到控制器中。默认情况下,Rails 只加载与控制器同名的辅助模块。 (例如,ArticlesController 将加载 ArticlesHelper)。如果您有许多模型(例如文章;帖子;类别),则必须在控制器中上传每个模型。 the docs

                    助手

                    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
                    

                    【讨论】:

                      【解决方案14】:

                      请在 ApplicationController 中尝试include SessionsHelper

                      class ApplicationController < ActionController::Base
                        include SessionsHelper
                        ...
                      end
                      

                      【讨论】:

                        猜你喜欢
                        • 2012-02-13
                        • 2011-01-24
                        • 1970-01-01
                        • 2023-03-14
                        • 2011-08-03
                        • 1970-01-01
                        • 1970-01-01
                        • 2013-03-06
                        • 2011-02-19
                        相关资源
                        最近更新 更多