简体   繁体   中英

Why do we need to pass :object to partials?

I have a model Category has_many :subcategories

I am using code to populate value of subcategories drop down according to value of categories drop down in a view using Ajax. Here is the code:

_form.html.erb

<%= f.select :category_id, @categories, {}, :tab_index => 4, :onchange => "#{remote_function(:url  => {:action => "populate_subcategories"},
                                                   :with => "'category_id='+value")}" %>
<div id = "subcategories_div">
  <%= render :partial => "subcategories", :object => @subcategories %>
</div>

deals_controller.rb

def new
  @deal = Deal.new
  @categories = Category.all.map { |category| [category.name, category.id]}
  @subcategories = @categories.first.subcategories.map { |subcategory| [subcategory.name, subcategory.id] }
end

def populate_subcategories
  subcategories = Subcategory.where(:category_id => params[:category_id]).map { |subcategory| [subcategory.name, subcategory.id] }

  render :update do |page|
    page.replace_html 'subcategories_div', :partial => 'subcatgories', :object => subcategories
  end
end

and finally _subcategories.html.erb

<%= f.select :subcategory_id, subcategories, {}, :tab_index => 5 %>

My question is, in the code page.replace_html 'subcategories_div', :partial => 'subcatgories', :object => subcategories why are we defining subcategories as local variable and passing it as an object to the partial? We could have written like this

def populate_subcategories
  @subcategories = Subcategory.where(:category_id => params[:category_id]).map { |subcategory| [subcategory.name, subcategory.id] }

  render :update do |page|
    page.replace_html 'subcategories_div', :partial => 'subcategories'
  end
end

use @subcategories as the instance variable so that it is available in the partial as in the case of normal views in Rails.

Also in the _subcategories.html.erb

<%= f.select :subcategory_id, @subcategories, {}, :tab_index => 5 %>

and in _form.html.erb

<div id = "subcategories_div">
  <%= render :partial => "subcategories" %>
</div>

Why is first method preferred over the second one? Is it because we have only one variable to pass to the partial? Is there any performance improvement for first method?

The reason is that you want your partials to be code-independent from your views. By using @subcategories you create a dependency between your partial and your view that is unnecessary. It means that to use that same partial again you must ensure that you have @subcategories defined, and that might not be the case. For example, you might only have @my_subcategories, or @filtered_subcategories defined. Even worse, you might have @subcategories and @filtered_subcategories and you might want to display both using the same partial. In this case it's better to be able to pass your subcategories to the partial instead of depending on instance variables being set. That way your partials are really modular and conform to the object oriented principle of encapsulation.

For example:

<h1><%= My Subcategories %></h1>
render :partial => 'subcatgories', :object => @my_subcategories
<h1><%= Other Subcategories %></h1>
render :partial => 'subcatgories', :object => @other_subcategories

you can gracefully name your ivars in partials,

render 'subcatgories', :subcategories => @hashtags

or

render 'subcatgories', :subcategories => @legals

then you can use subcategories in your partial, using ivar as like its name pretends to be

go and see ActionView::Rendering#render

there is longer params form to achieve the same behavior ... ( :partial => 'subcatgories', :locals => {:subcategories => @hashtags} )

I believe :subcategories => @hashtags has superior readability over :object => @hashtags

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM