Rails nested forms separated - ruby-on-rails

I'm after some direction in created nested forms operating in their own forms (if that makes sense). I've created some diagrams to help explain what I'm after.
I have the nested forms working fine, I'm just interested to find out if the below is possible.
I know I don't have any code to show, but any guidance or assistance would be greatly appreciated as I'm not sure where to start.
Model
class General < ApplicationRecord
belongs_to :operation
belongs_to :report
end
Form
<%= form_with(model: general, local: true) do |f| %>
<h1>General</h1>
<%= f.text_field :first_name %>
<%= f.text_field :last_name %>
<%= f.collection_select :property_id, Property.all, :id, :name %>
<%= f.collection_select :field_id, Field.all, :id, :name %>
<h1>Operations</h1>
<%= f.fields_for :operations do |o| %>
<%= o.text_field :model %>
<%= o.text_field :type %>
<%= o.collection_select :status_id, Status.all, :id, :name %>
<% end %>
<h1>Reports</h1>
<%= f.fields_for :report do |r| %>
<%= r.text_field :first_name %>
<%= r.text_field :last_name %>
<%= r.text_area :comments %>
<% end %>
<%= f.submit 'Submit' %>
<% end %>
This is my standard form using nested forms for Operations and Reports resulting is something like this:
I'm looking to seperate out the Operations and Reports forms and place a link available in the General show route.
The user will click on the Operations link and bring up the nested form to edit.

I'm not sure if I understand you correctly, but I guess you can hide operations and reports using CSS, add two buttons and add an event listener on each of them to display operations form and reports form on click (changing the hidden nested forms CSS).

Related

HABTM association dropdown select

I am trying to create a dropdown select on a form. I have a HABTM association between professors and classrooms:
Classroom Model:
class Classroom < ApplicationRecord
has_and_belongs_to_many :professors
end
Professor Model:
class Professor < ApplicationRecord
has_and_belongs_to_many :classrooms
end
Strong Params:
def classroom_params
params.require(:classroom).permit(:name, :professor_ids => [])
end
I am trying to find a way to use f.select instead of select_tag inside the form. But when I do it, the database does not save the values. This way works:
<%= form_for #classroom do |f| %>
<%= f.label :name %><br>
<%= f.text_field :name %><br>
<% array = Professor.all.map { |professor| [professor.user.name, professor.id] } %>
<%= select_tag "classroom[professor_ids][]", options_for_select(array) %>
<% end %>
But I am trying like that and it is not working:
<%= form_for #classroom do |f| %>
<%= f.label :name %><br>
<%= f.text_field :name %><br>
<% array = Professor.all.map { |professor| [professor.user.name, professor.id] } %>
<%= f.select :professor_ids, options_for_select(array) %>
<% end %>
The view works correctly but when I submit the form, the value doesn't go to to the classroom_params. I tried to debug it stopping the controller after the submit and I got this:
The params came correctly with all the information submitted, but the classroom_params came missing the professor_ids.
Is there a way to do this dropdown using f.select?
You whitelisted the array of 'professor_ids', but your 'select' input returns 1 string ("prefessor_ids" => "2" from you screenshot). Maybe you want to set the select as 'multiple'? (I have not tested it, but i think params will be whitelisted correctly after that)
<%= form_for #classroom do |f| %>
<%= f.label :name %><br>
<%= f.text_field :name %><br>
<%= s.collection_select :professor_ids, Professor.all, :id, :name, multiple: true %>
<% end %>
where
class Professor
...
delegate :name, to: :user
end
Update
You probably don't have 'cfg' variable in your controller action.

Rails way to edit multiple attributes on a model from a view

I have a model Person with the following attributes:
:name, :state, :age, :town
Let's say I want to be able to edit all of the attributes except for :name from that Person's edit view. Is there a "rails" way to do this, and if so what would I write without looping through each attribute and creating a form?
Right now, I've got something like this:
<%= form_for #person do |person_form| %>
<%= person_form.fields_for :age do |age_form| %>
<%= age_form.text_field :age %>
<% end %>
<% end %>
And I would do that for each attribute.
It would be just a standard form since the object you're wrapping the form around has all of the attributes.
<%= form_for #person do |f| %>
<%= f.text_field :state %>
<%= f.text_field :age %>
<%= f.text_field :town %>
<%= f.submit %>
<% end %>
Of course, you can add labels and whatever else you need to the form.

Form for adding two database entries in rails

