Nested_attributes dont appear in my params - ruby-on-rails

I'm trying to include nested_form in one of my model new form.
<%= form_for :master_box, url: master_boxes_path do |f| %>
<%= f.label :number %><br>
<%= f.text_field :number %>
<%= f.fields_for :orders do |o| %>
<fieldset>
<%= o.label :number, "Number" %>
<%= o.text_field :number %>
</fieldset>
<% end %>
<br>
<%= f.submit %>
<% end %>
I don't know why when I submit to create my masterbox, my params don't contain orders_attributes.
Here's my models :
class MasterBox < ActiveRecord::Base
has_many :orders
accepts_nested_attributes_for :orders
end
class Order < ActiveRecord::Base
has_many :products
belongs_to :master_box
end
and my strong parameters :
def master_box_params
params.require(:master_box).permit(:number, :number_orders, orders_attributes: [:number])
end
It is pretty simple but I don't understand why I don't have orders_attributes in my params.
I have this instead, only "orders" :

Try changing the first line of your form to:
<%= form_for #master_box, url: master_boxes_path do |f| %>
and also passing through the id in your params:
def master_box_params
params.require(:master_box).permit(:number, :number_orders, orders_attributes: [:id, :number])
end

fields_for :orders creates the orders parameter that you are seeing. This bit of your strong parameters orders_attributes: [:number] is allowing the numbers attribute of orders to be passed through. You should be looking at the orders parameter that you are receiving. That's where the data you want is.

Related

Create multiple new records from checkboxes in form using nested attributes in Rails

I'm trying to come up with a contact form that creates a contact record and potentially multiple location records, if multiple locations are checked in a list of checkboxes. I thought of having all location records created and then destroyed, if they aren't checked. I don't think that's optimal though.
I'm using many to many relationships in the models.
This is what they look like at the moment:
contact.rb
class Contact < ApplicationRecord
has_many :contact_locations, dependent: :destroy
has_many :locations, through: :contact_locations
accepts_nested_attributes_for :contact_locations, allow_destroy: true, reject_if: :empty_location?
private
def empty_location?(att)
att['location_id'].blank?
end
end
location.rb
class Location < ApplicationRecord
has_many :locations, dependent: :destroy
has_many :contacts, :through => :contact_locations
has_many :contact_locations
end
contact_location.rb
class ContactLocation < ApplicationRecord
belongs_to :location
belongs_to :contact
end
contacts_controller.rb
def new
#contact = Contact.new
#locations = Location.all
4.times {#contact.contact_locations.new}
end
private
def contact_params
params.require(:contact).permit(:name, :phone, ..., contact_locations_attributes: [:location_ids])
end
new.html.rb
<%= form_with model: #contact do |f| %>
...
<%= #locations.each do |location| %>
<%= f.fields_for :contact_locations do |l| %>
<%= l.check_box :location_id, {}, location.id, nil %><%= l.label location.name %>
<% end %>
<% end %>
...
<% end %>
Does anyone how to make it work properly?
I'm working on Ruby 2.5.1 and Rails 5.2.1.
Thanks a lot.
I think your solution is the form objects pattern.
You can have something like this:
<%= form_for #user do |f| %>
<%= f.email_field :email %>
<%= f.fields_for #user.build_location do |g| %>
<%= g.text_field :country %>
<% end %>
<% end%>
And convert it in something more readable that permits you to instance the locations inside the registration object, checking the value of the checkboxes.
<%= form_for #registration do |f| %>
<%= f.label :email %>
<%= f.email_field :email %>
<%= f.input :password %>
<%= f.text_field :password %>
<%= f.input :country %>
<%= f.text_field :country %>
<%= f.input :city %>
<%= f.text_field :city %>
<%= f.button :submit, 'Create account' %>
<% end %>
Here you will find how to apply the pattern: https://revs.runtime-revolution.com/saving-multiple-models-with-form-objects-and-transactions-2c26f37f7b9a
I ended up making it work with Kirti's suggestion on the following question:
Rails Nested attributes with check_box loop
It turns out I needed to make a small adjustment in my form's fields_for tag.
Thanks a lot the help!

How do I render this form using fields_for in Rails 5?

I have problem adding a nested model to a form. Specifically, nothing appears in this form section.
new.html.erb
<%= render 'form' %>
_form.html.erb
...
<% fields_for :bigip do |f| %>
<%= f.text_field :bgname %>
<%= f.text_field :bguser %>
<%= f.text_field :bgpassword %>
<% end %>
...
Here are the underlying models and controllers.
pool.rb
class Pool < ApplicationRecord
has_one :bigip, inverse_of: :pool
accepts_nested_attributes_for :bigip, :allow_destroy => true
end
bigip.rb
class Bigip < ApplicationRecord
belongs_to :pool
end
pools_controller.rb
def new
#pool = Pool.new
#pool.build_bigip
end
devil is in details :)
I simply missed "=" in line "<% fields_for :bigip do |f| %>"

