Rails: has_many :through _ids nested? - ruby-on-rails

On a single page I might have a single Video and then checkboxes to add multiple dogs to it. Easy enough (as follows)...
View:
<%= check_box_tag "video[dog_ids][]", dog.id %>
Controller:
params[:video][:dog_ids] ||= []
But what I can't figure out how to do is have multiple videos, each with multiple dogs.
I currently have this:
<% #videos.each do |video| %>
<%= fields_for "item[]", video do |f| %>
<%= f.hidden_field :id, :index => nil %>
<%= f.text_field :title, :index => nil%>
<%= f.text_area :body, :index => nil %>
<% video.dogs.each do |dog| %>
<%= check_box_tag "item[][video[dog_ids][]]", dog.id %>
<% end %>
<% end %>
<% end %>
But when I do that, dogs_ids is always nil when it's submitted.
Any idea what I'm doing wrong?

Such a setup with fields_for "item[]" and f.text_field :title, :index => nil produces:
<input id="item__name" name="item[][title]" size="30" type="text" value="vid1">
This indicates that the checkbox name should be item[][dog_ids][].
A working example:
<% #videos.each do |video| %>
<%= fields_for "item[]", video do |f| %>
<%= f.text_field :title, :index => nil %>
<% video.dogs.each do |dog| %>
<%= check_box_tag "item[][dog_ids][]", dog.id %> <%= Dog.name %>
<% end %>
<br>
<% end %>
<% end %>
This produces result in params:
{"item"=> [
{"title"=>"vid1", "dog_ids"=>["1", "2"]},
{"title"=>"vid2", "dog_ids"=>["2"]},
{"title"=>"vid3", "dog_ids"=>["2", "3"]}
]}

Related

Save Question(s) form with one submit button

In my rails app I have a questions view that renders all the questions in a poll. I want to make sure that all the questions rendered can be submitted using 1 submit button.
If that's not possible, how can I render one question after another until there are no more quesitons?
The front-end code goes:
poll_question.html.erb:
<% #poll.questions.each do |qst| %>
<%= render "questions" , qst: qst%>
<p style="color: red"><%= notice %></p>
<hr>
<% end %>
Render partial _questions.html.erb:
<%= form_with model: qst.question_results.build, url: question_question_results_path(qst) do |f| %>
<% qst_type = qst.poll.voting_type %>
<% option_length = qst.options.count %>
<%= f.hidden_field :question_id, value: qst.id %>
<%= f.hidden_field :option_id, value: qst.options.first.id %>
<h3> <%= qst.title %></h3>
<h6> <%= qst.description %> </h6>
<ul>
<% qst.options.each do |option| %>
<%= f.fields_for :question_result_ranks, f.object.question_result_ranks.build do |rank_f| %>
<%= rank_f.hidden_field :option_id, value: option.id %>
<%= option.title %>
<%= rank_f.select :rank, options_for_select((1..option_length).step(1)) %><br>
<% end %>
<% end %>
</ul>
<div>
<%= f.submit "Save Answer" %>
</div>
<% end %>
Here is my routes.rb
resources :users do
resources :polls
# Questions
resources :questions, shallow: true do
resources :options
resources :question_results
patch "/create_question_results", to: "questions#create_question_results", as: "create_question_results"
end
end
Edit: These views are not rendered under the Poll and Question Controller, They are rendered under the session module which has no relationships in the model.
If you want to submit all the questions with one click, you should use a nested form.
Main template poll_question.html.erb:
<%= form_with model: #poll do |form| %>
<%= form.fields_for :questions do |f| %>
# This block renders a collection of partials.
<%= render 'question', f: %>
<% end %>
<%= form.submit 'Save' %>
<% end %>
Question form _quiestion.html.erb:
<% qst = f.object %>
<% qst_type = qst.poll.voting_type %>
<% option_length = qst.options.count %>
<%= f.hidden_field :question_id, value: qst.id %>
<%= f.hidden_field :option_id, value: qst.options.first.id %>
<h3> <%= qst.title %></h3>
<h6> <%= qst.description %> </h6>
<ul>
<% qst.options.each do |option| %>
<%= f.fields_for :question_result_ranks, f.object.question_result_ranks.build do |rank_f| %>
<%= rank_f.hidden_field :option_id, value: option.id %>
<%= option.title %>
<%= rank_f.select :rank, options_for_select((1..option_length).step(1)) %><br>
<% end %>
<% end %>
</ul>
And don't forget to add accepts_nested_attributes_for :questions in your poll model.

