Rails: Set a common or global instance variable across several controller actions

前端 未结 4 1176
萌比男神i
萌比男神i 2020-12-14 03:02

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

相关标签:
4条回答
  • 2020-12-14 03:16

    I would have a method on @foo which returns a bar, that way you can use @foo.bar in your views.

    <% @bar = @foo.bar %> #if you really don't want to change your views, but you didn't hear this from me :)

    0 讨论(0)
  • 2020-12-14 03:19

    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. :)

    0 讨论(0)
  • 2020-12-14 03:19

    Use <%= do_some_calculations(@foo) %> inside your templates. That is the straight way.

    0 讨论(0)
  • 2020-12-14 03:38

    I had this challenge when working on a Rails 6 application.

    I wanted to use an instance variable in a partial (app/views/shared/_header.html.erb) that was defined in a different controller (app/controllers/categories_controller.rb).

    The instance variable that I wanted to use is @categories which is defined as:

    # app/controllers/categories_controller.rb
    
    class CategoriesController < ApplicationController
    
      def index
        @categories = Category.all
      end
      .
      .
      .
    end
    

    Here's how I did it:

    Firstly, I defined a helper_method for the instance variable in my app/controllers/application_controller.rb file:

    class ApplicationController < ActionController::Base
      helper_method :categories
    
      def categories
        @categories = Category.all
      end
    end
    

    This made the @categories instance variable globally available as categories to every controller action and views:

    Next,I rendered the app/views/shared/_header.html.erb partial in the app/views/layouts/application.html.erb this way:

    <%= render partial: '/shared/header' %>
    

    This also makes the @categories instance variable globally available as categories become available to every controller views that will use the partial without the need to define the @categories instance variable in the respective controllers of the views.

    So I used the @categories instance variable globally available as categories in the partial this way:

    # app/views/shared/_header.html.erb
    
    <% categories.each do |category| %>
      <%= link_to category do %>
        <%= category.name %>
      <% end %>
    <% end %>
    

    Note: You can use locals to pass in the variables into the partials:

    <%= render partial: '/shared/header', locals: { categories: @categories } %>
    

    However, this will require a controller action that sets a @categories instance variable for every controller views that will use the partial.

    You can read up more about Helpers and Helper Methods in the Rails Official Documentation: https://api.rubyonrails.org/classes/AbstractController/Helpers/ClassMethods.html

    That's all.

    I hope this helps

    0 讨论(0)
提交回复
热议问题