I'm trying to create a database with two types of data.
1) Apartment buildings with their own attributes (ex. address)
2) Units (belonging to buildings) with their own attributes (ex. price, size)
I was wondering if I could have a page with a form for both databases?
Ex. A form to create a new building, and add the new unit information directly on the page.
<%= form_for(#building) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :address %>
<%= f.text_field :address %>
<%= f.label :contact %>
<%= f.email_field :contact %>
<br>
<%= form_for(#unit) do |f| %>
<%= f.label :bedrooms %>
<%= f.text_field :bedrooms %>
<%= f.label :price %>
<%= f.text_field :price %>
<%= f.label :building_id %>
<%= f.text_field :building_id %>
<br>
<%= f.submit "Create building", class: "btn btn-large btn-primary" %>
<% end %>
<% end %>
But i understand this only creates the new building, not the units associated with them.
You cannot have a form inside a form - you will have to use what's called nested attributes.
I assume a building has many units, and a unit belongs to a building. Then your code needs to be as follows:
Building
class Building < ActiveRecord::Base
attr_accessible :units_attributes
has_many :units, :dependent => :destroy
accepts_nested_attributes_for :units, :reject_if => lambda { |a| a[:bedrooms].blank? }, :allow_destroy => true
end
Unit
class Unit < ActiveRecord::Base
belongs_to :building
end
Form
Note the fields_for form helper (pretty self explanatory):
Put the following inside your form:
<%= f.fields_for :units do |builder| %>
<%= builder.label :bedrooms %>
<%= builder.text_field :bedrooms %>
# etc
<% end %>
When you reload the page, you will see that your form probably doesn't contain any fields for units just yet. This is because the building instance inside the form does not have any units yet - do the following inside your controller to see unit fields:
3.times { #building.units.build }
Now you should see three sets of unit fields inside the form. If you fill them in and submit the form, they will be saved as children of that building - if you leave them blank, they won't. :reject_if => lambda { |a| a[:bedrooms].blank? } inside the building model takes care of that: If the bedrooms field is left blank, the unit will not be saved.
This is all you need!
If this was a bit too fast, just watch this railscast.
Also, check out this awesome gem called nested_forms, which gives you links to add and remove nested form fields on the fly (allowing you to get rid of that cumbersome extra line in your controller).

Formtastic Confused on Has One Relationships

I'm a bit stuck on a 'has_one' and 'belongs_to' relationship and getting it to properly display in Formtastic. I have a person model that has one picture (a profile picture). I want the user to be able to select the picture using radio buttons. So far, I have:
<% form.inputs do %>
<%= form.input :picture, :as => :radio, :collection => #pictures %>
<% end %>
However, this fails (because the foreign key is stored on the 'belongs_to' side of associations in Rails. Any suggestions?
Ended up using custom controller code to fix. Use a variety of filters, etc.
Came across this in the "related" sidebar. I think this is a good use case for nested attributes -- from the Formtastic README:
Nested forms are also supported (don’t forget your models need to be setup correctly
with accepts_nested_attributes_for). You can do it in the Rails way:
<%= semantic_form_for #post do |form| %>
<%= form.inputs :title, :body, :created_at %>
<%= form.semantic_fields_for :author do |author| %>
<%= author.inputs :first_name, :last_name, :name => "Author" %>
<% end %>
<%= form.buttons %>
<% end %>
Or the Formtastic way with the :for option:
<%= semantic_form_for #post do |form| %>
<%= form.inputs :title, :body, :created_at %>
<%= form.inputs :first_name, :last_name, :for => :author, :name => "Author" %>
<%= form.buttons %>
<% end %>

Using accepts_nested_attributes_for with a belongs_to association, and using find_or_create_by_attr behaviour

I am building a Rails application which allows a user to create an object that refers to multiple other models, creating them if they do not exist, and just associating to ones that already exist:
# app/models/upload.rb
class Upload < AR:B
belongs_to :user
belongs_to :observed_property
belongs_to :sensor
accepts_nested_attributes_for :observed_property, :sensor
validates_presence_of :observed_property, :sensor
end
(The associations to sensor and observed_property are just one-way, there are no has_many returning.)
The Controller is nothing special, just a standard RESTful seven, and I would think it would be possible to do this properly while keeping most of the logic in the Model.
Instead of having the user fill out multiple different forms and then reference those objects separately, I have attempted to use accepts_nested_attributes_for to embed them into the Upload form using fields_for:
# app/views/uploads/new.html.erb
<% form_for #upload, :url => user_uploads_path(#user) do |f| %>
<%= f.error_messages %>
<% f.fields_for :observed_property do |builder| %>
<fieldset>
<legend>Observed Property</legend>
<p><%= builder.label :_id, "Observed Property ID" %><br />
<%= builder.text_field :_id %></p>
<p><%= builder.label :description %><br />
<%= builder.text_area :description, :rows => 5 %></p>
</fieldset>
<% end %>
<% f.fields_for :sensor do |builder| %>
<fieldset>
<legend>Sensor</legend>
<p><%= builder.label :_id, "Sensor ID" %><br />
<%= builder.text_field :_id %></p>
<p><%= builder.label :description %><br />
<%= builder.text_area :description, :rows => 5 %></p>
</fieldset>
<% end %>
<%= f.submit "Submit", :class => "button" %>
<% end %>
This however does not work, as no form is displayed for the fields_for. I tried to apply what was mentioned in this answer, but the model would just fail to save, citing missing associations.
I have attempted a few hackish things such as overriding the sensor= and observed_property= methods and caching the hashes for before_save, but that doesn't really feel like the right way to do things.
I ended up using the following solution, and it does seem to work. I created a gist to hold the solution with a matching spec to define the behaviour I was seeking.
http://gist.github.com/437939

Resources