Rails: Dynamically Building Forms and Saving Responses - ruby-on-rails

I'm working on a sort of survey-style project where I need to dynamically create a form based off a Question's Choice's. I've gotten decently far but have run into some issues. Question is a simple model that has_many :choices. Choice has a polymorphic content type that can be represented by anything, in this case things like inputs, check boxes, radio buttons, etc. I want to have a survey page list the questions and choices associated with that question.
So I have this:
/views/survey/index.html.erb
<h1>Survey</h1>
<%= form_for #response do |f| %>
<% #questions.each do |question| %>
<%= f.fields_for :questions do |builder| %>
<%= render question, f: builder %>
<% end %>
<% end %>
<%= f.submit 'Get Response' %>
<% end %>
app/views/questions/_question.html.erb
<h3><%= question.title %></h3>
<% question.choices.each do |choice| %>
<%= f.fields_for "question-#{question.id}" do |builder| %>
<%= render choice, f: builder %>
<% end %>
<% end %>
And an example of a choice partial:
app/views/choice_inputs/_choice_input.html.erb
<%= f.label choice_input.label %>
<%= f.text_field choice_input.label %>
Is this the best way of going about this? The problem, at least I think, with this is the html being generated gives me form names like:response[questions][question-2][tell us more]
I also don't understand how to build a Response object to this. Should I loop through the params in my ResponseController and assign Answer's to each Question? Also how would I go about permitting each question in the params?
I could see params.require(:response).permit(:question-1, :qustion-2, :etc...) getting way out of hand. Thanks for any input on this!

Related

ActiveAdmin nested form duplicate

