Better way of displaying nested attributes in Rails form - ruby-on-rails

I need to display only four options to questions. At present I am repeating the code four times. I am sure that there is a better way to do it. Can you please tell me how?
form
<%= form_for #question do |form| %>
<div class="field">
<%= form.label :body %>
<%= form.text_area :body %>
</div>
<%= form.fields_for :options, question.options.build do |a| %>
<div class="field">
<%= a.label :options %>
<%= a.text_area :body %>
<%= a.check_box :is_answer, checked: true %>
</div>
<% end %>
<%= form.fields_for :options, question.options.build do |a| %>
<div class="field">
<%= a.label :options %>
<%= a.text_area :body %>
<%= a.check_box :is_answer, checked: true %>
</div>
<% end %>
<%= form.fields_for :options, question.options.build do |a| %>
<div class="field">
<%= a.label :options %>
<%= a.text_area :body %>
<%= a.check_box :is_answer, checked: true %>
</div>
<% end %>
<%= form.fields_for :options, question.options.build do |a| %>
<div class="field">
<%= a.label :options %>
<%= a.text_area :body %>
<%= a.check_box :is_answer, checked: true %>
</div>
<% end %>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
Here I am repeating the block for :options four times. How can I do it in a single block?

In your controller your could do
def create
#question = Question.new
4.times { #question.options.build }
end
And then in your view
<%= form_for #question do |form| %>
<div class="field">
<%= form.label :body %>
<%= form.text_area :body %>
</div>
<%= form.fields_for :options, question.options.build do |a| %>
<div class="field">
<%= a.label :options %>
<%= a.text_area :body %>
<%= a.check_box :is_answer, checked: true %>
</div>
<% end %>
<% end %>
That should build 4 of the nested fields for you so you don't have to repeat the code that many times :D

Related

How to put nested fields_for code directly in parent _form?

How can I rewrite the code in duels/_form so I can put the code from dueler_fields directly in there?
duels/_form
<%= simple_form_for(#duel) do |f| %>
<%= f.text_field :consequence %>
<%= f.text_field :reward %>
<%= f.fields_for :duelers do |dueler| %>
<%= render 'dueler_fields', :f => dueler %>
<% end %>
<%= link_to_add_association f, :duelers do %>
<span class="glyphicon glyphicon-plus"></span> Dueler
<% end %>
<% end %>
_dueler_fields
# I want to place these two lines of code in the _form
<%= f.number_field :user_id, placeholder: "Enter User ID" %>
<%= f.number_field :challenge_id, placeholder: "Enter Challenge ID" %>
duels_controller
def new
#duel = Duel.new
respond_with(#duel)
end
duels has_many duelers.
change f to dueler and you should be good to go. or:
<%= simple_form_for(#duel) do |f| %>
<%= f.text_field :consequence %>
<%= f.text_field :reward %>
<%= f.fields_for :duelers do |dueler_form| %>
<%= dueler_form.number_field :user_id, placeholder: "Enter User ID" %>
<%= dueler_form.number_field :challenge_id, placeholder: "Enter Challenge ID" %>
<% end %>
<% end %>

Extend forms without page reload, rails

I'm searching for a solution to extend my form without page reload.
First I tried to render a partial with coffee or javascript, but escape_javascript didnt work.
Here's the view
<%= form_for #recipe = current_user.recipes.build do |f| %>
<%= f.label :name, "Recipe Name" %>
<%= f.text_field :name %>
<%= button_to "Add Ingredient", '#', class: "btn btn-lg btn-primary", id: "add" %>
<p></p>
<%= f.submit class: "btn" %>
<% end %>
The form above should be extented with following partial by every click on the button
<div id="recipe-ingredients">Quantity
<%= f.fields_for :quantities, #recipe.quantities.build do |quantity| %>
<%= render 'quantity_fields', f: quantity %>
<% end %>
</div>
_quantity_fields
<%= f.label :amount, "Amount:" %>
<%= f.text_field :amount %>
<%= f.collection_select(:ingredient_id, Ingredient.all, :id, :name) %>
This approach did not work (recipes.js.erb)
$(document).ready(function() {
$("#add").click(function() {
$("p").append("<%= escape_javascript
render(:partial => 'quantities') %>");
});
});
There's a workaround (see below) but I'm searching for a better solution.
$(document).ready(function() {
$("#workout-week").append(<%= escape_javascript(
Haml::Engine.new(File.read(File.join(Rails.root,'app/views',
'_show_period.html.haml'))).render(Object.new, period: #period)) %>);
});
A second approach is to write following lines in Coffee or JavaScript:
<%= f.fields_for :quantities, #recipe.quantities.build do |quantity| %>
<%= f.label :amount, "Amount:" %>
<%= f.text_field :amount %>
<%= f.collection_select(:ingredient_id, Ingredient.all, :id, :name) %>
<% end %>
I'm a newbie so take this with a grain of salt, but have you tried using render :foo instead of redirect_to :foo in the appropriate controller function?
I solved it with cocoon
<%= form_for #recipe do |f| %>
<div class="field">
<%= f.label :name %>
<br/>
<%= f.text_field :name %>
<%= f.fields_for :quantities do |quantity| %>
<%= render 'quantity_fields', :f => quantity %>
<% end %>
<div class="links">
<%= link_to_add_association 'add', f, :quantities %>
</div>
</div>
<%= f.submit %>
<% end %>

If statement preventing submit button to work

My submit button won't work because of the first if statement. If I remove the block, the button works. The statement seems to break the view. Why?
<% if params[:action] == "edit" %>
<div class="field">
<%= form_tag :action => "edit" do %>
<%= select_tag :vehicle_id, options_from_collection_for_select(#vehicles, :id, :model, params[:id].to_i), :onchange => "this.form.submit()" %>
<% end -%>
<%= link_to 'Nouvelle voiture', new_vehicle_path %>
</div>
<% end -%>
<div class="field">
<%= f.label "Modèle" %>
<%= f.text_field :model, required: true %>
</div>
<div class="field">
<%= f.label "Immatriculation" %>
<%= f.text_field :license_plate, required: true %>
</div>
<div class="field">
<%= f.label "Complément" %>
<%= f.text_field :complement, required: true%>
</div>
<div class="field">
<%= f.label "Puissance CV" %>
<%= f.number_field :horse_power, required: true %>
</div>
<div class="field">
<%= f.label "Indemnité KM" %>
<%= f.number_field :km_compensation, required: true%>
</div>
<% if params[:action] == "edit" %>
<%= link_to 'Détruire', #vehicle, method: :delete, data: { confirm: 'Êtes-vous sûr ? Les trajets associés seront aussi détruits.' } %>
<h1>Trajets</h1>
<div>
<span>Clients</span>
<span>Kms aller/retour</span>
</div>
<%= f.fields_for :trip_distances do |builder| %>
<div class="field">
<%= builder.text_field :id_contract %>
<%= builder.number_field :length %>
</div>
<% end -%>
<% end -%>
<div class="actions">
<%= f.submit 'Sauvegarder' %>
</div>
When you put if statement you don't have form in which your submit button resides. Without if statement your form is in the view, and you can submit to it.
Found the solution. I didn't need the form_tag:
<%= form_tag :action => "edit" do %>

How to check attribute value of current object in edit form?

I have a nested model. How to check attribute value of object(hotel) of neted model in edit form? I can't figure out how to write if/else statement in _hotels_fields.html.erb
edit.html.erb
<% provide(:title, "Edit trip") %>
<h1>Edit trip</h1>
<%= form_for(#trip) do |f| %>
<%= render 'fields_edit', f: f %>
<%= f.submit "Save changes" %>
<% end %>
_fields_edit.html.erb
<p>
<%= f.label :image %>
<%= f.file_field :image %>
</p>
<p>
<%= f.label :content %>
<%= f.text_area :content %>
</p>
<p>Hotel</p>
<%= f.fields_for :hotels do |builder| %>
<%= render 'hotels_fields', f: builder %>
<% end %>
_hotels_fields.html.erb
<% if #trip.hotels.name == "hotel" %>
<p>Render any text</p>
<% end %>
<fieldset>
<p>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :description %>
<%= f.text_field :description %>
</p>
</fieldset>
In the context of _hotels_fields.erb.html one specific hotels (why plural here if you have only one?) is represented by f.object. Therefore this should work:
<% if f.object.name == 'hotel' %>
...
<% else %>
...
<% end %>

How to ensure all nested attributes show during 'edit'

I currently have a nested model User has_many Sales_Orders has_many Items.
I can create the Sales_Order with nested Items properly but when I try to 'edit' the Sales_Order, the Sales_Order information is visible but the Items are not shown. Any idea why these wouldn't show?
[sales_orders_controller.rb]
...
def edit
#sales_order = SalesOrder.find(params[:id])
end
[edit.html.erb]
<% provide(:title, "Edit SO") %>
<h1>Edit Sales Order</h1>
<div class="row">
<div class="span6 offset3">
<%= form_for(#sales_order) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="span3">
<%= f.label :so, "SO#:" %>
<%= f.text_field :so %>
<%= f.label :customer, "Customer:" %>
<%= f.text_field :customer %>
<%= f.label :enter_date, "Date Entered:" %>
<%= f.text_field :enter_date, value: date_formatter(#sales_order.enter_date) %>
<%= f.label :request_date, "Request Date:"%>
<%= f.text_field :request_date, value: date_formatter(#sales_order.request_date) %>
<%= f.label :comments, "CS Comments:" %>
<%= f.text_area :comments %>
</div>
<div class="span3">
<% f.fields_for #sales_order.items do |builder| %>
<%= render 'item_fields', f: builder %>
<% end %>
</div>
<%= f.submit "Save changes", class: "btn btn-large btn-primary" %>
<% end %>
</div>
</div>
[_item_fields.erb]
<fieldset>
<%= f.label :item_code, "Item Code:" %>
<%= f.text_field :item_code %>
<%= f.label :qty_in_kg, "Qty (kg):" %>
<%= f.text_field :qty_in_kg %>
<%= f.label :qc_comments, "Comments:" %>
<%= f.text_field :qc_comments %>
<%= link_to "remove", '#', class: "remove_fields" %>
</fieldset>
<% f.fields_for #sales_order.items do |builder| %>
should be
<%= f.fields_for #sales_order.items do |builder| %>
Without the = you're building the output in the loop but never rendering/printing the return value (the generated HTML output).
Use <%= f.fields_for #sales_order.items do |builder| %>
Notice the = sign. This implies, "evaluate and embed"

Resources