Rails Partial: Undefined Local Variable - ruby-on-rails

I use rails infrequently, so pardon if this is obvious. I've looked at the other questions, am working from Ruby On Rail Guide, and it looks like I'm doing this correctly, but I still can't get my local variables to work.
todays/show.html.erb
<p>
<strong>Tasks:</strong>
<%= render partial: "next_steps/next_step_today",
collection: #today_lines %>
</p>
next_steps/_next_step_today.html.erb
<p>
<%= render partial: "next_steps/next_step",
locals: {next_step: today_line.next_step} %>
<%= link_to 'x', today_line, method: :delete, data: { confirm: 'Are you sure?' } %>
</p>
next_steps/_next_step.html.erb
<span class="<%= next_step.complete ? "completed_next_step" : ""%> next_step_span_<%= next_step.id%>">
<%= form_for(next_step,
:remote => true,
:html => {:'data-type' => 'json',
:multipart => true,
:id => "edit_next_step_#{next_step.id}_#{rand()}"}
) do |f| %>
<%= f.hidden_field( :id, :value => next_step.id) %>
<%= f.hidden_field( :note_id, :value => next_step.note_id) %>
<%= f.hidden_field( :content, :value => next_step.content) %>
<%= f.hidden_field( :due_date, :value => next_step.due_date) %>
<%= f.check_box( :complete, :class => "next_step_complete_button" ) %>
<%= next_step.content %>
<% end %>
</span>
I know that the last partial _next_step.html.erb was working before I starting trying to add partials for extra flexibility. Now I can't seem to get the locals passed in correctly.
My previous working code was
todays/show.html.erb
<p>
<strong>Tasks:</strong>
<% #today_lines.each do |today_line| %>
<p><%= render today_line.next_step %></p>
<% end %>
</p>
Error message
NameError in Todays#show
Showing /.../app/views/next_steps/_next_step_today.html.erb where line #3 raised:
undefined local variable or method `today_line' for #<#:0x007f930adbd860>
Extracted source (around line #3):
<p>
<%= render partial: "next_steps/next_step",
locals: {next_step: today_line.next_step} %>
<%= link_to 'x', today_line, method: :delete, data: { confirm: 'Are you sure?' } %>
</p>
Any ideas?
EDIT: FINAL WORKING CODE
todays/show.html.erb
<p>
<strong>Tasks:</strong>
<%= render partial: "next_steps/next_step_today",
collection: #today_lines %>
</p>
_next_step_today.html.erb
<p>
<%= render "next_steps/next_step",
next_step: next_step_today.next_step %>
<%= link_to 'x', next_step_today, method: :delete, data: { confirm: 'Are you sure?' } %>
</p>
collection: does require that you use the partial file name for the local var.
I also found in my searching that if you don't use partial: you can also omit locals: and just use the variable name instead, which is cleaner. This change is shown in _next_step_today.html.erb. I wish I could also name the collection variable, instead of using the partial file name, or instead of using an each, but this is close enough, and working.

The name of the variable within the partial is derived from the name of the partial itself, not from the name of the collection.
Your _next_step_today.html.erb should then be the following:
<p>
<%= render partial: "next_steps/next_step",
locals: {next_step: next_step_today.next_step} %>
<%= link_to 'x', next_step_today, method: :delete, data: { confirm: 'Are you sure?' } %>
</p>
Edit: if you want to stick to the #collection convention, that is

Show needs to specify the key name that the partial will use. So:
<%= render partial: "next_steps/next_step_today",
today_lines: #today_lines %>
Fix the spelling in next_step_today partial as well:
<%= render partial: "next_steps/next_step",
locals: {next_step: today_lines.next_step} %>

Related

Comments section from Ruby on Rails blog tutorial is not rendering

I went through the entirety of the Ruby on Rails tutorial for the blog application here. In this blogging application there are 2 models articles and comments. Comments belong to the articles model. However, the problem that I seem to be having is that my comments do not seem to be showing up in my show view from my article_controller.rb but everything else seems to be. I am still pretty new to rails but does anything stick out from the files shown below?
show.html.erb
<h1><%= #article.title %></h1>
<p><%= #article.body %></p>
<ul>
<li><%= link_to "Edit", edit_article_path(#article) %></li>
<li><%= link_to "Destroy", article_path(#article),
method: :delete,
data: { confirm: "Are you sure?" } %></li>
</ul>
<h2>Comments</h2>
<%= render #article.comments %>
<h2>Add a comment:</h2>
<%= render 'comments/form' %>
_comment.html.erb
<p>
<strong>Commenter:</strong>
<%= comment.commenter %>
</p>
<p>
<strong>Comment:</strong>
<%= comment.body %>
</p>
<p>
<%= link_to 'Destroy Comment', [comment.article, comment],
method: :delete,
data: { confirm: "Are you sure?" } %>
</p>
_form.html.erb
<%= form_with model: [ #article, #article.comments.build ] do |form| %>
<p>
<%= form.label :commenter %><br>
<%= form.text_field :commenter %>
</p>
<p>
<%= form.label :body %><br>
<%= form.text_area :body %>
</p>
<p>
<%= form.label :status %><br>
<%= form.select :status, ['public', 'private', 'archived'], selected: 'public' %>
</p>
<p>
<%= form.submit %>
</p>
<% end %>
comment.rb
class Comment < ApplicationRecord
include Visible
belongs_to :article
end
visible.rb
module Visible
extend ActiveSupport::Concern
VALID_STATUSES = ['public', 'private', 'archived']
included do
validates :status, inclusion: { in: VALID_STATUSES }
end
class_methods do
def public_count
where(status: 'public').count
end
end
def archived?
status == 'archived'
end
end
Thank you in advance for any help.
You've got this line in show.html.erb.
<%= render 'comments/form' %>
According to your filenames it should be:
<%= render 'comment' %>
Okay I figured it out, I forgot the :status part of this line params.require(:comment).permit(:commenter, :body, :status).

Can I nest form tag inside form?

I have a situation where I have to nest form tag inside form because of HTML flow but it can't be done. Are there any alternatives for this?
<tr class="first last">
<td class="a-right last" colspan="50"><button onclick="setLocation('#')" class="button btn-continue" title="Continue Shopping" type="button"><span>Continue Shopping</span></button>
<%= button_tag class: 'button btn-update', id: 'update-button' do %>
<%= Spree.t(:update) %>
<% end %>
<%= form_tag empty_cart_path, method: :put do %>
<%= submit_tag Spree.t(:empty_cart), class: 'button btn-empty' %>
<% end %>
</td>
</tr>
</tfoot>
<%= form_for #order, url: update_cart_path, html: { id: 'update-cart' } do |order_form| %>
<%= render partial: 'form', locals: { order_form: order_form } %>
<% end %>
<% end %>
button_tag should be inside form_for form, but if I set it like this:
<td class="a-right last" colspan="50"><button onclick="setLocation('#')" class="button btn-continue" title="Continue Shopping" type="button"><span>Continue Shopping</span></button>
<%= form_for #order, url: update_cart_path, html: { id: 'update-cart' } do |order_form| %>
<%= button_tag class: 'button btn-update', id: 'update-button' do %>
<%= Spree.t(:update) %>
<% end %>
<%= form_tag empty_cart_path, method: :put do %>
<%= submit_tag Spree.t(:empty_cart), class: 'button btn-empty' %>
<% end %>
</td>
</tr>
</tfoot>
<%= render partial: 'form', locals: { order_form: order_form } %>
<% end %>
<% end %>
it's not working
Can I nest form tag inside form?
You cannot nest form tags.
It is wrong. It won't work because it is wrong. Most browsers will only see one form.
https://www.w3.org/TR/html5/forms.html#the-form-element
Content model:
Flow content, but with no form element descendants.
If I'm correct you like to have that empty_cart button aligned with your update button. In Rails you can create a link that does an update or post or whatever you like. You can do something like:
<%= link_to Spree.t(:empty_cart(_method: 'put')), empty_cart_path, class: 'button btn-empty', method: :post %>

Rails accessing fields_for hidden_field id

I have a nested form with a parent object (full_application) and a collection of child objects (fullapplication_districts) via a has_many association. I am attempting to allow for deletion of individual child objects on the form (via javascript) but to do so I need to be able to grab the id of each child object in the view for passing to the controller. fields_for creates a hidden input field for the id but I can't seem to figure out how to grab the id from it. In the example below the record is the 13th in the list of rendered child objects.
<input type="hidden" value="538" name="full_application[fullapplication_districts_attributes][12][id]" id="full_application_fullapplication_districts_attributes_12_id">
Here's the form setup in the view:
<%= form_for(#full_application, url: full_applications_edit_path, method: :put) do |f| %>
<%= f.fields_for :fullapplication_districts do |fad| %>
<%= fad.collection_select :district_id, District.all, :id, :name, {include_blank: true}, {class: 'form-control'} %>
<%= fad.number_field :percent_one, class: 'form-control', step: :any %>
<%= fad.number_field :percent_two, class: 'form-control', step: :any %>
<%= fad.number_field :percent_three, class: 'form-control', step: :any %>
<%= link_to full_applications_districts_path(???), method: :delete, remote: true, data: { confirm: "Are you sure you want to delete this record?" } do %>
<i class="fa fa-trash"></i>
<% end %>
<% end %>
<% end %>
You can use: fad.object or fad.object.id. This will return to fullapplication_district instance.
<%= link_to full_applications_districts_path(fad.object), method: :delete, remote: true, data: { confirm: "Are you sure you want to delete this record?" } do %>
<i class="fa fa-trash"></i>
<% end %>

How to use ajax on rails 4?

I am trying to create a comment area in rails 4 using ajax. My target is to create comment and its output in same page without page loading. I have added some code. When i click on "add comment" button the data entered to DB, but does not reflect in same page.Please share with me if any one have any idea, thank u.
My codes are below:
In comment controller:
def create
#article = Article.find(params[:article_id])
#comment = #article.comments.create
#comment.body = params[:comment]["body"]
respond_to do |format|
#comment.save
format.html { redirect_to #article }
format.js
end
end
In show.html.erb under views/articles
<div class="col-xs-12 col-sm-12">
<h2 class="text-center"><%= #article.title.html_safe %></h2>
<p><%= #article.body.html_safe %></p>
<h2>Comments</h2>
<div id="comments">
<!-- <p><%= render :partial => #article.comments %></p> -->
<%= render :partial => 'comments/comment', :collection => #article.comments %>
</div>
<%= form_for([#article, Comment.new], :remote => true) do |f| %>
<p>
<%= f.label :body, "New comment" %><br/>
<%= f.text_area :body, type:"text", tabindex: "6", class: "form-control", placeholder: 'your comment', rows: "4", required: true %>
</p>
<p><%= f.submit "Add comment" %></p>
<% end %>
</div>
_comment.html.erb under view/comments
<%= div_for comment do %>
<p>
<b>
Posted <%= time_ago_in_words(comment.created_at) %> ago
</b>
<br/>
<%= comment.body %>
<%= link_to 'Delete', article_comment_path(comment.article_id, comment.id), method: :Delete, :class => 'btn btn-sm btn-warning', tabindex: "3" %>
<%= link_to 'Edit', article_path(comment.article_id, comment.id), :class => 'btn btn-sm btn-warning', tabindex: "3" %>
</p>
<% end %>
create.js.erb under views/comments
page.insert_html :bottom, :comments, :partial => 'comment', :object => #comment
page[:new_comment].reset
config/application.rb
config.action_view.JavaScript_expansions[:defaults] = %w(jquery rails application)
the proper way to handle this case in rails is using a remote form, this way you can interactively insert and remove objects from db.
Here are two explained blog posts about remote forms in rails detailed guide about remote forms and how to partials ajax rails. This way you can submit the form without refresh an then have an handler to generate the created element after the callback from the controller.
Hope this fits your question.
Added something like:
create.js.erb under views/comments
$("#comments").append("<%= escape_javascript(render(:partial => #comment)) %>");
$("#new_comment")[0].reset();
And It works for me.

Ruby on Rails - Trouble looping through partial using collection

I am having issues using the :collection command for a partial within a form I am creating in rails. I would ideally like to use the :collection command, so I can easily manipulate this section in my .rjs templates (the form will submit and reload the form when the check box is changed, it's a to-do list).
This code works:
<% form_for "list[]", :url => {:action => "checkbox_update"} do |f| %>
<ul id="lists_not_completed">
<% for #list in #lists %>
<%= render :partial => #list, :locals => {:f =>f, :complete => FALSE } %>
<% end %>
</ul>
<% end %>
with the partial:
<% if #list.completed == complete %>
<li><%= f.check_box :completed %>
<%=h #list.name %>
<%= link_to 'Show', list %>
<%= link_to 'Edit', edit_list_path(list) %>
<%= link_to 'Destroy', list, :confirm => 'Are you sure?', :method => :delete %></li>
<% end %>
This code does not work, but I would like it to use this form:
<% form_for "list[]", :url => {:action => "checkbox_update"} do |f| %>
<ul id="lists_not_completed">
<%= render :partial => 'list', :collection => #lists, :locals => {:f =>f, :complete => FALSE } %>
</ul>
<% end %>
with the non-working partial:
<% if list.completed == complete %>
<li><%= f.check_box :completed %>
<%=h list.name %>
<%= link_to 'Show', list %>
<%= link_to 'Edit', edit_list_path(list) %>
<%= link_to 'Destroy', list, :confirm => 'Are you sure?', :method => :delete %></li>
<% end %>
I get the error:
object[] naming but object param and #object var don't exist or don't respond to to_param: nil. It is referring to this line: <li><%= f.check_box :completed %>. I'm not sure if why this doesn't work and have tried many, many different variations, but I can't get it working. Is the form preventing me from doing this? The form_for code is straight from the Rails Way book for listing multiple objects from one model in a form.
Any help on this would be greatly appreciated.
I think that the problem is you've not got #list defined anywhere when you're using the render :partial with a :collection.
The system is looking for #list to match the list[] when you call f.check_box
you could set #list = list in your partial to get around that. I suppose.
Tim's answer is correct, but I'd probably avoid extracting the partial within the form_for loop altogether. I suppose it's a matter of style, but I think the confusion here isn't really worth the cleanup that the partial represents in this case. I'd probably write a partial that included the whole form.

Resources