I am using a link from an index page that has a group of nested records (row) that I need to update all at once. The link goes to an edit action that I need to make update the attributes of nested records (prisms).
I tried using the simple_form gem methods for nested models. It gives me a field for all of the objects, when I only want one field to enter a value to them all. The builder from that looks usable, but I don't know how to use it to update the fields. Either way, the form isn't right.
I have tried every variation of form_for and fields_for I could find on Google to develop the edit form. It looks like I'm the only one on Earth trying to solve this problem.
This is how I have my routes set up:
resources :gardens, shallow: true do
resources :prisms
resources :rows
Here is how my garden model is now:
class Garden < ApplicationRecord
mount_uploader :picture, ImageUploader
belongs_to :user
has_one :photo
has_many :rows, :dependent => :destroy
has_many :prisms
geocoded_by :address
after_validation :geocode
after_commit :populate_garden!
def id
self[:id]
end
def populate_garden!
# row 0
(0..length-1).each do |i|
Row.create(row_num: i, garden_id: id)
end
end
end
The garden model creates my rows through the populate_garden! method.
Here is the row model:
class Row < ApplicationRecord
belongs_to :garden
has_many :prisms, :dependent => :destroy
accepts_nested_attributes_for :prisms
after_commit :populate_rows
def id
self[:id]
end
def populate_rows
# row 0
(0..garden.width-1).each do |i|
Prism.create(:row_id => self.id, :row_num => self.row_num, :col_num => i, :garden_id => self.garden_id)
end
end
end
The row model creates prisms in the populate_rows method.
Here is the prism model:
class Prism < ApplicationRecord
belongs_to :row
belongs_to :garden
include RankedModel
ranks :column_order
end
Here is the table from my index.html.erb that I click to open the edit action.
<table>
<% @rows.each_with_index do |gardenrow, index| %>
<% @rows.select { | row | row.row_num == index}.each do |row| %>
<td class="prism-cols">
<%= link_to 'Edit Row', edit_row_path(row), class:"dark-link" %>
<br /><i class="fas fa-arrow-down"></i>
</td>
<% end %>
<% end %>
</table>
The row passes nicely into the edit action, and I currently have this incorrect form:
<h1>The row brought into this form page is: </h1>
<%= @row.inspect %>
<div class="container">
<%= simple_form_for @row do |m| %>
<%= m.simple_fields_for :prisms do |p| %>
<%= p.input :crop_name %>
<% end %>
<%= m.button :submit %>
<% end %>
</div>
The rows_controller update method looks like this:
def update
@row = Row.find(params[:row_id])
@row.prisms.build
redirect_to root_path
end
I need one form field for crop_name that will change all of the prisms in the selected row with a single submit. I don't have any problems updating one prism at a time through an edit action on the prism. The difficulty I'm having is working through the nesting of prisms inside of a specific row.
With the help of my mentor below I was able to develop a form that works with the controller to make this work. Here is the updated code for later use with this type of problem.
Here is the form data:
<%= form_tag({controller: "rows", action: "update"}, method: "patch") %>
<%= label_tag(:crop_name, "Crop Name") %>
<%= text_field_tag(:crop_name) %>
<%= hidden_field_tag(:row_id, @row.id) %>
<%= submit_tag("submit") %>
Here is the controller update method:
def update
@row = Row.find(params[:id])
@garden = Garden.find_by_id(:garden_id)
@row.prisms.each do |p|
p.crop_name = params[:crop_name]
p.save!
end
redirect_to :controller => 'gardens', :action => 'show', id: @row.garden_id
end
Thanks for the help. I don't think I could have figured this out from the documentation alone.
If I'm understanding correctly, I think simple_form
may be limiting you. A basic ruby form may do what you want. I'm not 100% sure what the best way is to do a simple_form
on nested fields but this stackoverflow answer may be able to help more.
Using a basic ruby form You want a form that has one field. When submitted, it will take the value from the submitted form and update that field for all prisms of that row. I would recommend digging more into the basics of ruby forms for this kind of scenario and then do something like this.
// html.erb
<%= form_tag({controller: "rows", action: "update_prism_crop_name"}, method: "post", class: "nifty_form") %>
<%= label_tag(:crop_name, "Crop name") %>
<%= text_field_tag(:crop_name) %>
<%= hidden_field_tag(:row_id, @row.id) %>
<%= submit_tag("Submit") %>
<% end %>
// rows_controller
def update_prism_crop_name
@row = Row.find(params[:row_id])
@row.prisms.each do |prism|
prism.crop_name = params[:crop_name]
prism.save!
end
# other redirect stuff
end
The form_tag explicitly calls out an action but I have to imagine that you'll need to build a route for this custom action as well.
I haven't tested any of this and I'm a bit rusty in rails but I believe something like this would work.