Rails 2 - partials: what does #comment = Comment.new mean? - ruby-on-rails

I am working through a tutorial with the following code:
<h3>New Comment</h3>
<%= render :partial => #comment = Comment.new,
:locals => { :button_name => "Create" } %>
I believe that 'render :partial => #comment' works like 'render :partial => "comment", :object => #comment'
Where does ' = Comment.new' fit in?
Is it shorthand for :object?
Alan

In Ruby terms,
#obj = Object.new # returns #obj
So you're rendering a comment partial and creating a new comment object that it can work with at the same time.

See http://apidock.com/rails/ActionView/Partials section "Rendering objects with the RecordIdentifier":
# <%= render :partial => "accounts/account", :locals => { :account => #buyer } %>
<%= render :partial => #account %>
Though documented, this is hardly used. The new+assignation (as explained by aharon) works, but it seems a bit tricky. In a tutorial you would expect to find a more orthodox approach:
Create objects in controllers not in views.
Use render :partial => 'mypartial', :locals => {...}

Related

Passing local variable into partial returns NameError

I am trying to pass the index of something into a partial and am getting a NameError.
Right now, this is my render statement and I am able to access builder just fine.
<%= render 'my_partial', :builder => form_helper %>
But when adding index like below, I get the error.
<%= render 'my_partial', :builder => form_helper, :locals => {:index => index } %>
Any thoughts?
Thanks!
edit:
While trying
<%= render :partial => 'my_partial', :locals => {:builder => form_helper, :index => index } %>
The specific error is "undefined local variable or method `index' for #<#:0x007fc37206ae40>"
Either:
<%= render 'my_partial', :builder => form_helper, :index => index %>
Or:
<%= render :partial => 'my_partial', :locals => {:index => index, :builder => form_helper } %>

Rails render a partial with collection twice?

I have this:
<%= render :partial => "rewards", :collection => #rewards, :as => :reward %>
when I count the items in the collection with <%= #rewards.count %>, it shows 1, and I check ed the db that there is only one reward. However, the partial is rendered twice in my master view, with the second one empty (reward == nil). Any clue on this?
Updates:
Found the reason, before this render statement, there is a user.rewards.build statement for creating a form:
<%= render :partial => "form_reward", :locals => {:user => #user, :reward => #user.rewards.build } %>
<%= render :partial => "rewards", :collection => #rewards, :as => :reward, :locals => {:user => #user } %>
somehow the partial rendered this object also! I guess this is because name pollution. Now how to overcome this problem then?
<%= render :partial => 'rewards', :object => #rewards, :as => :reward %>
You should be able to access it as reward to test try this:
<%= reward.inspect %>
Ohh and of cause if it should be repeatet you should pass it by as a :collection instead of :object like its in my example
I would suggest you to check the query where the #rewards is been populated. It seems like there are two objects in the #reward collection one Reward object and a nil object.
You may use the compact method of the collection to remove the nil object.

Trouble on rendering a template passing a local variable

I am running Ruby on Rails 3 and I would like to render a template (show.html.erb) passing a local variable.
In RAILS_ROOT/views/users/show.html.erb I have
Name: <%= #user.name %>
Surname: <%= #user.surname %>
I have also a page controller to handle pages and in the application_controller.rb an istance of #current_user. A page is called user, so in RAILS_ROOT/views/pages/user.html.erb I have
<%= render :template => "users/show", :locals => { :user => #current_user } %>
The above code doesn't work (I get this error: RuntimeError in Pages#user, Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id) but this works:
<%= render :template => "users/show", :locals => { :user => #user = #current_user } %>
I think it is not a good approach to "overwrite" the #user variable. This is because, for example, if I need to recall #user after the above 'render' statement it will don't work anymore.
So, what is a solution in order to render show.html.erb?
I tryed also
<%= render :template => "users/show", :locals => { #user => #current_user } %>
<%= render :template => "users/show", :locals => { :object => #current_user, :as => #user }
but those don't work.
UPDATE
If in pages_controller.rb I put this
def user
#user ||= #current_user
end
it will work and in the view files you can just use
<%= render :template => "users/show" %>
Anyway, I discoverd that I have this error (see below for more info):
ActionController::RoutingError in Pages#user
No route matches {:action=>"destroy", :controller=>"users"}
The error is generated from this form statement located in a partial loaded from show.html.erb:
<%= form_for(#user, :url => user_path) do |f| %>
...
<% end %>
:locals => { :user => #current_user }
and in template
Name: <%= user.name %>
Local variables are local, so you don't need # to refer them.
#user502052
You can render view explicitly from your controller.
render :template => "users/show", :locals => {...}
When you don't execute render in controller, framework does that for you with default parameters. When you do, you can specify different template file, pass local variables, render a partial: anything render function supports.
Just in case you are NOT rendering a partial, and do not want to use :template option, this can also be done in Rails 4 with:
render 'users/show', {user: #current_user}
Url:
http://localhost/pages/user
this will call the user method on pages_controller. You have this:
def user
#user ||= #current_user
end
Rails creates an instance variable #users and by default will try to render a view template at app/views/pages/user.html.erb. If that is not what you want, you have to say so in the controller:
def user
#user ||= #current_user
render :template => "users/show", :locals => { :user => #current_user }
end
This will now render app/views/users/show.html.erb with a local variable called user instead of the default app/views/pages/user.html.erb.
Currently you are waiting until you are inside a view template and then asking to render another view template. Once you are in a view template you should only need to render partial templates:
render :partial => 'users/show', :locals => {:user => #current_user}
Hopefully that helps clarify.

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

Using partial to render a complete view

I have a simple partial to show some topics from the associated community
<%= render :partial => 'shared/topic', :collection => #community.topics %>
I'm trying to make a mobile version of the site, and to not render the partial to the same view, but to a new view.
I tried something like this
def topicsCommunity
fetch_topics ["community_id = ?", #community.id]
render :action => 'index'
end
But I can't get the community.id from my community view.
Also tried this :
#topicscommunity = #community.topics.find(:all,
:conditions => {:community_id => #community.id})
But from the topics_Controller, it didn't work.
Thanks for the help.
You don't have to use render :partial => ... in views only. You can easily do it in your controller (instead of render :action => ... or whatever).
So, just put this in the end of your controller
render :partial => 'shared/topic', :collection => #community.topics
There's no fundamental difference between calling render with :action, :partial, :text, :template or any other hash key.
If you just want to render the same template, use:
def topicsCommunity
fetch_skills ["community_id = ?", #community.id]
render 'index'
end

Resources