nested fields_for Rails 4 - ruby-on-rails

i have problem permit about double nested fields_for on rals 4. example relationship:
Service - > has_many :product_services
accepts_nested_attributes_for :product_services, allow_destroy: true
Product Service -> has_many :foto_product_services
accepts_nested_attributes_for :foto_product_services, allow_destroy: true
Service -> new.html.slim
= form_for #service, :html => {:multipart => true} do |f|
= f.fields_for :product_services do |builder|
= render 'field_product', f: builder
= f.submit
Service -> _field_product.html.slim
= f.text_field :price, :class => 'text_field input-lg width-100'
= f.fields_for :foto_product_services do |builder|
= builder.file_field "avatar[]", type: :file, multiple: true
Permit Params in my Service Controller
def service_params
params.require(:service).permit(:service_category_id, :title, :description, :product_services_attributes => [:title, "_destroy"], :foto_product_services_attributes => [:avatar])
end
When I click button submit after selected foto product, I get error unpermitted param :foto_product_services_attributes.

You have deep nested attributes, so the foto_product_services_attributes should be inside the product_services_attributes:
params.require(:service).permit(:service_category_id, :title, :description, :product_services_attributes => [:title, "_destroy", :foto_product_services_attributes => [:avatar]])

Related

Rails - Parameters not being saved when using nested forms in Cocoon

I've followed Cocoon's instructions for creating a nested form for a has_many association but there's one thing that I can't seem to figure out. I'm able to add an existing genre to my project but when it comes to creating a completely new one the parameters for my genres aren't being permitted. When I refer to my rails console to debug the issue this is the message I receive upon update:
Unpermitted parameters: genre_attributes
What's strange is I've permitted both my join table genreships and my genre model along with having my movie model accept their nested attributes but still no luck. There has to be something I'm not doing in my movie_params method but not able to find what. I've literally tried to permit every possible attribute within this method and completely out of ideas on what could be the solution
Models
class Movie < ActiveRecord::Base
has_many :genreships
has_many :genres, through: :genreships
accepts_nested_attributes_for :genres, :reject_if => :all_blank, :allow_destroy => true
accepts_nested_attributes_for :genreships, :reject_if => :all_blank, :allow_destroy => true
extend FriendlyId
friendly_id :title, use: :slugged
end
class Genreship < ActiveRecord::Base
belongs_to :movie
belongs_to :genre
accepts_nested_attributes_for :genre, :reject_if => :all_blank
end
class Genre < ActiveRecord::Base
has_many :genreships
has_many :movies, through: :genreships
extend FriendlyId
friendly_id :name, use: :slugged
end
Movies Controller
def movie_params
params.require(:movie).permit(:title, :release_date, :summary, genreships_attributes: [:id, :genre_id, :_destroy], genres_attributes: [:id, :_destroy, :name])
end
Form
= simple_form_for #movie do |f|
.field
= f.input :title
.field
= f.input :release_date, label: 'Release Date', order: [:month, :day, :year], start_year: 1901
.field
= f.input :summary, as: :text
#genres
= f.simple_fields_for :genreships do |genreship|
= render 'genreship_fields', :f => genreship
= link_to_add_association 'add a genre', f, :genreships
.actions = f.submit 'Save', class: 'btn btn-default'
Genreship Partial
.nested-fields
#genre_from_list
= f.association :genre, :collection => Genre.order(:name), :prompt => 'Choose an existing genre'
= link_to_add_association 'or create a new genre', f, :genre
= link_to_remove_association "remove genre", f
Genre Partial
.nested-fields
= f.input :name
Here's what's shown in the rails console right after posting a new movie:
Started POST "/movies" for 127.0.0.1 at 2014-11-19 08:17:42 -0500
Processing by MoviesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"2/wqXhn/x73AdOOrSo49Q/OPAmrcVk0rLViJJNpIhps=", "movie"=>{"title"=>"", "release_date(2i)"=>"11", "release_date(3i)"=>"19", "release_date(1i)"=>"2014", "summary"=>"", "genreships_attributes"=>{"1416403056574"=>{"genre_attributes"=>{"name"=>"Comedy"}, "genre_id"=>"", "_destroy"=>"false"}}}, "commit"=>"Save"}
Unpermitted parameters: genre_attributes
You use genre_attributes while genres_attributes (plural form) is defined in your controller. Change it to:
def movie_params
params.require(:movie).permit(:title, :release_date, :summary, genreships_attributes: [:id, :genre_id, :_destroy], genre_attributes: [:id, :_destroy, :name])
end
I created a solution that in a sense deviates from Nathan's example code somewhat but gets the job done nonetheless. Simply moving this line from genreship_fields.html.slim to _form.html.slim did the trick:
link_to_add_association 'create a new genre', f, :genres
My partials now look like this:
Form
= simple_form_for #movie do |f|
.field
= f.input :title
.field
= f.input :release_date, label: 'Release Date', order: [:month, :day, :year], start_year: 1901
.field
= f.input :summary, as: :text
#genres
= f.simple_fields_for :genreships do |genreship|
= render 'genreship_fields', :f => genreship
| #{link_to_add_association 'add a genre', f, :genreships} | #{link_to_add_association 'create a new genre', f, :genres}
.actions = f.submit 'Save', class: 'btn btn-default'
Genreship Partial
.nested-fields
#genre_from_list
= f.association :genre, :collection => Genre.order(:name), :prompt => 'Choose an existing genre'
= link_to_remove_association "remove genre", f
Genre Partial
.nested-fields
= f.input :name
= link_to_remove_association "remove form", f