I know there are multiple questions with a similar title to this, but I haven't found anything that resembled my problem. If there is already a solution and thus my question is a duplicate, I'm sorry - I just didn't find it, it's not that I didn't search.
I'm using ActiveAdmin with the ActiveSkin theme. I have a form for my model Agent where I want to use the nested forms for a has_many relation. I created this code in a partial:
<%= semantic_form_for [#agent], builder: ActiveAdmin::FormBuilder do |f| %>
<%= f.semantic_errors %>
<%= f.inputs 'General Information' do %>
<%= f.input :name %>
<%= f.input :description %>
<% end %>
<%= f.inputs 'Capture Columns' do %>
<%= f.has_many :capture_columns, new_record: 'Add Column' do |column| %>
<%= column.input :column_name %>
<%= column.input :column_datatype %>
<% end %>
<% end %>
<%= f.actions do %>
<%= f.action :submit %>
<li class="cancel"><%= link_to 'Cancel', :back %></li>
<% end %>
<% end %>
Basically, this is working, but it looks like this:
Why is the html duplicated (I checked it, it's exactly the same)? What am I doing wrong?
EDIT:
The inner HTML for the nested form is duplicated, too:
Not saying it's the right behavior, but according to the docs, you need to avoid printing to the template when using has_many.
Try using <%- or <% instead of <%= in the f.has_many declaration and block.
There is a loop hear. The problem is simple to solve, just get in the loop and understand why it is looping and how to fix it. You should use binding.pry to test it. You can set a breakpoint in the form with <% binding.pry %> or you can print variables like <% puts column %> in your server log.
<%= f.has_many :capture_columns, new_record: 'Add Column' do |column| %>
<%= column.input :column_name %>
<%= column.input :column_datatype %>
<% end %>

Cocoon: allow users only to add not edit

I have a Ticket model, which has many Comments. In the edit view, I allow users to add comments, using cocoon. However I want to ensure that previous comments can't be edited. In the view I use a partial called indexlist to render all the previous comments (and delete them). For brevity, I haven't included that code. So in the view I have
<h1>Comments</h1>
<%= render 'comments/indexlist' %>
<br /><br />
<%= f.fields_for :comments do |tc| %>
<%= render partial: 'comment_fields', locals: {f: tc} %>
<% end %>
<div>
<%= link_to_add_association 'Add Comment', f, :comments, :class => "btn btn-primary" %>
</div>
The problem is using f.fields_for :comments do |tc| ... is that it renders each previous comment, but without it, if there are validation errors on the subform all the data is lost during the form round trip.
I'm sure there's an easy solution to this one...
I guess you'll need to have a conditional in the comment_fields
<% if f.object.user_id == current_user.id %>
<div class="field">
<%= f.label :content %>
<%= f.text_field :content %>
</div>
<% else %>
<%= f.object.content %>
<% end %>
That will let you edit your own comments.
The other way you could do it is have one form purely for the ticket and use ajax to add/edit comments rather than use cocoon and nested_attributes which would be the like the way stackoverflow works.

Rails form_for check_box

I'm trying to create a basic survey app. On my take survey page I'm looping through and displaying each answer option as a radio button or checkbox as a form_for to create a user's choice. The choices are working great for the questions that are single choice (or radio buttons), but they aren't saving for multi select questions. I'm pretty sure this has to do with the form I have for the checkbox.
It seems like I should do
<%= f.check_box :answer_id, answer.id %> <%= answer.title %> <br>
similar to how I'm creating the radio button but that throws an error
undefined method `merge' for 14:Fixnum
Here's my code that displays:
<h3>Questions:</h3>
<ul><% #survey.questions.each do |question| %>
<li><p><%= question.title %></p></li>
<% choice = question.choices.build %>
<% if question.single_response == true %>
<%= form_for [question, choice] do |f| %>
<% question.answers.each do |answer| %>
<%= f.radio_button :answer_id, answer.id %> <%= answer.title %><br>
<% end %>
<%= f.hidden_field :survey_id, value: #survey.id %>
<%= f.submit %>
<% end %>
<br />
<% else %>
<%= form_for [question, choice] do |f| %>
<% question.answers.each do |answer| %>
<%= f.check_box :answer_id %> <%= answer.title %> <br>
<%= f.hidden_field :survey_id, value: #survey.id %>
<% end %>
<%= f.submit %>
<% end %>
<br />
<% end %>
<% end %>
</ul>
Any idea what I need to do to get it to save the answer_id to the choice so that it actually creates the choice?
Thanks!
This question is a few years old but I think it deserves a better answer. Since you are using form_for (a model backed form), then you probably want to use the form_for check_box method that you originally tried to use. In your case, it would look like this:
<%= f.check_box :choice, { :multiple => true }, answer.id, false %>
Here is the doc on this.
For checkboxes, you actually want to return an array as the parameter. There is a little funny syntax to this because we don't actually want to use the form builder methods. It should look something like this (adapt to your specific model names and methods)
<%= check_box_tag 'choice[answer_ids][]', answer.id %>
Using this syntax should tell Rails to compile all of the checked checkbox values into an array.
This Railscast goes over the topic.

add a tag by another user by using acts-as-taggable-on

By using acts-as-taggable-on, I made possible to add tags to a word model. And each word belongs to a user.
And I want to make it possible another user can add a tag but for a given amount of time after adding a tag the user can't add another tag.
To implement the function I'm stuck at a error params not found: word.
I rewrite a form
<%= form_for [word.user, word] do |f| %>
<%= f.text_field :tag_list %>
<%= f.submit 'Edit' %>
<% end %>
to
<%= form_tag add_tag_user_word_path(word.user, word) do %>
<%= text_field_tag :tag %>
<%= submit_tag 'Add' %>
<% end %>
then I got the params not found error, when I submit the form.
I could not find the way to pass params[:word] by using form_tag. How can I do it?
I found that I can write like "word[tag]" like this.
<%= form_tag add_tag_user_word_path(word.user, word) do %>
<%= text_field_tag "word[tag]" %>
<%= submit_tag 'Add' %>
<% end %>
Then it works as I hope.

How to submit multiple, duplicate forms from same page in Rails - preferably with one button

In my new views page I have:
<% 10.times do %>
<%= render 'group_member_form' %>
<% end %>
Now this form contains the fields: first_name, last_name, email_address and mobile_number. Basically I want to be able to fill in the fields of all the forms in one click which then submits each into the database as a unique row/id.
What would be the easiest way to accomplish this?
Note: The number of times do is called from a variable. Any advice welcome, thanks!
You should have only one form (you should put only fields in the group_member_form partial). In your view you should have something like:
<%= form_tag "/members" do %>
<% 10.times do %>
<%= render 'group_member_form' %>
<% end %>
<%= submit_tag "Submit" %>
<% end %>
and in _group_member_form.html.erb you should have
<%= text_field_tag "members[][first_name]" %>
<%= text_field_tag "members[][last_name]" %>
<%= text_field_tag "members[][email_address]" %>
<%= text_field_tag "members[][mobile_number]" %>
This way, when the form submits, params[:members] in the controller will be an array of member hashes. So, for example, to get the email adress from the fourth member after submitting the form, you call params[:members][3][:email_adress].
To understand why I wrote _group_member_form.html.erb like this, take a glance at this:
http://guides.rubyonrails.org/form_helpers.html#understanding-parameter-naming-conventions.
You can also use accepts_nested_attributes_for in your model, and use fields_for on your form.
Submitting multiple forms, afaik, only javascript, if the forms are remote: true, and you run through each of them and then submit.
$("form.class_of_forms").each(function() {
$(this).submit();
});
Alternatively a more up to date approach using form_with and fields_for, without removing the form into a partial, could be written like this:
<%= form_with (url: end_point_path), remote: true do |form| %>
<% (1..5).each do |i| %>
<%= fields_for 'cart_items'+[i].to_s do |fields|%>
<%= fields.text_field :first_name %>
<%= fields.text_field :last_name %>
<%= fields.email_field :email_address %>
<%= fields.number_field :phone_number %>
<% end %>
<% end %>
<%= form.submit "Submit" %>
<% end %>

Resources