Having labels only appear once in field_for

What I currently have is:
<%= f.label :attachment_uploader, 'Current Attachments:' %>
<%= f.fields_for :data_files do |attachment| %>
<% if !attachment.object.new_record? %>
<%= attachment.label :attachment_uploader, 'Delete: ' + attachment.object.attachment_uploader_url.split("/").last %>
<%= attachment.check_box :_destroy %>
<% end %>
<% end %>
However, if I don't have any attachments the label is still there. For the sake of aesthetics I'd like it to be hidden unless I have attachments.
I was thinking something akin to:
<%= f.fields_for :data_files do |attachment, index| %>
<% if index == 0 %>
<%= attachment.label :attachment_uploader, 'Current Attachments:' %>
<% end %>
#rest of code
<% end %>
But that doesn't work!
I've read about the f.options[:index] in another post, but I couldn't figure it out.
Add an unless empty? condition before fields_for. #object will be the object for which you created the form
<%= f.label :attachment_uploader, 'Current Attachments:' %>
<% unless #object.data_files.empty? %>
<%= f.fields_for :data_files do |attachment| %>
<% if !attachment.object.new_record? %>
<%= attachment.label :attachment_uploader, 'Delete: ' + attachment.object.attachment_uploader_url.split("/").last %>
<%= attachment.check_box :_destroy %>
<% end %>
<% end %>
<% end %>

Find ID does not find the id and create

I have a 2 views that I want to use before the create action.
1st view is add_sample_details.html.erb
<% form_tag add_expt_details_samples_path :method => :post do %>
<% for sample in #samples %>
<% fields_for "samples[]", sample do |form| %>
<fieldset>
<legend>Sample Name: <%= sample.name %></legend>
<p><center><%= form.label :sample_title %>
<%= form.text_field :sample_title, :size => 25 %></center></p>
<table>
<tr>
<td>
<%= form.label :taxon_id %>
<%= form.text_field :taxon_id, :size => 15 %>
</td>
<td>
<%= form.label :scientific_name %>
<%= form.text_field :scientific_name, :size => 20 %>
</td>
<td>
<%= form.label :common_name %>
<%= form.text_field :common_name, :size => 15 %>
</td>
</tr>
</table>
<p>
<center>
<%= form.label :sample_descripition %><br \>
<%= form.text_area :description %>
</center>
</p>
</fieldset>
<% end %>
<% end %>
<p><center><%= submit_tag "Next" %></center></p>
<% for samp in #samples %>
<%= hidden_field_tag("sample_ids[]", samp.id) %>
<% end %>
<% end %>
in the SamplesController, the add_expt_details looks like this
def add_expt_details
# Collect the samples that were sent
#expt_samples = Sample.find(params[:sample_ids])
end
and the add_expt_details.html.erb looks like this
<% form_for #expt_samples, :url => create_study_samples_path, :html => { :method => :put } do |f| %>
<% #expt_samples.each do |samp|%>
<% f.fields_for :expts do |form| %>
<%= form.label :experiment_title %>
<%= form.text_field :expt_title, :size => 15 %><br \>
<% end %>
<% end %>
<p><center><%= submit_tag "Next" %></center></p>
<% end %>
and my create_study action is like this
def create_study
#study = Study.new(params[:study])
# this method collects all the samples from the add_sra_details view from the hidden_field_tag
if current_user.id?
# Put the current user_id in the study.user_id
#study.user_id = current_user.id
if #study.save # Save the values for the study
# Update the Sample attributes
#samples = Sample.update(params[:samples].keys, params[:samples].values).reject { |p| p.errors.empty? }
# For all those sample_ids selected by the user, put the study ids in the sample_study_id
#samples.each do |samp|
#study.samples << samp
end
# get the ids_sent from the add_expt_details
#expt_samples = Sample.find(params[:id])
# A Flash message stating the details would be prefereable..! (Means you have to do it)
flash[:success] = "Your Study has been Created"
redirect_to add_expt_details_samples_path
else
flash[:error] = "Study Faulty"
render :action => "add_sra_details"
end
end
end
The error message I get when I keep the #expt_samples = Sample.find(params[:id]) is "undefined method `keys' for nil:NilClass"
and If I dont have the #expt_samples, it gives me an error "Couldn't Find id in Sample"
Can some one suggest how can I update set of sample ids from one form and also create new Expt model records that are associated to the sample_ids in another form.
All suggestions are appreciated.
Cheers
You need to refer to Rails' accepts_nested_attributes_for
To see how to link existing objects with forms, you can see examples here:
http://josemota.net/2010/11/rails-3-has_many-through-checkboxes/
rails 3 has_many :through Form with checkboxes
has_many through checkboxes