rails accept nested atributes for a polymorphic association

I have an error "Can't mass-assign protected attributes: Upload", but I have assigned it to be accessible.
This is a nested form with a polymorphic association.
Models
class Upload < ActiveRecord::Base
attr_accessible :link, :post_id
belongs_to :uploadable, polymorphic: true
end
class Post < ActiveRecord::Base
attr_accessible :description, :title, :uploads_attributes
has_many :uploads, as: :uploadable
accepts_nested_attributes_for :uploads, :reject_if => lambda { |a| a[:content].blank?
}, :allow_destroy => true
end
I tried too put accept_nested ... for :uploadable but tells me dont exist the association
The action new on the controller is this one
def new
#post = Post.new
#post.uploads.new
end
and here is the form for create
<%= form_for [:admin,#post], remote: true, :html => {:multipart => true} do |f| %>
<div class="field">
<%= f.label :title %><br />
<%= f.text_field :title%>
</div>
<div class="field">
<%= f.label :description%><br />
<%= f.text_area :description %>
</div>
<div>
<%= f.fields_for :upload do |builder| %>
<%= render 'upload_fields', f: builder %>
<% end %>
<%= link_to_add_fields "Add Upload", f, :uploads %>
</div>
<div class="actions">
<%= f.submit%>
</div>
<% end %>
The partial ...
<fieldset>
<%= f.label :file %><br />
<%= f.file_field :file %>
<%= f.hidden_field :_destroy %>
<%= link_to "remove", '#', class: "remove_fields" %>
</fieldset>
Dont think the javascript affects, so Im not going to put it here.
How I cna solve "Can't mass-assign protected attributes" on polymorphic asociations ?
Plz need help on this anyone. Cant belive I cant upload files, looks so simple on tutorials, and Its not working, or I get a Can't mass assign orthe upload its not saved ....
Try to use #post.uploads.build instead of #post.uploads.new
The associated model needs to know the identity of her parent to save the relationship.
I recommend you the following railscast: Polymorphic Association.
#uploads_controller.rb
before_filter :load_uploadable
def create
#upload = #uploadable.uploads.new(params[:upload])
....
end
private
def load_uploadable
resource, id = request.path.split('/')[1, 2] # /posts/1
#uploadable = resource.singularize.classify.constantize.find(id)
end
This line inside your view:
<%= f.fields_for :upload do |builder| %>
Should be this:
<%= f.fields_for :uploadable do |builder| %>
Because the association on the Post model is called "uploadable", not "upload".
For nested attributes to work, you will need to specify the model does accept nested attributes for this model, which can be done by putting this line underneath the belongs_to in your model:
accepts_nested_attributes_for :uploadable
And then you will need to make these attributes accessible, which you can do with this:
attr_accessible :uploadable_attributes

Nested forms and accepts_nested_attributes_for

I am trying to understand how to make a nested form of my models but I am struggeling with understanding how and what I need to do it. I have been reading the Rails documentation and looked at the railscast but they just mention the accepts_nested_attributes_for method etc without explaining. Can someone please help?
Per API of Rails it's said:
Nested attributes allow you to save attributes on associated records through the parent...
Example: it shows how we can manage posts through Member, fields_for is used to manage associated fields in a form, passing it the name of the associated model and then loop through all of the associated post records and create a form builder for each of them.
#controller
def new
#member = Member.new
end
#model
class Post < ActiveRecord::Base
belongs_to :member
end
class Member < ActiveRecord::Base
has_many :posts
accepts_nested_attributes_for :posts
end
#form
<%= form_for #member do |f| %>
<%= f.error_messages %>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<%= f.fields_for :posts do |builder| %>
<p>
<%= builder.label :account %><br />
<%= builder.text_area :account %>
</p>
<% end %>
<p><%= f.submit "Submit" %></p>
<% end %>
Rails API: http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html

Nested Form: Resource adds dynamically but doesnt get created?

I am using the nested form gem and i add products dynamically to the form. When i do click "add", another product resource appears but on creation it ERASES the former ones from being created entirely. This is how the scenario goes:
Fill in Location
Choose Date
Fill in Product ( one is already on form)
Add 5 more products (Products 2, 3, 4, 5)
Fill in All Products
"click" Create
Created Product 5
This is how my nested form looks:
<%= nested_form_for #location, :url => products_path(#product) do |f| %>
<%= f.label :business %>
<%= f.text_field :business %>
<%= f.label :address %>
<%= f.text_field :address %>
<%= f.fields_for :product_dates, :url => products_path(#product) do |d| %>
<%= d.label :date %>
<%= d.date_select :date %>
<%= d.fields_for :products, :url => products_path(#product) do |p| %>
<%= p.text_field :name %>
<%= p.text_field :price %>
<%= p.text_field :tag_list %>
<%= p.link_to_remove "Remove Product" %>
<% end %>
<%= d.link_to_add "Add", :products %>
<% end %>
<%= f.submit "Finish" %>
<% end %>
Controller:
class ProductsController < ApplicationController
def new
#location = Location.new
#product = Product.new
product_date = #location.product_dates.build
product_date.products.build
end
def create
#location = Location.create(params[:location])
if #location.save
flash[:notice] = "Products Created."
redirect_to :action => 'index'
else
render :action => 'new'
end
end
Models:
class User < ActiveRecord::Base
devise
attr_accessible :email, :password, :password_confirmation, :remember_me
has_many :products, :dependent => :destroy
end
class Location < ActiveRecord::Base
attr_accessible :address, :business, :product_dates_attributes
has_many :products
has_many :product_dates
accepts_nested_attributes_for :product_dates
end
class ProductDate < ActiveRecord::Base
attr_accessible :date, :products_attributes
belongs_to :location
belongs_to :user
has_many :products
accepts_nested_attributes_for :products
end
class Product < ActiveRecord::Base
attr_accessible :name, :price, :tag_list
belongs_to :user
belongs_to :location
belongs_to :product_date
end
Any Suggestions?
First of all remove the url_for declarations on the fields_for declarations so you get
<%= nested_form_for #location, :url => products_path(#product) do |f| %>
<%= f.label :business %>
<%= f.text_field :business %>
<%= f.label :address %>
<%= f.text_field :address %>
<%= f.fields_for :product_dates do |d| %>
<%= d.label :date %>
<%= d.date_select :date %>
<%= d.fields_for :products do |p| %>
<%= p.text_field :name %>
<%= p.text_field :price %>
<%= p.text_field :tag_list %>
<%= p.link_to_remove "Remove Product" %>
<% end %>
<%= d.link_to_add "Add", :products %>
<% end %>
<%= f.submit "Finish" %>
<% end %>
What is really confusing is your whole routing and params approach. It's just not right. You have a form_for #location with a :url products_path(#product) This will right royally cause issues with the params that are sent back and there in lies the problem.
Stick with routing to location controller not the products controller by removing the products_path(#product) form your nested_form_for declaration and you will find that you will have all the necessary records saved but you will most likely need to change the redirect_to declaration in the locations_controller create action and the same for the update_action.
But why use the products controller at all when you are dealing with a location? Again this just isn't natural or intuitive.
One last thing. Your remove links won't work as you have not added the necessary :dependent => :destroy declaration to the has_many declarations and you are also missing the :reject_if procs and the :allow_destroy => true declarations on the accepts_nested_attributes declarations.
Can I strongly suggest that you
1) Use either the locations controller or the products controller not both
I mean link to get to this form link_to the locations controller and set everything up there or use form_for #product rather than #location and handle everything in the products controller
2) watch the railscasts that this gem is based on very closely
http://railscasts.com/episodes/196-nested-model-form-part-1
http://railscasts.com/episodes/197-nested-model-form-part-2
3) Spend some time learning about how rails form view helpers arrange for the params hash to be organised in the controllers actions. In your case, have a close look at your log file for the parameters that come into the create action as things currently stand.
You will most likely see that the params are not nested as you would exect them to be which is why the nested attributes declaration is not behaving as expected

Resources