Rails:跨几个控制器动作设置一个公共的实例变量 [英] Rails: Set a common instance variable across several controller actions
问题描述
应该如何设置一个通用的实例变量以便在模板中使用,但在运行 之后 。 换句话说,我希望在我的application_controller中工作。 不起作用因为 同样重要的是,在操作之后运行 我的想法都不是很理想: 将所有控制器的特定于案例的代码重构为 子类 有什么想法?谢谢。 几个控制者的index()都做分页,每个参数都是 我会尝试使用Monkeyn修补Fixnum,所以我可以像
class ApplicationController< ActionController :: Base
after_filter:set_something_common
def set_something_common
#所有控制器的操作都查询了数据库并为我设置了@foo ...
@bar = some_calculation_on(@foo)
#...所有模板期望@bar下注设置。
end
end
after_filter
在渲染后运行。精细。但是,什么是正确的模式?
set_something_common
,因为这些操作具体案件;但他们都设置了 @foo
。
set_something_common()
。
case_specific_code()
,并强制它们依次运行:
before_filter:case_specific_code,:set_something_common
application_controller
并重新定义索引
方法。
$ b 编辑:Matthew的回应促使我澄清:
@offset
和 @limit
(通过全局 before_filter
)查看数据切片。大。现在我想要一个通用的方法来计算下一个切片链接的RESTful URL。我被鼓励看到 url_for()
生成一个URL返回到相同的资源,所以我试过:
<$ p $ b $ def set_something_common#真的叫做set_next_url,事实被告知
@next_url = url_for(:offset => @offset + @limit,:limit => @limit)
结束
@ offset.next_url_for(self,@limit)
从模板,但我不知道它是否会工作。想想看,如果我要修改模板,那么我也可以设置一个应用程序帮手。我还不确定最好的解决方案是什么。
更新:接受的答案是使用帮手。
感谢大家的更新。我吸取了教训,像全局变量这样的助手是有原因的,而且当他们明显的有利和简洁的时候,他们不会被避开。
其次,我想要猴子补丁 Fixnum
。我的意思是,也许你做了,但我不知道。至少不是经常的,除非我从中得到一些完全邪恶的语义好处,比如能够说 3.blind_mice
。猴子修补它像这样的随机用例似乎是一个维护头痛的道路。
你提到重构所有控制器的特定的代码到一个之前的过滤器和依次运行它们。这让我想起... @foo
在每种情况下都是一样的吗?如果是这样的话,那么之前的过滤器将工作得很好:
before_filter:do_common_stuff
def do_common_stuff
@foo = common_foo
@bar = do_something_with @foo
end
一个完全合法的方法。但是,如果@foo从控制器更改为控制器...那么你有更多的选择。
你可以将你的过滤器分成两部分,控制器。
$ p $ #application_controller:
before_filter:get_foo,:do_something_common
def do_something_common
@ bar = do_something_with @foo
end
#baz_controller:
def get_foo
@foo = pull_from_mouth
end
#baf_controller :
def get_foo
@foo = pull_from_ear
end
但是你知道,如果这是一个简单的情况,不需要数据库访问或网络访问或类似的东西......你的情况不...不要自杀。不要流汗把它扔进一个帮手。这就是他们在那里,帮助。你基本上只是将一些视图数据重新排列成稍微容易使用的形式。帮手是我的投票。你可以把它命名为 next_url
。 :)
How should one have several different controller' actions set a common instance variable for use in templates but after the action runs.
In other words, I want this to work in my application_controller.
class ApplicationController < ActionController::Base
after_filter :set_something_common
def set_something_common
# All controllers' actions have queried the DB and set @foo for me...
@bar = some_calculation_on(@foo)
# ... and all templates expect @bar to bet set.
end
end
This does not work because after_filter
runs after rendering. Fine. But what is the correct pattern?
Again, it is important that set_something_common
runs after the action because those actions do case-specific things; but they all set @foo
.
None of my ideas seem ideal:
- Call
set_something_common()
towards the bottom of every action that needs it. Refactor all controllers' case-specific code into
case_specific_code()
and force them to run in order:before_filter :case_specific_code, :set_something_common
Subclass
application_controller
and redefine theindex
method.
Any thoughts? Thanks.
Edit: Matthew's response prompted me to clarify:
Several controlers' index() all do pagination, each taking parameters @offset
and @limit
(via a global before_filter
) to view data slices. Great. Now I want a common method to compute a RESTful URL for the "next slice" link. I was encouraged to see that url_for()
generates a URL returning to the same resource, so I tried:
def set_something_common # really called set_next_url, truth be told
@next_url = url_for(:offset => @offset + @limit, :limit => @limit)
end
I will try monkey patching Fixnum, so I can do something like @offset.next_url_for(self, @limit)
from the template, but I'm not sure if it will work. Come to think of it, if I am going to modify the templates, then I may as well set up an application helper. I'm still not sure what the best solution is.
Update: Accepted answer is "use a helper."
Thanks for the updates from everybody. I learned my lesson that helpers, like global variables, are there for a reason and not to be eschewed when they are plainly beneficial and succinct.
Firstly, you don't want to try to insert code "between" a controller action and a template rendering. Why? Because you want the controller action to have the freedom to choose what sort of response to give. It could return XML, JSON, headers only, a redirection, nothing, etc. That's why after filters are executed after the response has been rendered.
Secondly, you don't want to monkey patch Fixnum
. I mean, maybe you do, but I don't. Not often at least, and not unless I get some totally wicked semantic benefits from it, like being able to say 3.blind_mice
. Monkey patching it for a random use case like this seems like a maintenance headache down the road.
You mention refactoring out all the controllers' case specific code into a before filter and running them sequentially. Which brings up to my mind... @foo
is the same in every case? If that's the case, then one before filter would work just fine:
before_filter :do_common_stuff
def do_common_stuff
@foo = common_foo
@bar = do_something_with @foo
end
That's a totally legit approach. But if @foo changes from controller to controller... well, you have a few more options.
You can separate your before filters into two halves, and customize one per controller.
# application_controller:
before_filter :get_foo, :do_something_common
def do_something_common
@bar = do_something_with @foo
end
# baz_controller:
def get_foo
@foo = pull_from_mouth
end
#baf_controller:
def get_foo
@foo = pull_from_ear
end
But you know, if it's a simple case that doesn't need database access or network access or anything like that... which your case doesn't... don't kill yourself. And don't sweat it. Throw it in a helper. That's what they're there for, to help. You're basically just rearranging some view data into a form slightly easier to use anyway. A helper is my vote. And you can just name it next_url
. :)
这篇关于Rails:跨几个控制器动作设置一个公共的实例变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!