Using form_for with Awesome Nested Set

I have a Comment model with the acts_as_nested_set enabled, but when I try to do something like this (for nested comments), i receive the error "comment_comments_path not found", presumably because the default pathing doesn't work with Awesome Nested Set. How do I get around this?
<%= form_for([#comment, #comment.children.build]) do |f| %>
<%= f.text_area :content, :placeholder=>'What do you think?'%>
<%= f.submit 'Submit Reply'%>
<% end %>
I also tried this:
<%= form_for(#comment) do |f| %>
<% #comment.children.each do |sub| %>
<%= f.fields_for :children, sub do |child| %>
<%= child.text_area :content, :placeholder=>'What do you think?'%>
<%= f.submit 'Submit Reply'%>
<% end %>
<% end %>
<% end %>
but it didn't generate a textbox for me to type in.
You're very close, yeah you have to build it first then have fields for, so this:
<% #comment.children.build %>
<%= form_for([#comment]) do |f| %>
<%= f.fields_for :children do |child| %>
<%= child.text_area :content, :placeholder=>'What do you think?'%>
<% end %>
<%= f.submit 'Submit Reply'%>
<% end %>
<% end %>
This will have a form for all existing children + the new one. If you want only a form for a new child then you'll want this instead:
<%= form_for([#comment]) do |f| %>
<%= f.fields_for #comment.children.build, :children do |child| %>
<%= child.text_area :content, :placeholder=>'What do you think?'%>
<% end %>
<%= f.submit 'Submit Reply'%>
<% end %>
<% end %>

Ajax and voting

I have a parent class Car and the /cars/show page lists all of the reviews associated with it. The reviews can be voted on. I am having some difficulty getting the :votes_count to update by JavaScript.
/votes/create.js.erb
$("#votes").html("<%= review.votes_count %>") // this does not work
/cars/show
<% #car.reviews.each do |review| %>
<p id='votes'><%= pluralize(review.votes_count, 'vote') %></p>
<% if current_user %>
<%= form_for(#vote, :remote => true) do |f| %>
<%= f.hidden_field "review_id", :value => review.id %>
<%= f.hidden_field "user_id", :value => current_user.id %>
<%= f.submit "vote" %>
<% end %>
<% end %>
<br />
<%= review.content %>
<% end %>
create.js.erb
<% #car.reviews.each do |review| %>
$("#review_<%= review.id %>").html("<%= pluralize(review.votes_count, 'vote') %>");
<% end %>

Resources