Interpret string value as ruby method - ruby-on-rails

I have a FormQuestion model that stores form_for tags as strings.
I am looking to have something like the following:
<%= form_for(application_form) do |f| %>
<% FormQuestion.all.each do |q| %>
<%= q.input %> #where q.input = "f.text_field :name"
<% end %>
<% end %>
How can I get the string returned from q.input to be interpreted as the form_for ruby tag, rather than simply being printed as text on the page?
EDIT:
eval(q.input) was suggested, however I am looking for a safer alternative

You can use send method as:
<%= form_for(application_form) do |f| %>
<% FormQuestion.all.each do |q| %>
<%= f.send(q.input) %> #where q.input = "f.text_field :name"
<% end %>
<% end %>

I would change this to either be:
<%= form_for(application_form) do |f| %>
<% FormQuestion.all.each do |q| %>
<% f.send q.type, q.name %> #where q.type = :text_field and q.name = :name
<% end %>
<% end %>
Or else:
<%= form_for(application_form) do |f| %>
<% FormQuestion.all.each do |q| %>
<%= raw q.as_html %> # where q.as_html = "<input name="name"></input>"
<% end %>
<% end %>

Related

fields_for not nesting attributes

I have this form:
<%= form_for(:quiz_responses, url: quiz_responses_path) do |f| %>
<%= f.hidden_field :name, value: #survey.name %>
<%= fields_for :questions do |ff| %>
<% #questions.each do |question| %>
<ul>
<%= ff.hidden_field "#{question_counter}", value: question.content %>
<%= ff.label question.content %>
<%= fields_for :answers do |fff| %>
<% question.answers.each do |answer| %>
<%= fff.hidden_field "#{answer_counter}", value: answer.content %>
<% answer_counter += 1 %>
<%= fff.label answer.content %>
<%= f.radio_button("user_answer[#{user_answer_counter}]", answer.content) %>
<% end #questions.answers.each do %>
<% end #fields_for answers %>
<% user_answer_counter += 1 %>
</ul>
<% question_counter += 1 %>
<% end ##questions.each do %>
<% end #fields_for questions %>
<%= f.submit %>
<% end #form_for%>
My wanted result is that I get a params hash with :quiz_responses containing a :questions hash, and each question value inside that hash contains an :answers hash containing answers. But this is what I see:
where there's a questions hash containing all the questions and a separate answers hash containing all the answers, and somehow user_answeris inside quiz_responses. How do I fix this mess?
You need to call fields_for on your form object like this:
<%= form_for(:quiz_responses, url: quiz_responses_path) do |f| %>
# ...
<%= f.fields_for :questions do |ff| %>
# ...
<%= ff.fields_for :answers do |fff| %>
# ...

Couldn't save collection_radio_buttons in array Ruby on Rails

We have a problem to save the values of the radio_buttons of a loop. It doesn't save in an array.
The SavedAnswer model has an has_and_belongs_to_many relation with the MultipleChoiceAnswer model.
This is my code:
<%= form_for #saved_answer do |f| %>
<% #questions.each do |question| %>
<%= collection_radio_buttons(:saved_answer, :multiple_choice_answer_ids , question.multiple_choice_answers, :id, :title) do |c| %>
<%= c.radio_button %>
<%= c.label %>
<% end %>
<% end %>
<%= f.submit "Submit" %>
<% end %>
My output is
Parameters: {"utf8"=>"✓", "authenticity_token"=>"57I9yLZMccvcb3Bn5/pw7kES0c9CUAGs33yCXoS0Urm1Yek/Baz8Hl7fO8Yl/OVZWLKsX7qrwOlqEBoXrGkcxQ==", "saved_answer"=>{ "multiple_choice_answer_ids"=>"1"}, "commit"=>"Submit"}
Thanks in advance!
You have form_for with |f| and collection with |f|.
It's not a good decision, i think. That can cause problems.
If not - write what you receive in params when trying to save.
Just use check boxes for your issue:
<%= form_for #saved_answer do |f| %>
<% #questions.each do |question| %>
<%= check_box_tag "saved_answer[multiple_choice_answer_ids][]", question.id, #saved_answer.multiple_choice_answer_ids.include?(question.id) %>
<%= question.title %>
<% end %>
<%= f.submit "Submit" %>
<% end %>
Refer: http://railscasts.com/episodes/17-habtm-checkboxes?view=asciicast

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

How do I separate elements by their type with an each method?

I created two scaffolds: announce_sections and announcements. The announce_sections are the types of announcements there are (i.e. games, tryouts, etc) and when I create an announcement I specify what type of announce_sections it is. I'm trying to display it so that each announce_section is viewed, with each announcement and its information under the announce_section. This is what I came up with:
<% #announce_sections.each do |announce_section| %>
<%= announce_section.name %>
<% #announcements.each do |announcement| %>
<%= announcement.announcement_title %>
<%= announcement.information %>
<%= announcement.additional_information %>
<%= announcement.type %>
<% end %>
<% end %>
However, this code only displays the announce_sections with the all announcements under it. The announcements don't get separated into their respective announce_sections. How do I change it so that it does?
<% #announce_sections.each do |announce_section| %>
<%= announce_section.name %>
<% #announcements.where(type: announce_section).each do |announcement| %>
<%= announcement.announcement_title %>
<%= announcement.information %>
<%= announcement.additional_information %>
<%= announcement.type %>
<% end %>
<% end %>
Use the name of the field you are using to assign the announcement type instead of 'type'
There are many ways to solve this, but one simple one is to build a hash where the key is the type of announcement_section and the value is an array (or Set) of the announcement. One way to build that hash is to use the Hash.new {|hash, key| ... } form of the constructor.
#hash = Hash.new {|hash, section| hash[section] = Array.new }
#announcements.each do |a|
# for each announcment append it to the array under the hash
#hash[a.section] << a
end
And then, in the view
<% #hash.keys.each do |section| %>
<%= section %>
<% #hash[section].each do |announcement| %>
<%= announcement.announcement_title %>
<%= announcement.information %>
<%= announcement.additional_information %>
<%= announcement.type %>
<% end %>
<% end %>

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

Resources