I'm starting to develop a small application in Ruby On Rails. I have a short form (within a view) in which the number of fields is variable and created with the code snippet below:
<% for item in #event.items %>
<tr>
<td><%= item.name %></td>
<td><input type="number" name="quantity" /></td>
</tr>
<% end %>
I want to after click 'submit', run a controller's method that access to the data included in each of the fields in the form and perform insertions on the database. In the end, I want the page to be refreshed.
How do I customize the action of the submit button to perform a controller's function? And how do I access inside this function to the form fields (whose number is variable as mentioned).
Thanks in advance for your help.
You can use nested attributes. Then it should looks something like this (sorry for HAML):
= form_for #event do |f|
= f.fields_for :items do |item|
= item.object.name #displays item name
= item.number :quantity
And in your event model:
accepts_nested_attributes_for :items
I would suggest to use in this case the nested_form gem https://github.com/ryanb/nested_form.
Related
I'm working on an admin functionality for an application in Rails.
I've got a table in a page that lists a series of attributes of a particular model "Property".
I want users to be able to click on each line and make the attribute value editable by rendering a partial. In order to do that I assume I need to create a partial for each attribute and have a similar form in each partial with one visible field related to the attribute the user clicked on.
Something like:
View:
<tr id="edit_price" data-link="<%= 'edit_field_price_path' %>">
<% if !#property.price.blank? %>
<th scope="row">Price</th>
<td>$<%= #property.price %></td>
<td>Edit</td>
<% else %>
<th scope="row" class="empty">Price</th>
<td class="empty">Add price</td>
<% end %>
</tr>
Partial:
<%= form_with model: #property, method: :put do |f| %>
<%= f.number_field :price %>
<%= f.hidden_field ONE_FOR_EACH_VALUE, value: ATTRIBUTE_VALUE %>
...
<% end %>
The problem is that I've got over 40 potential fields that can be edited, which means I'd need to create over 40 partials in separate files and add them all to my routes.rb file.
How can I come up with a smarter solution for that?
Is it possible to pass the attribute name as a variable and dynamically edit a single form with jquery?
Does the same need to be done with the routes file?
Thanks a lot in advance.
for that you can use something like best in place gem, it basically create the functionality you like, not for the complete line, but for specific attributes.
read the documentation for configuration, after doing that, you can create the clickable/editable attribute by doing this on your view
<%= best_in_place #user, :name, :as => :input %>
this will create the clickable text, and this will fire the input on the frontend to edit it.
I ended up creating all of those partials. They have different types of fields, so I couldn't find any way to optimize that.
Running a single jquery script that identifies where to place each partial depending on the field name to access each form partial made implementation a bit easier though. It's been proposed here: Concatenate jquery variable into Rails partial
I am a beginner in ruby. I have a table in a view, that when I click on the line / item it should pick up the ID of the selected line and move to the other view that will be triggered, I am 3 days searching on and I can not implement.
The view that should take the ID or another parameter so that in the other I can treat the select to bring more detailed information >>:
<td>
<%= link_to pedido.id, detalhes_backoffice_pedidos_path(:pedido_id =>
pedido.id) , :onclick=>"window.open(this.href,'create_company',
'height=600,
width=600');return false;" %>
</td>
The view ("popup") that is called when clicked on the request id. Obs.:Tried in countless ways, and at the moment she is like this ... >>>>
<div class='container-fluid'>
<div style='display: block;' class="col-xs-6 esquerdo ">
<label>Num.pedido<%= pedido.id %></label> <br>
<label>nome</label> <br>
<label>telefone</label> <br>
</div>
Controller>>
class Backoffice::PedidosController < BackofficeController
.....
def detalhes
render :layout => "application"
#pedido = params[:pedido_id]
end
I am totally lost, after trying so much .... If you can pass some example link for study, it will be very useful too !!
It has become clear that you just need to use AJAX to show the selected pedido details on the page. Rails has an easy way to do this.
First put in a table with a div below it for displaying the pedido info. Each row in the table has a link to the controller action that will do the AJAX. Use remote: true to make the link AJAX, so the user is not taken to another page.
<table>
<tbody>
<% #pedidos.each do |pedido| %>
<tr>
<td><%= link_to 'More info on this Pedido!' fetch_info_pedidos_path(pedido), remote: true %></td>
</tr>
<% end %>
</tbody>
</table>
<div id="pedido-info"></div>
Make the route for the action in the pedido controller. This is in routes.rb
resources :pedidos do
get :fetch_info, on: :member
end
This should create a path that looks like /pedidos/:id/fetch_info with the name fetch_info_pedidos
The link in the table will make a js format request along this route so the controller action must be ready to handle that. The pedido id will come as a parameter called :id
def fetch_info
#pedido = Pedido.find params[:id]
respond_to :js
end
Since it responds to a js format request it will respond with js content, not html - that means we need to have a js file as the view, but before we make that let's make a partial for displaying pedido info. This can be dropped into any view using the render method. It will be in app/views/pedidos/_pedido.html.erb (you have to use an underscore at the start of the file name to show it is a partial) You can put any content in here you like, using the pedido variable to refer to the pedido. Here's an example:
<h2>Pedido!</2>
<p>number: <%= pedido.id %></p>
<p>nom: <%= pedido.nom %></p>
<p>telefone: <%= pedido.fone%></p>
Finally let's make the js that gets passed back to the browser. This will be an erb file like other views. It will just put the _pedido partial as the content to the div under the table. app/views/pedidos/fetch_data.js.erb
$('#pedido-info').html("<%= j render #pedido %>");
That's all you need. The j here escapes the output of the render method so that it plays nicely inside a javascript string.
There's a bit of Rails magic happening here, which I will explain, because, as you would learn at any wizard training school: "don't use any magic you don't completely understand"
The render method expects the name of a partial to render, and optionally some local variables to pass. If it's given only an ActiveRecord object, it will look for the partial that matches the class name of the object (Pedido goes to _pedido.html.erb) and it passes the object as a local variable also with matching name. so render #pedido gets translated to render partial: 'pedido', locals: {pedido: #pedido}
I haven't tried any of the code in this answer, I just wrote it off the top of my head, so you may have to jiggle it a bit to get it to work.
here's a link to a page you might have come across if you had simply Googled how to do this. It says essentially the same as what I have said here, except his AJAX brings in a whole collection of objects, not just one at a time.
I may have misunderstood the question, but it seems to me you just need to link to the detalhes action for each pedido in the table.
here is the table:
<table>
<tbody>
<% #pedidos.each do |pedido| %>
<tr>
<td><%= link_to 'Detalhes this Pedido!' detalhes_path(pedido) %></td>
<td>More table data related to this pedido</td>
</tr>
<% end %>
</tbody>
</table>
and in the routes you would have something like this:
resources :pedidos do
get :detalhes, on: :member, as: 'detalhes'
end
I have a table in view:
#view
<%= form_tag save_table_path do %>
<table>
<% #channel_name_body.values.max_by(&:size).size.times do |i| %>
<tr class="border">
<% #channel_name_body.values.map { |a| a[i] }.each do |value| %>
<td contenteditable class="border light_green"><%= value %></td>
<% end %>
</tr>
<% end %>
</table>
<%= submit_tag "save",:class => "btn btn-primary offset4" %>
<% end %>
I don't know what to do next to pass value of all cell in table to controller such as:
#controller
def save_table
#table=params[:table] #or #row1=params[:row1]... or #col1=params[:col1]....
end
Edit: I found way to solve this problem, it must use js.
I don't want to use js, what about if I change to <%= text_field_tag :cell, value %> how can I get value of all cell in table ?
I think you're getting confused with how to handle data in Rails (or any backend system)
HTML
HTML is a markup language; which means if you give it certain code, it will put various elements onto the page. The <table> tag is one of those elements, and has no bearing on the controller-side functionality of your app
Controller Params
HTML form params are directly related to the form (nothing else)
In Rails, you get the params hash ordered like this:
params[:form_name][:input_name]
Your Code
From what you've shown, it seems you have several parts missing
Firstly, you need input elements (to populate the params). Currently, you have:
<td contenteditable class="border light_green"><%= value %></td>
This does not create any params, as it's not an input element. It's just a value that's been outputted on the screen. What you'd need is something like:
<td contenteditable class="border light_green"><%= text_field_tag :cell, :value => value %></td>
By adding these inputs, you will give Rails the ability to populate the params hash with their values, which you can then access from your controller like this:
def save
#table = params[:form_name][:cell][0]
end
Hope this helps?
Try this:
<%= text_field_tag "table[cell#{index}]", value %>
On form submit it will give you values like params[:table][:cell1], params[:table][:cell2] and so on...
Hope this helps..
I want to assign unique Id to each row generated by nested form .
I looked this question Creating unique id for <fieldset> when using form_for Rails Nested Model Form but this doesn't solve my problem .
I managed to solve this problem by looking into nested form gem .
Inside nested gem unique Id is generated for each addition dynamically.
data-blueprint is parsed and "new_#{association}" is replaced with generated unique ID.In my case relation was like 'Catalogues' has_many 'Category' so my association was categories.
I assigned new row with id = "new_categories" and its replaced by unique Id when new row is added.
Maybe its useful some one else.
Actually, the solution given by Anil Maurya only works for items that have been dynamically added via javascript using link_to_add provided by the gem. But for me, it would leave new_association for already existing items.
In order to properly identify every nested element (even the deeply nested ones), it is possible to use f.index. The advantage is that if the entry already exists (meaning, if it was in the database), then it will just be replaced by the index that it has in the array. However, using link_to_add will replace f.index by the ID automatically generated by nested_form, just like Anil Maurya's solution.
For deeply nested solutions, instead of just writing fields_for and using the same variable f everytime, if you need to properly tag your elements, your should specify which partial to render and each time use a different f variable, which you should pass to the partial
For example: if you have
Main has_many :nested1s
Nested1 has_many :nested2s
Nested2 has_many :nested3s
Then your code should look like this (I gave an example with tables because it's more difficult):
<%= nested_form_for #Main do |main_form| %>
<table>
<thead>
<stuff />
</thead>
<%= main_form.fields_for :nested1s, :wrapper => false do |nested1_f| %>
<%= render 'main/nested1_fields', nested1_f: nested1_f %>
<% end %>
_nested1_fields.html.erb
<tbody class="fields">
<tr>Stuff</tr>
<tr>
<table id="nested1-<%= nested1_f.index %>-nested2s">
<thead>Stuff</thead>
<%= nested1_f.fields_for :nested2s, :wrapper => false do |nested2_f| %>
<%= render 'main/nested2_fields', nested1_f: nested1_f, nested2_f: nested2_f %>
<% end %>
</table>
</tr>
<tr><%= nested1_f.link_to_add 'add nested2', :nested2, :data => { :target => "#nested1-#{nested1_f.index}-nested2s"}, class: "btn btn-sm btn-success" %>
</tbody>
_nested2_fields.html.erb
<tbody class="fields">
...
<table id="nested1-<%= nested1_f.index %>-nested2-<%= nested2_f.index %>-nested3s">
<%= fields_for :nested3s do |nested3_f| %>
...
...
</tbody>
Also it is important to note that the gem nested_form will only work well if every nested fieldsets are wrapped by a tag with the class "fields"
This is hopefully a slam dunk for a Rails maven :
I have a form that is supposed to iterate over a set of LineItems and gather information on each. I am trying to get form_for and fields_for to create the proper field names and parameters to give my controller a params hash something like
params[:line_items] = { <line_item.id> => { :rma_reason => "some string", :rma_qty => 2 } }
What I have is:
<% form_for(#object) do |rma_form| %>
<% #order.line_items.each do |item| %>
....
<% fields_for item do |item_f| %>
<%= item_f.text_area :rma_reason %>
<%= item_f.text_field :rma_qty, :value => item.quantity, :size=>3 %>
<% end %>
....
<% end %>
<% end %>
And the resultant HTML looks like (what you would expect, I guess):
<textarea id="line_item_id" name="line_item[id]"></textarea>
<input id="line_item_rma_qty" name="line_item[rma_qty]" size="3" type="text" value="1" />
However what I am trying to get (and failing to find any solution beyond going back to ad-hoc HTML tags) is, field names that are indexed by the line_item.id, e.g. line_item[1928][rma_qty] for instance. This would allow my controller to iterate over each line_item and update it with the given params.
... maybe in a pure REST UI, the form should be tied to ONE instance of LineItem, and the standard form_for would work - but the user should be able to submit all the changes at once with one form. Is it possible?
When you're nesting form fields, you have to make sure you are chaining the fields_for methods form the appropriate form builder:
<% rma_form.fields_for :line_item, item do |item_f| %>
by calling fields_for alone, you were breaking the chain from form_for and thus the incorrect field names.
the fields_for needs to be called on the main form helper, and a string parameter with magic []s and an argument indicating which instance should be inserted in the []s
<% rma_form.fields_for "line_item[]", item do |item_f| %>
so now my tag looks something like
<input id="return_authorization_line_item_1070870205_rma_qty" name="return_authorization[line_item][1070870205][rma_qty]" size="3" type="text" value="1" />
which is peachy.
this classic railscast is a good fields_for intro, and this comment explains the effect of the magic bracket that did what I wanted - other than that, couldn't find this feature documented anywhere.