在Rails中从控制器调用Helper方法时出现“undefined method”错误

45

有人知道为什么我会收到以下错误信息吗?

undefined method `my_method' for #<MyController:0x1043a7410>

当我在我的ApplicationController子类内调用my_method("string")时会发生什么?我的控制器看起来是这样的:

class MyController < ApplicationController
  def show
    @value = my_method(params[:string])
  end
end

还有我的助手

module ApplicationHelper
  def my_method(string)
    return string
  end
end

最后是ApplicationController

class ApplicationController < ActionController::Base
  after_filter :set_content_type
  helper :all
  helper_method :current_user_session, :current_user
  filter_parameter_logging :password
  protect_from_forgery # See ActionController::RequestForgeryProtection for details

可能是重复的问题:在Rails控制器中尝试调用帮助程序方法时出现NoMethodError错误 - Marc-André Lafortune
12个回答

62

在控制器中不能调用帮助程序。如果需要在多个控制器中使用,最好的方法是在 ApplicationController 中创建该方法。

编辑:要明确的是,我认为很多混淆(如果我错了,请纠正)源于 helper: all 调用。实际上, helper: all 仅包括所有助手程序,以便在视图端下任何控制器中使用。在Rails的早期版本中,助手名称空间确定哪些控制器视图可以使用助手程序。

我希望这可以帮助你。


好的信息。实际上,我为我的方法创建了一个模块,正如以下线程所提倡的那样,因为该方法非常通用(它将字符串转换为URL安全格式),不应该只属于控制器:https://dev59.com/nnVC5IYBdhLWcg3w-mVO#130821 - Chad Johnson
这是一个很好的答案,但我想进一步扩展一下。当在控制器中使用helper_method时,会将存在于控制器中的方法添加到相应的helper中。例如,在Application Controller中的方法将被添加到ApplicationHelper中。反之则不行。 - engineerDave

34

在共享模块中定义方法是一个不错的选择,因为辅助函数会自动包含在Rails视图中。 - Tomislav Mikulin
它应该被标记为正确答案,因为这将带来问题的解决方案。但是像@theIV所做的那样提供一些解释也会有所帮助。 :-) - fro_oo

30

像这样在application_controller.rb文件中包含ApplicationHelper:

class ApplicationController < ActionController::Base
  protect_from_forgery       
  include ApplicationHelper  
end

这种方式可以让application_helper.rb文件中定义的所有方法在控制器中使用。

您还可以在单个控制器中包含单个助手。


哇,如果有人想在其他控制器或视图中使用ApplicationHelper方法,只需添加include ApplicationHelper即可运行。 - Nikhil Thombare

7
也许我错了,但是助手不仅适用于视图吗?通常,如果您需要在控制器中使用函数,则将其放入ApplicationController中,因为那里的每个函数都可以在其子类中使用。

哎,那很糟糕。我希望我能在控制器和视图中都使用方法。唉。 - Chad Johnson
你可以,有点像... 你的 helper_method 调用为你在视图中访问这些方法提供了便利。 - theIV
我有一个帮助程序,必须在视图和控制器中使用,用于递归树渲染json,但我不能在控制器中使用它? - Vedmant

6

gamecreature此篇帖子中所说:

  • 在Rails 2中使用@template变量。
  • 在Rails 3中使用控制器方法view_context

4

Helpers(辅助函数)是为视图服务的,但是在ApplicationController.rb中添加一行代码来包含那个helper文件可以解决你的问题。在你的情况下,在ApplicationController.rb中插入以下行:

include ApplicationHelper

3

尝试在您的辅助模块中追加 module_function(*instance_methods),之后您可以直接在该模块本身上调用这些方法。


3
据我所知,helper :all 会使得helpers在视图中可用...

1
虽然在控制器中调用帮助程序并不是一个好的实践,因为帮助程序应该在视图中使用。在控制器中使用帮助程序的最佳方法是在application_controller中创建一个帮助程序方法,并将其调用到控制器中。但即使需要在控制器中调用帮助程序,也只需在控制器中包含该帮助程序即可。
class ControllerName < ApplicationController
  include HelperName
  ...callback statements..

并直接调用辅助方法到控制器中
 module OffersHelper
  def generate_qr_code(text)
    require 'barby'
    require 'barby/barcode'
    require 'barby/barcode/qr_code'
    require 'barby/outputter/png_outputter'
    barcode = Barby::QrCode.new(text, level: :q, size: 5)
    base64_output = Base64.encode64(barcode.to_png({ xdim: 5 }))
    "data:image/png;base64,#{base64_output}"
  end

控制器
class ControllerName < ApplicationController
include OffersHelper

def new
  generate_qr_code('Example Text')
end
end

希望这有所帮助!

0

我曾经遇到过同样的问题...

你可以通过一些hack/bodge方法解决它,将那个逻辑放入一个模型中,或者专门为此创建一个类。与那些讨厌的帮助方法不同,模型对控制器是可访问的。

这是我的 "rag.rb" 模型

class Rag < ActiveRecord::Base
  belongs_to :report
  def miaow()
    cat = "catattack"
  end  
end

这是我的“rags_controller.rb”控制器的一部分。
def update
  @rag = Rag.find(params[:id])
  puts @rag.miaow()
  ...

我点击“更新”后,终端出现了一个猫的攻击。

在实例化后,可以调用模型中的方法。将catattack替换为一些代码。(这是我目前最好的)

:helper all仅打开视图助手。

这展示了如何创建一个类并调用它。 http://railscasts.com/episodes/101-refactoring-out-helper-object?autoplay=true


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