Rails 3.2 has_many :as polymorphic, Simple Form, simple_fields_for

Trying to save some images in my product form. I'm excpecting paremeters where I would have images_attributes being a part of "product". When I make parameters like that in the console and create a Product, the images actually save.
class Product < ActiveRecord::Base
extend FriendlyId
friendly_id :name, use: :slugged
attr_accessible :description, :name, :category_ids, :brand_ids, :image_ids, :images_attributes
has_many :images, :as => :imageable
accepts_nested_attributes_for :images
end
class Image < ActiveRecord::Base
belongs_to :imageable, :polymorphic => true
attr_accessible :name, :file
mount_uploader :file, ImageUploader
end
= simple_form_for(#product, :html => {:multipart => true}) do |f|
= f.error_notification
.form-inputs
= f.input :name
= f.input :description
= f.association :categories, as: :check_boxes
= f.association :brands, as: :check_boxes
= f.association :images
= simple_fields_for :images do |i|
= i.input :file, as: :file
= i.input :name
.form-actions
= f.button :submit
# GET /products/new
# GET /products/new.json
def new
#product = Product.new
#product.images.build
respond_to do |format|
format.html # new.html.erb
format.json { render json: #product }
end
end
{
"utf8"=>"✓",
"authenticity_token"=>"vvXZFh9sJivA3i4Y0rx9i/oqLwKByrExgYisfdj/N78=",
"product"=> {
"name"=>"sxsad",
"description"=>"saasd",
"category_ids"=>[""],
"brand_ids"=>[""],
"image_ids"=>[""]
},
# should be images_attributes and come straight after image_ids?
"images"=>{
"name"=>"sdfsdfsdf"
},
"commit"=>"Create Product"
}
Once i've got it working for one image I will look into something like Cocoon for multiple images. Any thoughts on where this could be going wrong would be greatly appreciated :).
You should simply write:
= f.simple_fields_for :images do |i|

Ruby on Rails, form_for, paperclip, and mass-assignment of protected parameters

I have been developing a rails app that uploads and processes images. Images, along with other string information is submitted via a form_for. I've been researching this topic for about 16 hours now and no solution has worked. Honestly it's like rails isn't even reading my code.
One Processmodel has many Assets, where an Asset is just a model to hold one image file. When creating processmodels, I can never access the asset, always recieving the cannot mass-assign attirbutes: assets_attributes
Completed 500 Internal Server Error in 13ms
ActiveModel::MassAssignmentSecurity::Error (Can't mass-assign protected attributes: asset):
app/controllers/process_controller.rb:20:in `new'
app/controllers/process_controller.rb:20:in `create'
-
This form is used in new.html.erb
<%= semantic_form_for #processmodel, :url => { :action => 'create' }, :html => { :multipart => true } do |f| %>
<%= f.input :batch, :as => :string, :name => "Batch" %>
<%= f.input :batchset, :as => :string, :name => "Batchset" %>
<%= f.input :numSlots, :as => :number, :name => "Number of slots" %>
<%= f.input :key, :as => :file, :name => "Key" %>
<%= f.semantic_fields_for :asset do |asset| %>
<%= asset.input :asset, :as => :file, :label => "Image" %>
<% end %><br />
<%= f.submit %>
<% end %>
-
class Processmodel < ActiveRecord::Base
attr_accessible :user_id, :batch,
:batchset, :numSlots,
:key,:assets_attributes
attr_accessor :key_file_name
has_many :assets, :dependent => :destroy
belongs_to :user
has_attached_file :key
# :url => Rails.root.join('/assets/readimages/:basename.:extension'),
# :path => Rails.root.join('/assets/readimages/:basename.:extension'),
accepts_nested_attributes_for :assets, :allow_destroy => true
.
.
.
end
-
require 'RMagick'
class Asset < ActiveRecord::Base
attr_accessible :results_string,
:name,
:ambiguous_results,
:image
belongs_to :batch_element
belongs_to :processmodel
has_attached_file :image
validates_attachment_presence :image
end
-
class ProcessController < ApplicationController
def create
#Processmodel = Processmodel.new(params[:processmodel])
#Processmodel.save
all_img = Array.new(#processmodel.assets.all)
respond_to do |format|
if #processmodel.beginRead(...)
redirect_to :action => 'results_main', :controller => 'results'
else
format.html { render action: "new" }
end
end
end
-
def new
#processmodel = Processmodel.new
#5.times{#processmodel.assets.build}
respond_to do |format|
format.html #new.html.erb
end
end
Am requesting an ideas on how to fix this and get my app working.
You need to update your database migration. Run:
rails g migration AddIdToAsset processmodel_id:integer
rake db::migrate
You've called your attached file :image here:
has_attached_file :image
But you call it :asset in your view:
<%= asset.input :asset, :as => :file, :label => "Image" %>
To fix, just change this line to
<%= asset.input :image, :as => :file, :label => "Image" %>

Rails Nested Attribute Retrieval in Controller

Here's the structure of my code. I have a video attached with each cresponse and as far as I can tell I have been successful in uploading it. The problem comes when I need to convert it after the structure is saved. I wish to access the newly updated nested attribute (see lesson_controller) but am not sure how to go about doing so.
Many thanks!
Pier.
lesson.rb
class Lesson < ActiveRecord::Base
has_one :user
has_many :comments, :dependent => :destroy
has_many :cresponses, :dependent => :destroy
acts_as_commentable
accepts_nested_attributes_for :comments, :reject_if => lambda { |a| a[:body].blank? }, :allow_destroy => true
accepts_nested_attributes_for :cresponses
and here's cresponse.rb
class Cresponse < ActiveRecord::Base
belongs_to :lesson
attr_accessible :media, :accepted, :description, :user_id
# NOTE: Comments belong to a user
belongs_to :user, :polymorphic => true
# Paperclip
require 'paperclip'
has_attached_file :media,
:url => "/system/:lesson_id/:class/:basename.:extension",
:path => ":rails_root/public/system/:lesson_id/:class/:basename.:extension"
Here's my HTML view
<% #cresponse = #lesson.cresponses.build %>
<%= form_for #lesson, :html => { :multipart => true } do |f| %>
<td class="list_discussion" colspan="2">
<div class="field">
<%= f.fields_for :cresponses, #cresponse, :url => #cresponse, :html => { :multipart => true } do |builder| %>
Upload : <%= builder.file_field :media %><br />
Description : <%= builder.text_field :description %>
<%= builder.hidden_field :user_id , :value => current_user.id %>
<% end %>
</div>
</td>
and here's lesson_controller.rb - update
def update
#lesson = Lesson.find(params[:id])
respond_to do |format|
if #lesson.update_attributes(params[:lesson])
**if #lesson.cresponses.** <-- not sure how to find the cresponse that I need to convert
puts("Gotta convert this")
end
Think I should answer my own question ..
Basically for lesson_controller.rb
params[:lesson][:cresponses_attributes].values.each do |cr|
#cresponse_user_id = cr[:user_id]
#cresponse_description = cr[:description]
if cr[:media]
.... and so on

activeadmin: adding delete for a nested resource

I have a infrastructure object composed for many datacenters. In the apps/admin/infrastructures.rb I have the following code:
form do |f|
f.inputs "Infrastructure details" do
f.input :name
f.has_many :datacenters do |datacenter_form|
datacenter_form.input :name
end
end
f.buttons
end
I can add datacenters with no problems but I don't know how I can delete it from infrastructure form.
Sep 2017 Update:
Rails 5.1.4, ActiveAdmin 1.0.0
Append :id and _destroy in permit_params along with other attributes from the model e.g. :name in your case. Then provide the :allow_destroy option in f.has_many too. Other requirements remain the same; like adding allow_destroy: true in accepts_nested_attributes_for.
Final look:
ActiveAdmin.register Infrastructure do
permit_params :name, datacenters_attributes: [:id, :_destroy, :name]
form do |f|
f.inputs "Infrastructure details" do
f.input :name
f.has_many :datacenters, heading: false,
allow_destroy: true,
new_record: false do |datacenter_form|
datacenter_form.input :name
end
end
f.buttons
end
end
ActiveAdmin Reference
This worked for me:
i.input :_destroy, as: :boolean
and in the Model remember to add :allow_destroy :
accepts_nested_attributes_for :images, allow_destroy: true
Solved adding the following line:
datacenter_form.input :_destroy, :as => :boolean, :required => false, :label => 'Remove'
The code looks like:
form do |f|
f.inputs "Infrastructure details" do
f.input :name
f.has_many :datacenters do |datacenter_form|
datacenter_form.input :name
datacenter_form.input :_destroy, :as => :boolean, :required => false, :label => 'Remove'
end
end
f.buttons
end
If you cant destroy the object nested. You need to put :_destroy in your app/admin/object.rb permit_params
permit_params :id,:name, :cod, :_destroy
I hope this will be helpful (I've changed my code to suit your example, so I hope there are no typos here):
form do |f|
f.inputs "Infrastructure details" do
f.input :name
f.has_many :datacenters do |datacenter_form|
datacenter_form.inputs :datacenters do
datacenter_form.input :name
end
datacenter_form.buttons do
link_to "Delete", admin_datacenter_path(datacenter_form.object), method: "delete", class: "button" unless datacenter_form.object.new_record?
end
end
end
f.buttons
end
and the controller method should be defined in datacenters.rb
controller do
def destroy
#datacenter = Datacenter.find(params[:id])
#datacenter.destroy
redirect_to edit_admin_retailer_path(#datacenter.infrastructure)
end
end
This should work:
datacenter_form.label :_delete
datacenter_form.check_box :_delete
This adds a checkbox for each nested object which will delete the object if checked.
Don't forget to add the following to your parent model
has_many :child_name, :dependent => :destroy

Resources