我的问题是关于使用实例变量的控制器方法(可能包含在外部类中)。我经常在控制器中使用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,而不是将其作为参数。在你的圣人看来,这是一个糟糕的编码习惯吗?还是我是偏执狂?
假设这是一个问题,我会看到两种处理它的一般方法:
检查实例var和bail,除非它已设置:
def do_something_to_document
raise "no doc!" unless @document
[...]
end
使用实例var作为参数调用操作:
def do_something_to_document(document)
[...]
end
2看起来更好,因为它隐藏了调用对象的上下文。但do_something_to_doc只能由已经设置@document的控制器调用,并且将@document作为方法参数会产生对象创建的开销。 (对吧?)1似乎很苛刻,但应该涵盖所有案例。
我倾向于选择1(假设我对性能问题是正确的),即使看到引用神秘实例变量的方法列表也会给我带来荨麻疹。思考?如果我能更清楚,请告诉我。 (当然,如果在某处我没有看到它,我只是指出了正确的方向......)
谢谢, -Erik
答案 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