Rails:跨几个控制器动作设置一个公共的实例变量 [英] Rails: Set a common instance variable across several controller actions

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

问题描述

应该如何设置一个通用的实例变量以便在模板中使用,但在运行 之后

换句话说,我希望在我的application_controller中工作。

  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的回应促使我澄清:



    几个控制者的index()都做分页,每个参数都是 @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)
    结束

    我会尝试使用Monkeyn修补Fixnum,所以我可以像 @ offset.next_url_for(self,@limit)从模板,但我不知道它是否会工作。想想看,如果我要修改模板,那么我也可以设置一个应用程序帮手。我还不确定最好的解决方案是什么。



    更新:接受的答案是使用帮手。



    感谢大家的更新。我吸取了教训,像全局变量这样的助手是有原因的,而且当他们明显的有利和简洁的时候,他们不会被避开。

    首先,你不想尝试在控制器动作和模板渲染之间插入代码。为什么?因为你希望控制器的行动有自由选择给予什么样的回应。它可以返回XML,JSON,头只,重定向,没有,等等。这就是为什么在响应被呈现后执行过滤器。

    其次,我想要猴子补丁 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 the index 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屋!

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