fields_for in table produces technically incorrect HTML - ruby-on-rails

When I use a construct like:
<table>
<%= f.fields_for :group_locations do |gl| %>
<tr>
<td><%= gl.label :group_id %></td>
<td><%= gl.select :group_id, paths %></td>
</tr>
<% end %>
</table>
I get an error in my browser (Safari) for each row in the table (<input> is not allowed inside <tbody>. Inserting <input> before the <table> instead.) This is caused by the hidden <input> for the association's id being placed after the </tr>. How can I cause the id's <input> to appear inside one of the TD elements?

I think the hidden field won't be printed if you print it manually. Could you try this?
<table>
<tr>
<%= f.fields_for :group_locations do |gl| %>
<td><%= gl.hidden_field :id %></td>
<td><%= gl.label :group_id %></td>
<td><%= gl.select :group_id, paths %></td>
<% end %>
</tr>
</table>

The fields_for method concatenates the hidden id <input> to the end of the block it captures. So, if you put your <% end %> tag before your second </td>, you should get the result you want.

This is more of a comment (but I don't seem to be able to comment directly). Just wanted to note that Dogbert's answer worked for me. The malformed html didn't seem to worry most browsers... until I tried to use jquery ui sortable on the the table in IE8, which caused a number of problems (including a crash). Anyway, explicitly including the id in a hidden field inside a td seems the way to go. You may want to consider only doing this if the object is persisted (otherwise the hidden field has no value, which may or may not be an issue depending on your code). Adding a check to see if an object is persisted might look like (in the above case):
<% if gl.object.persisted? %>
<td><%= gl.hidden_field :id %></td>
<% end %>

Related

How to dynamically generate checkboxes on the view and submit to controller?

I send a collection to my view and iterate over it. Each iteration has a checkbox as well as two text fields. I want to be able to submit selected items, but also submit the values in the text field as an update as well.
<% #lots.each_with_index do |lot, index| %>
<tr>
<td><%= lot.lot_code %></td>
<td ><%= check_box_tag "lots[][lot_id]", lot.id, false, %></td>
<td><%= text_field_tag "lots[][seal_num]", lot.seal_number %></td>
<td><%= text_field_tag "lots[][contr_num]", lot.container_number %></td>
</tr>
<% end %>
My #lots collection has three rows:
{id: 2, container_number: "container#0002", seal_number: "seal#0002"}
{id: 6, container_number: "container#0006", seal_number: "seal#0006"}
{id: 11, container_number: "container#00011", seal_number: "seal#00011"}
(apologies if that is not proper hash syntax)
My problem is that if I check items 1 and 3, the parameter string shows the following:
"lots"=>[{"lot_id"=>"2", "seal_num"=>"seal 0002", "contr_num"=>"container#0002"},
{"seal_num"=>"Seal-006", "contr_num"=>"container #006", "lot_id"=>"11"},
{"seal_num"=>"Seal-0011", "contr_num"=>"container #0011"}]
The problem is that lot_id = 11 should be the 3rd item in the array, not the second. For some reason, because item #2 is not selected, the empty lot_id element is being populated by the next one in the sequence.
How do I make sure the selected IDs are in the same elements as the other attributes? Or how do I make sure the non-selected items don't even end up on the parameter string?
Edit: I have also tried the following:
<% #lots.each_with_index do |lot, index| %>
<tr>
<td><%= lot.lot_code %></td>
<td ><%= check_box_tag "lots[#{index}][lot_id]", lot.id, false, %></td>
<td><%= text_field_tag "lots[#{index}][seal_num]", lot.seal_number %></td>
<td><%= text_field_tag "lots[#{index}][contr_num]", lot.container_number %></td>
</tr>
<% end %>
And I get this on the following parameter string:
lots"=>{"0"=>{"lot_id"=>"2", "seal_num"=>"seal 0002", "contr_num"=>"container#0002"},
"1"=>{"seal_num"=>"Seal-006", "contr_num"=>"container #006"},
"2"=>{"lot_id"=>"19", "seal_num"=>"Seal-0011", "contr_num"=>"container #0011"}}
This maintains the integrity of the rows as desired, but I later get a "TypeError: no implicit conversion of String into Integer" later on in processing.
Edit 2: Realized the solution in the edit created a hash, and my code was looking to access an array. So when the hash was iterated over, I was errantly accessing the key, an integer, rather than the value.

Rails / MongoDB: Variable to address object-attribute not translating

In my class AleShot I have some dynamic mongoid-attributes. In order to index them, I collect all attributes in an array called "dynamos". Now when I want to list these (see code below) I get: undefined method 'dyn_f' for #<AleShot:0x007f8f7ab18328>
Any Ideas why the dyn_f-variable isn't translated correctly?
<% #ale_shots.each do |ale_shot| %>
<tr>
<td><%= ale_shot.name %></td>
<% dynamos.each do |dyn_f| %>
<td><%= ale_shot.dyn_f %></td>
<% end %>
</tr>
<% end %>
That could be because dyn_f is not defined as a field in the model.
Access it like this
ale_shot['dyn_f']

Correct way of conditional rendering within a partial in Rails?

