Rails:跨多个控制器操作设置公共或全局实例变量 [英] Rails: Set a common or global instance variable across several controller actions

查看:87
本文介绍了Rails:跨多个控制器操作设置公共或全局实例变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

应该如何让几个不同的控制器操作设置一个公共实例变量用于模板,但要在操作运行后 .

How should one have several different controller' actions set a common instance variable for use in templates but after the action runs.

换句话说,我希望它可以在我的application_controller中工作.

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

不起作用,因为after_filter在渲染后运行.美好的.但是正确的模式是什么?

This does not work because after_filter runs after rendering. Fine. But what is the correct pattern?

同样,set_something_common在操作之后运行很重要,因为这些操作会执行特定于案例的事情.但它们都设置了@foo.

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:

  • 在需要执行每个操作的底部调用set_something_common().
  • 将所有控制器的特定于案例的代码重构为case_specific_code(),并强制它们按顺序运行:

  • 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

  • 子类application_controller,并重新定义index方法.

  • Subclass application_controller and redefine the index method.

    有什么想法吗?谢谢.

    几个控制者的index()都进行分页,每个都使用参数@offset@limit(通过全局before_filter)来查看数据切片.伟大的.现在,我想要一种通用方法来为下一个切片"链接计算一个RESTful URL.鼓励我看到url_for()会生成一个返回相同资源的URL,所以我尝试了:

    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
    

    我将尝试对Fixnum进行猴子修补,因此我可以从模板中执行类似@offset.next_url_for(self, @limit)的操作,但是我不确定它是否可以工作.想一想,如果我要修改模板,那么我不妨设置一个应用程序助手.我仍然不确定最佳解决方案是什么.

    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.

    感谢大家的更新.我吸取了教训,像全局变量一样,辅助对象之所以存在是有原因的,当它们明显有益且简洁时,就不要回避.

    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.

    推荐答案

    首先,您不想尝试在控制器动作和模板渲染之间插入代码.为什么?因为您希望控制器动作可以自由选择要给出哪种响应.它可以返回XML,JSON,仅标头,重定向,什么都没有等.这就是为什么在呈现响应之后执行过滤器之后的原因.

    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.

    第二,您不希望猴子补丁Fixnum.我的意思是,也许可以,但是我不可以.至少不经常,而且除非我从中获得了一些完全邪恶的语义好处,例如能够说3.blind_mice,否则它不会.猴子为这样的随机用例打补丁,这似乎是日后的维护难题.

    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.

    您提到将所有控制器的案例特定代码重构为before过滤器,并按顺序运行它们.哪个让我想到... @foo在每种情况下都是一样的?如果是这种情况,那么前置过滤器就可以正常工作:

    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
    

    那是完全合法的方法.但是,如果@foo从控制器更改为控制器...那么,您还有更多选择.

    That's a totally legit approach. But if @foo changes from controller to controller... well, you have a few more options.

    您可以将before过滤器分为两半,并为每个控制器自定义一个.

    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
    

    但是,您知道,如果这是一个简单的案例,不需要数据库访问或网络访问,或者诸如此类的事情……您的案例不需要……别自杀.而且不要流汗.扔在一个帮手.这就是他们在那里寻求帮助的地方.基本上,您只是将一些视图数据重新排列成稍微易于使用的表单.帮手是我的选票.您可以将其命名为next_url. :)

    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屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