Rails render a partial with collection twice? - ruby-on-rails

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.

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 } %>

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

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

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 => {...}

How can I dynamically call the named route in a :partial in rails?

I have the following partial. It can be called from three different times in a view as follows:
<%= render :partial => "contact_event",
:collection => #contacts,
:locals => {:event => email} %>
Second time:
<%= render :partial => "contact_event",
:collection => #contacts,
:locals => {:event => call} %>
Third time:
<%= render :partial => "contact_event",
:collection => #contacts,
:locals => {:event => letter} %>
In each instance, call, email, letter refer to a specific instance of a Model Call, Email, or Letter.
Here is what I tried to do and conceptually what I'd like to do: assign the route based on the class name that has been passed to the :event from the :partial.
What I did was create what the actual url should be. The 'text' of it is correct, but doesn't seem to recognize it as a named route.
<!-- provide a link to skip this item -->
<% url = "skip_contact_#{event.class.name.tableize.singularize}_url" %>
<%= link_to_remote "Skip #{url} Remote",
:url => send("#{url}(contact_event, event)")
:update => "update-area-#{contact_event.id}-#{event.id}" %>
<span id='update-area-<%="#{contact_event.id}-#{event.id}"%>'> </span>
The result of the above: when event has been passed an email instance, for example, it says:
skip_contact_email_url not a method.
The url is right, but it doesn't recognize as a method.
How can I dynamically define skip_contact_email_url to be skip_contact_letter_url if the local variable is letter?
Even better, how can I have a single named route that would do the appropriate action?
You can use polymorphic_url. It generates corresponding route based on item types:
Edit: The route is generated based on record's class, so if you pass :event => call or :event => email, it will work like this:
# event.class == Email
polymorphic_url([contact_event, event], :action => :skip)
#=> /contact_events/:contact_event_id/emails/:id/skip
# event.class == Call
polymorphic_url([contact_event, event], :action => :skip)
#=> /contact_events/:contact_event_id/calls/:id/skip
etc.
Edit2:
Routes:
map.resources :contacts do |contact|
contact.with_options :member => {:skip => : ... [get/post - what you have] } do |c|
c.resources :letter
c.resources :emails
c.resources :calls
end
end

Sortable_element with RJS does not working

I have a list of images where user can arrange their orders.
When user uploaded an image, I want the list to still be sortable.
I am using a similar upload that was described here: http://kpumuk.info/ruby-on-rails/in-place-file-upload-with-ruby-on-rails/
Please help.
Here are the code for upload in view file:
<% form_for [:admin, #new_image], :html => { :target => 'upload_frame', :multipart => true } do |f| %>
<%= hidden_field_tag :update, 'product_images'%>
<%= f.hidden_field :image_owner_id %>
<%= f.hidden_field :image_owner_type %>
<%= f.file_field :image_file %><br />
or get image from this URL: <%= f.text_field :image_file_url %>
<%= f.hidden_field :image_file_temp %><br />
<%= f.submit "Upload Image" %>
<% end %>
And in controller view:
def create
#image = Image.new(params[:image])
logger.debug "params are #{params.inspect}"
if #image.save
logger.debug "initiating javascript now"
responds_to_parent do
render :update do |page|
logger.debug "javascript test #{sortable_element("product_images", :url => sort_admin_images_path, :handle => "handle", :constraint => false)}"
page << "show_notification('Image Uploaded');"
page.replace_html params[:update], :partial => '/admin/shared/editor/images', :locals => {:object => #image.image_owner, :updated_image => #image}
page << sortable_element("product_images", :url => sort_admin_images_path, :handle => "handle", :constraint => false)
end
end
#render :partial => '/admin/shared/editor/images', :locals => {:object => #image.image_owner, :updated_image => #image}
else
responds_to_parent do
render :update do |page|
page << "show_notification('Image Upload Error');"
end
end
end
end
Or, to rephrase the question:
Running this:
page.replace_html params[:update], :partial => '/admin/shared/editor/images', :locals => {:object => #image.image_owner, :updated_image => #image}
page << sortable_element("product_images", :url => sort_admin_images_path, :handle => "handle", :constraint => false)
Will NOT adding sortable list feature.
Please help,
Thank you
I think the problem may well be that the sortable is created when the page first loads. I have run into this issue a couple of times. Adding a new element to the list means you have to call the sortable function again to have the new element included in the sorting.
I am not across prototype/scriptaculous, but there may be a way to have the sortable element listen for events that add elements to the list. jQuery has a set of rebinding events that will respond to new elements added to the DOM, might be something simialr in the other libs.
Found it!
Instead of:
page.replace_html params[:update], :partial => '/admin/shared/editor/images', :locals => {:object => #image.image_owner, :updated_image => #image}
Use
page.replace params[:update], :partial => '/admin/shared/editor/images', :locals => {:object => #image.image_owner, :updated_image => #image}

Resources