RoR:控制器方法中的实例变量

时间:2012-03-21 19:39:19

标签: ruby-on-rails coding-style

我的问题是关于使用实例变量的控制器方法(可能包含在外部类中)。我经常在控制器中使用before_filter来设置某些变量,例如:

class DocumentController < ApplicationController
  before_filter :fetch_document

  def action
    @document.do_something
  end

  private

  def fetch_document
    @document = Document.find(params[:id])
  end
end

我一直致力于一个项目,其中一些控制器将共享一些功能,比如文档编辑。我的第一个想法是提取相关的方法,并从application_controller.rb或单独的模块中获取它们。但后来我发现我正在编写看起来像这样的代码:

  def fetch_document
    @document = Document.find(params[:id])
  end

  def do_something_to_document
    @document.do_something
  end

这引发了警告:do_something_to_document基本上假定存在@document,而不是将其作为参数。在你的圣人看来,这是一个糟糕的编码习惯吗?还是我是偏执狂?

假设这是一个问题,我会看到两种处理它的一般方法:

  1. 检查实例var和bail,除非它已设置:

    def do_something_to_document
      raise "no doc!" unless @document
      [...]
    end
    
  2. 使用实例var作为参数调用操作:

    def do_something_to_document(document)
      [...]
    end
    
  3. 2看起来更好,因为它隐藏了调用对象的上下文。但do_something_to_doc只能由已经设置@document的控制器调用,并且将@document作为方法参数会产生对象创建的开销。 (对吧?)1似乎很苛刻,但应该涵盖所有案例。

    我倾向于选择1(假设我对性能问题是正确的),即使看到引用神秘实例变量的方法列表也会给我带来荨麻疹。思考?如果我能更清楚,请告诉我。 (当然,如果在某处我没有看到它,我只是指出了正确的方向......)

    谢谢, -Erik

2 个答案:

答案 0 :(得分:0)

由于@variable是会话/实例变量,您将在 do_something_to_document 方法中获得Nil异常。

第一个代码很好,因为 before_filter 将始终加载您的@document。

我建议你写点那样的东西

def fetch_document(doc_id)
  @document ||= Document.find(doc_id)
end

def do_something_to_document
  my_doc = fetch_document(params[:id])
end

其中 do_something_to_document 在控制器中(如果没有,请不要使用params [:id],即使您知道可以访问此全局,也请使用另一个显式参数)。 || = thing,将确保您只通过请求调用一次。

答案 1 :(得分:0)

如果你真的需要不同控制器中的文档,我会做这样的事情:

class ApplicationController < ActionController::Base
  private
  def document
    @document ||= Document.find(params[:document_id])
  end
end

class FooController < ApplicationController
  before_filter :ensure_document, :only => [:foo]

  def foo
    document.do_something
  end

  private
  # TODO: not sure if controller_name/action_name still exists
  def ensure_document
    raise "#{controller_name}##{action_name} needs a document" unless document
  end
end