nested form "Can't mass-assign protected attributes" - ruby-on-rails

I have 3 models; Quote, Item, and Product.
My quote/new.html.erb is set up to render a partial which contains the item form, and in that item form a partial is rendered to choose a product.
the error: ActiveModel::MassAssignmentSecurity::Error in QuotesController#create
"Can't mass-assign protected attributes: products"
(I edited out irrelevant stuff in the following)
Quote.rb
class Quote < ActiveRecord::Base
attr_accessible :items_attributes
has_many :items, :dependent => :destroy
accepts_nested_attributes_for :items
end
Item.rb
class Item < ActiveRecord::Base
attr_accessible :price, :product_attributes
belongs_to :quote
belongs_to :product
accepts_nested_attributes_for :product
end
Product.rb
class Product < ActiveRecord::Base
attr_accessible :name, :item_make
has_many :items
accepts_nested_attributes_for :items
end
new.html.erb
<%= simple_nested_form_for #quote do |m| %>
<%= m.simple_fields_for :items, :html => { :multipart => true } do |quoteform| %>
<%= render "form", f: quoteform %>
<% end %>
<%= m.link_to_add "Add an item", :items %>
<%= m.button :submit %>
<% end %>
_form.html.erb
<%= f.simple_fields_for :products, :html => { :multipart => true } do |x| %>
<% render "layouts/styleselect", g: x %>
<% end %>
_styleselect.html.erb
<% g.hidden_field :item_make, :value => #item.make %>
<%= g.input :name, collection: Product.where(:item_make => 1), label: false, input_html: {:id=>"sst_style"} %>
So basically the nested form goes Quote->Item->Product, but item belongs to product, which maybe is causing the problem? I tried adding product_attributes or products_attributes to both the item model and the quote model, and the same with accepts_nested_attributes_for product(s).
Any help would be appreciated, thanks.

Looks like you need to make products singular.
<%= f.simple_fields_for :product, :html => { :multipart => true } do |x| %>
<% render "layouts/styleselect", g: x %>
<% end %>
You currently have:
<%= f.simple_fields_for :products, :html => { :multipart => true } do |x| %>

Related

Name error while rendering