I have created a partial for a LineItem that, in my case, emits a <tr> with a couple of <td>s. This works just fine and dandy.
What I'd want to do then, is use the same partial in different places. The original view has plenty of room, so displaying every cell is ok. But another (a sidebar), has much less space, and I'd only want to display two of the 5 cells.
So the question, then, is what is the correct way of implementing this? I'd like for the "full" version to be the default unless otherwise specified, and only use the limited version if a parameter is passed.
Currently I'd probably use the feature of passing locals to a partial and check if a parameter limited is defined, and if so, skip the last N cells. Am I on a right track, and if so, what kind of a variable should I use (can I use symbols for this)?
Current _line_item.html.erb (that I'm somewhat unhappy with)
<tr>
<td><%= line_item.quantity %>×</td>
<td><%= line_item.product.title %></td>
<td class="item_price"><%= number_to_currency(line_item.total_price, unit: '€') %></td>
<% unless defined? limited %>
<td class="remove_item"><%= button_to 'Remove', line_item, method: :delete %></td>
<% end %>
</tr>
Edit: Added current version.
Yes, you are on the right track. You can do something like
<%= render 'partial_name', limited: true %>
and then in the partial:
<% limited ||= false %> # More explicit as to what default value is
<tr>
<td><%= line_item.quantity %>×</td>
<td><%= line_item.product.title %></td>
<td class="item_price"><%= number_to_currency(line_item.total_price, unit: '€') %></td>
<% unless limited %>
<td class="remove_item"><%= button_to 'Remove', line_item, method: :delete %></td>
<% end %>
</tr>

Using a variables to access elements in each loop

This is hard to explain.
I have a form builder (Question model) that creates form fields that belong to a specific event, these questions appear on the registration page handled by the Registration model.
There are default form fields that always stays the same and then X additional ones created by the form builder. The Question model has the field "db_field", which gets populated with the corresponding db field in the Registration model.
Note that the questions also have position_ids.
What I'm trying to achieve is to get answers display under the corresponding headings in a table in the index page, my view looks like this
<% #questions = Question.where(:event_id => #event.id).order(:position) %>
<table class="table table-striped table-bordered table-condensed">
<tr>
<% #questions.each do |q| %>
<th><%= q.question %></th>
<% end %>
</tr>
<% #event.registrations.each do |r| %>
<tr>
<% #questions.each do |q| %>
<td><%= r.(q.db_field) %></td>
<% end %>
</td>
</table>
So basically I need 'q.db_field', which might be 'title', for instance, to call r.title - if that makes sense.
I've tried a few things, but nothing seems to work.
Thanks in advance,
Charl
You can use Object#send to invoke methods on a given object.
See http://ruby-doc.org/core-2.0/Object.html for more info.
so replacing <%= r.(q.db_field) %> with <%= r.send(q.db_field) %> will allow you to use the field name from the DB. If you need to specify arguments for the method being called, you can pass them in after the method name. Per the docs, method name can either be a symbol or a string, if it is a string, it will be converted to a symbol for you.

Nested forms in rails for existing objects

In my app, I have a page where I want admin users to be able to update a particular characteristic of my "Package" model, which belongs to both the "Order" model and the "Item" model. It's a little complicated, but I basically want to present in a table all of the Packages belonging to a given Item, ordered in a particular way (that's what my packages_for_log method below does), with two blanks for updating the weight of the item. All the updates should ideally be submitted at once, with a single submit button at the bottom of the page. I've attempted a whole bunch of solutions, and my current one is below, but gives this error when I visit the page in my server:
undefined method `actual_lbs' for #<ActionView::Helpers::FormBuilder:0x007ff67df6c9c8>
The error's confusing to me, cause I was hoping that I was calling that method on the package instance, not a helper. Bit confused. At any rate, my code is below. The relevant section of the view:
<% form_for(#item) do |a| %>
<% #item.packages_for_log.each do |p| %>
<%= a.fields_for p do |i| %>
<tr>
<td><%= p.order.name %></td>
<td><%= p.order.processed_notes %></td>
<% if p.order.user %>
<td><%= "#{p.order.user.name.first(3).upcase}-#{p.id}" %></td>
<% else %>
<td><%= p.order.id %></td>
<% end %>
<td>
<%= i.text_field :actual_lbs %>
</td>
<td>
<%= i.text_field :actual_oz %>
</td>
<%= i.hidden_field :true_weight, value: (i.actual_lbs + i.actual_oz/16) %>
</tr>
<% end %>
<% end %>
<% end %>
Relevant section of the package.rb model file:
attr_accessible :order_id, :price, :true_weight, :actual_lbs, :actual_oz
attr_accessor :actual_lbs, :actual_oz # These two are virtual attributes for the above calc
And I added resources :packages to my routes file.
Any idea what I'm doing wrong? It's important to me that I loop through to create a table based on "p" and then edit that same "p" object. Just not sure how to do it. Pretty new to Rails.
I think your problem is this line:
<%= i.hidden_field :true_weight, value: (i.actual_lbs + i.actual_oz/16)
You need to put p.actual_lbs and p.actual_oz
EDIT: By the way, you probably need to move the true weight calculation to your controller action (CREATE action). I don't think :true_weight will get passed as you intended it to, using the above method.

Resources