I need to render a sub form in my main form and i tried to render it in the main form
this issue has relation with three models
Class PrdItem model< ActiveRecord::Base
has_one :prd_allisland_flat_delivery, dependent: :destroy, inverse_of: :prd_item
accepts_nested_attributes_for :prd_allisland_flat_delivery, allow_destroy: true
has_many :prd_province_vise_deliveries, dependent: :destroy, inverse_of: :prd_item
accepts_nested_attributes_for :prd_province_vise_deliveries, allow_destroy: true
end
Class PrdAllislandFlatDelivery < ActiveRecord::Base
belongs_to :prd_item
end
Class PrdProvincevisedelivery < ActiveRecord::Base
belongs_to :prd_item
end
In prd_item/new.html.erb the _form.html.erb is rendered
in that _form.html.erb
i wrote this code fragment
<%= p.fields_for :prd_allisland_flat_deliveries do |i| %>
<%= render(:partial => 'prd_allisland_flat_delivery_field', :locals => {:f => p})%>
<% end %>
this is a fragment of that form partial
<div class="col-md-4">
<%= f.text_field(:delivery_period, {placeholder: '0', class: 'form-control input_border input_field_text_align_right'})%>
</div>
that gives me
undefined method
`delivery_period' for #
error
in _form.html.erb
<%= p.fields_for :prd_allisland_flat_deliveries do |i| %>
<%= render(:partial => 'prd_allisland_flat_delivery_field', :locals => {:f => i})%>
<% end %>
and
<%= f.text_field(:delivery_period, {placeholder: '0', class: 'form-control input_border input_field_text_align_right'})%>

New action with form in one_of_many-to-one association

Can't figure out how to render new action. When I'm trying to load new action, I get next error - undefined method 'hotel' for nil:NilClass
My trip, hotelseller and hotel models
class Trip < ActiveRecord::Base
has_many :hotelsellers, :dependent => :destroy
attr_accessible :hotelsellers_attributes, :description
accepts_nested_attributes_for :hotelsellers, :reject_if => lambda { |a| a.blank? }
end
class Hotelseller < ActiveRecord::Base
belongs_to :trip
has_one :hotel
attr_accessible :hotel_attributes,
accepts_nested_attributes_for :hotel, :reject_if => lambda { |a| a.blank? }
end
class Hotel < ActiveRecord::Base
belongs_to :hotelseller
attr_accessible :description
end
My controller trips_controller.rb
def new
hotelseller_first = #trip.hotelsellers.build(five_stars: false)
hotelseller_second = #trip.hotelsellers.build(five_stars: true)
#hotel = #trip.hotelsellers.build.build_hotel
end
My form new.html.erb
<%= simple_form_for(#trip) do |f| %>
<%- f.description %>
<%= f.fields_for :hotelsellers do |builder| %>
<% if builder.object.five_stars %>
First hotel
<%= builder.hidden_field :five_stars, value: true %>
<% else %>
Second hotel
<%= builder.hidden_field :five_stars, value: false %>
<% end %>
<%= builder.descritpion %>
<%= builder.simple_fields_for :hotel do |builder| %>
<%= builder.description %>
<% end %>
<% end %>
<% end %>
I should change builder.simple_fields_for :hotel to builder.simple_fields_for :hotel_attributes

nested image model objects not showing on edit action

I've been ignoring this problem for a while but I can't any longer. My nested image model objects, product_images are not showing when I render a product's edit view. Due to this my application calls an error saying that the image is nil when I try to render the show view.
Why arent my nested product images appearing? I'm using paperclip and s3.
I need the nested images form to be editable, everything works when a new product is created, the editing is the only problem. The nil exception during the show action is just related to the edit action malfunction
Below is my code:
models ##
class ProductImage < ActiveRecord::Base
attr_accessible :product_id, :photo, :image_width, :image_height
belongs_to :product
has_attached_file :photo, :styles => { :small => "150x150>"}, :dependent => :destroy
validates_attachment_presence :photo
validates_attachment_size :photo, :less_than => 5.megabytes
validates_attachment_content_type :photo, :content_type => ['image/jpg', 'image/jpeg', 'image/png', 'image/gif']
after_post_process :save_image_dimensions
def save_image_dimensions
geo = Paperclip::Geometry.from_file(photo.queued_for_write[:original])
self.image_width = geo.width.to_i
self.image_height = geo.height.to_i
end
def sized_different?
if image_width < image_height
true
else
false
end
end
end
class Product < ActiveRecord::Base
attr_accessible :taxable, :shippable, :page_name, :tact_code, :manu_code, :body_code, :name, :alert, :price, :description, :colors_attributes, :sizes_attributes, :extras_attributes, :restraints_attributes, :product_images_attributes
validates_presence_of :page_name
validates_presence_of :price
validates_presence_of :description
validates_presence_of :name
has_many :product_images, :dependent => :destroy
has_many :restraints, :dependent => :destroy
has_many :colors, :dependent => :destroy
has_many :sizes, :dependent => :destroy
has_many :extras, :dependent => :destroy
accepts_nested_attributes_for :colors, :sizes, :extras, :restraints, :product_images
end
controller
def index
#products = Product.search(params)
unless current_cart.nil?
#cart = current_cart
else
#cart = nil
end
end
def new
#product = Product.new
#product.product_images.build
end
def create
#product = Product.new(params[:product])
if #product.save
render :index
else
render :new
end
end
def edit
#product = Product.find(params[:id])
#cart = current_cart
end
def show
#product = Product.find(params[:id])
#cart = current_cart
end
def update
#product = Product.find(params[:id])
if #product.update_attributes!(params[:product])
render :index
else
render :edit
end
end
end
_form view
<%= form_for #adminproduct, validate: true, html:{ multipart: true} do |f| %>
<div class="span3 field">
<ul class="unstyled">
<li><%= f.text_field :name, :placeholder => "Product name" %></li>
<li><%= f.text_field :manu_code, :placeholder => "Manufacturer code" %></li>
<li><%= f.text_field :alert, :placeholder => "Alert, example: Save 10%" %></li>
<li><%= f.text_field :price, :placeholder => "Base price" %></li>
<li><%= f.text_area :description, :placeholder => "Product description", :size => "30x10" %></li>
</ul>
</div>
<div class="span6 offset1">
<ul class="unstyled">
<li><%= f.check_box :taxable %>Item can be taxed</li>
<li><%= f.check_box :shippable%>Item can be standard shipped</li>
<li><br /><b>Choose product images:</b></li>
(the first image will be the product's main image)<br/>
<%= f.fields_for :product_images do |p|%><%= render 'product_image_fields', f: p %><% end %>
<li><%= link_to_add_fields "Add image", f, :product_images %></li>
Any insight is appreciated.
edit
product images partial
<fieldset>
<%= f.file_field :photo %>
<%= f.hidden_field :_destroy %>
<%= link_to "remove", '#', class: "remove_fields" %>
</fieldset>
On the products_controller, modify the edit action to include product_images so that accepts_nested_attributes_for knows which images to update.
def edit
#product = Product.includes(:product_images).find(params[:id])
# ...
end
I believe you need to call your partial like this:
<%= render partial: 'product_image_fields', locals: {f: p} %>
If it does not work, please paste in your original question your 'product_image_fields' file and the error message from your console
--
Ok this is your partial
<fieldset>
<%= f.file_field :photo %>
<%= f.hidden_field :_destroy %>
<%= link_to "remove", '#', class: "remove_fields" %>
</fieldset>
A your problem is empty product_image upload inputs. Well you using file_field, which produce input type=file, and HTML won't allow you to put a value in this kind of fields. In other words: you cannot load value from a database to a file_field.
This is my advise:
Change your partial to output what comes from the database. This is just to verify and confirm the data arrive at the right place
<fieldset>
<%= f.object.send :photo %>
<%= f.file_field :photo %>
<%= f.hidden_field :_destroy %>
<%= link_to "remove", '#', class: "remove_fields" %>
</fieldset>
You should get in the screen the path of your image. Also look at the HTML source, Rails should add hidden fields with your images records id.
If you got all right, then you need to display your image with something else than a file_field, try an image_tag or anything else you want to use
Have you tried you tried using the wonderful accepts_nested_attributes_for provided by Rails for working with Nested Attributes?
Read more http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html
EDIT
I thought best to provide you an example rather.
class Product < ActiveRecord::Base
attr_accessible ..., :product_images_attributes # <======= Pay attention here. Mass Assignment attributes required
accepts_nested_attributes_for :product_images
....
end

ruby on rails - presenting many to many relation

I have recipe and ingredient in a many to many relation.
I have defined the following commands in my presentation.
<div>
<%= render :partial => 'ingredients/form',
:locals => {:form => recipe_form} %>
</div>
the partial begins with
<%= form_for(#ingredient) do |ingredient_form| %>
but received #ingredient nill.
Then I tried
<%= recipe_form.fields_for :ingredients do |builder| %>
<%= render 'ingredient_fields', f: builder %>
<% end %>
where my render was
<p class="fields">
<%= f.text_field :name %>
<%= f.hidden_field :_destroy %>
</p>
but nothing was printed.
then I tried
<% #recipe.ingredients.each do |ingredient| %>
<%= ingredient.name %>
<% end %>
and only then all of the ingredients were printed.
What was I doing wrong in the previous tries ?
Thank you.
my ingredient recipe relation defined as follows
class Ingredient < ActiveRecord::Base
has_many :ingredient_recipes
has_many :recipes, :through => :ingredient_recipes
...
class Recipe < ActiveRecord::Base
has_many :ingredient_recipes
has_many :ingredients, :through => :ingredient_recipes
...
accepts_nested_attributes_for :ingredient_recipes ,:reject_if => lambda { |a| a[:content].blank?}
class IngredientRecipe < ActiveRecord::Base
attr_accessible :created_at, :ingredient_id, :order, :recipe_id
belongs_to :recipe
belongs_to :ingredient
end
You don't exactly specify what you are trying to do, so I am presuming you have a page that shows a recipe, with many ingredients that can be edited and added to. In your controller you have something like:
class RecipeController < ApplicationController
def edit
#recipe = Recipe.find(params[:id]
end
end
I am also presuming that you are looking to have a form that post backs to the create action. I therefore think you want a form like this:
<%= form_for #recipe do |form| %>
<%= label_for :name %>
<%= text_field :name %>
<%= form.fields_for :ingredients do |ingredients_fields| %>
<div class="ingredient">
<%= f.text_field :name %>
<%= f.hidden_field :_destroy %>
</div>
<% end %>
<% end %>
Also, change your recipe to accept nested attributes for ingredients, not ingredient_recipes:
class Recipe < ActiveRecord::Base
has_many :ingredient_recipes
has_many :ingredients, :through => :ingredient_recipes
...
accepts_nested_attributes_for :ingredients, :reject_if => lambda { |a| a[:content].blank?}
And finally, add attr_accessible for your content:
class Ingredient < ActiveRecord::Base
attr_accessible :content
...
Does that work for you?

Edit form load error using Formtastic, STI, Polymorphic & ActiveAdmin

I am new to rails and using a combination of formtastic, activeadmin,sti and polymorphic associations to build a form
When I I can create a nested form with the address parent with no problem, but when i introduce STI and attempt to build_origin_address instead of build_address, that is when I get the error below when loading the edit view
NameError in Admin/leads#edit
Showing .../app/views/admin/leads/_form.erb where line #3 raised:
uninitialized constant Lead::OriginAddress
Models:
class Address < ActiveRecord::Base
belongs_to :addressable, :polymorphic => true
belongs_to :lead
validates :line1, :presence => true, :length => {:minimum => 2}
attr_accessible :line1, :line2, :city, :state, :zip, :country
end
class OriginAddress < Address
end
class DestinationAddress < Address
end
class Lead < ActiveRecord::Base
has_one :origin_address, :dependent => :destroy, :as => :addressable
accepts_nested_attributes_for :origin_address, :allow_destroy => true
end
partial used in edit view:
<%= semantic_form_for [:admin, #lead] do |f| %>
<% #lead.build_origin_address unless #lead.origin_address %>
<%= f.inputs :name => "Lead Info" do %>
<%= f.input :first_name %>
<%= f.input :last_name %>
<% end %>
<%= f.semantic_fields_for :origin_address do |origin| %>
<%= origin.inputs :name => "Origin Address" do %>
<%= origin.input :line1 %>
....
<% end %>
<% end %>
<%= f.buttons do %>
<%= f.commit_button %>
<% end %>
<% end %>
I think you must define #lead before your form.

Resources