Rails 3: Can't Mass Assign Nested Attributes - ruby-on-rails-3

I'm getting the infamous error:
Can't mass-assign protected attributes: comments
As far as I can tell, I've done everything right in my model:
class Book < ActiveRecord::Base
attr_accessible :author, :edition, :issue, :title, :url, :comments_attributes
has_many :comments, :dependent => :destroy
accepts_nested_attributes_for :comments, :allow_destroy => true
end
And view:
<%= form_for #book, :remote => true do |f| %>
<%= f.label :title %>:
<%= f.text_field :title %><br />
<%= f.label :author %>:
<%= f.text_field :author %><br />
<%= f.fields_for #comment do |comment| %>
<%= comment.label :body, :Comment %>:
<%= comment.text_area :body %><br />
<% end %>
<%= f.submit %>
<% end %>
What am I missing here? I've read through over a dozen similar questions on stackoverflow, but the only advice out there seems to be to add attr_accessible and accepts_nested_attributes_for, both of which I've already got. Surely there's something else?

You have fields_for #comment do |comment|
It should be:
fields_for :comments do |comment|
Then in the next line I would probably just use a string "Comment" for the label.

Related

learning rails, trying to build blog categorization

I am working on building a blog with categorization. I am a bit stuck on how to implement categorization in the form. I have setup a has many through relationship and want to add check boxes to associate a blog with multiple categories. What I have so far is passing the categories through to the view, and I can list them out, however I cannot get the form_for method working for some reason.
Here is my code.
blog model
class Blog < ActiveRecord::Base
attr_accessible :body, :title, :image
has_many :categorizations
has_many :categories, through: :categorizations
has_attached_file :image, :styles => { :medium => "300x300>", :thumb => "100x100>" }
validates :title, :body, :presence => true
end
Category Model
class Category < ActiveRecord::Base
has_many :categorizations
has_many :blogs, through: :categorizations
attr_accessible :name
end
Categorization Model
class Categorization < ActiveRecord::Base
attr_accessible :blog_id, :category_id
belongs_to :blog
belongs_to :category
end
Blog new controller
def new
#blog = Blog.new
#categories = Category.all
respond_to do |format|
format.html # new.html.erb
format.json { render json: #blog }
end
end
Blog new form view
<%= form_for(#blog, :url => blogs_path, :html => { :multipart => true }) do |f| %>
<% if #blog.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#blog.errors.count, "error") %> prohibited this blog from being saved:</h2>
<ul>
<% #blog.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :title %><br />
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.file_field :image %>
</div>
<div class="field">
<%= f.label :body %><br />
<%= f.text_area :body %>
</div>
<div class="field">
Categories:
<% #categories.each do |category| %>
<% fields_for "blog[cat_attributes][]", category do |cat_form| %>
<p>
<%= cat_form.check_box :name %>
</p>
<% end %>
<% end %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
This code is my failing point
<% #categories.each do |category| %>
<% fields_for "blog[cat_attributes][]", category do |cat_form| %>
<p>
<%= cat_form.check_box :name %>
</p>
<% end %>
<% end %>
Although I am not positive I am approaching any of it right since I am currently learning. Any advice on how to accomplish this.
Thanks,
CG
First of all, you probably don't need a separate Categorization model unless there's a use case you haven't described here. You can set up a many-to-many relationship like this:
class Blog < ActiveRecord::Base
has_and_belongs_to_many :categories
end
class Category < ActiveRecord::Base
has_and_belongs_to_many :blogs
end
You should have a database table like this:
class CreateBlogsCategories < ActiveRecord::Migration
def change
create_table :blogs_categories, id: false do |t|
t.references :blog
t.references :category
end
end
end
Then you can construct the view like this:
<div class="field">
Categories:
<% #categories.each do |category| %>
<%= label_tag do %>
<%= check_box_tag 'blog[category_ids][]', category.id, #blog.category_ids.include?(category.id) %>
<%= category.name %>
<% end %>
<% end %>
</div>
Lastly, in your form_for, you specify url: blogs_path - you should remove this if you plan to use this form for the edit action as well, because that should generate a PUT request to /blogs/:id. Assuming you used resources :blogs in routes.rb, Rails will determine the correct path for you based on the action used to render the form.

Rails 3 fields_for has_one not rendering form fields with devise

Hello Im using devise to register users, and I want to create a profile related to a user every time a user signs up, the problem is that when I try to add the full name of the person from the profile model on the registration view for devise's user registration, it does not show up...
This are my models:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :profile_attributes
has_one :profile, dependent: :destroy
accepts_nested_attributes_for :profile
# attr_accessible :title, :body
end
This is the profile model
class Profile < ActiveRecord::Base
attr_accessible :email, :name, :phone, :code
belongs_to :user
validates_presence_of :user
end
And this is the devise view modified:
<% provide(:title, 'Sign up' ) %>
<h2>Sign up</h2>
<div class="row">
<div class="span6 offset3">
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
<%= render 'shared/error_messages', object: resource %>
<%= f.fields_for :profile do |profile_form| %>
<%= profile_form.label :full_name %>
<%= profile_form.text_field :name %>
<% end %>
<%= f.label :email %>
<%= f.email_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation %>
<div class="form-actions">
<%= f.submit "Sign up", class: "btn btn-large btn-primary" %>
</div>
<% end %>
<%= render "devise/shared/links" %>
</div>
</div>
I cant see anything wrong to why the name text field would not appear...
Thank you for your help
Figured it out, it was so simple I feel bad... so here it is:
I forgot to generate a new profile on the form so it ends up looking kind of like this:
.
.
.
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
<%= render 'shared/error_messages', object: resource %>
<div class="invisible">
<%= resource.build_profile %>
</div>
<%= f.fields_for :profile do |profile_form| %>
<%= profile_form.label :full_name %>
<%= profile_form.text_field :name %>
<% end %>
<%= f.label :email %>
<%= f.email_field :email %>
.
.
.
Hope this solves someone else's problem as well!
Thank you!
This question is already answered, but I thought I'd throw this up as an alternative for others. Form backing objects can be used to go back to a one form/one model kind of setup and help keep code cleaner.
Here's a good writeup on it:
http://pivotallabs.com/form-backing-objects-for-fun-and-profit/

Rails 3.2 : Can't mass-assign protected attributes

I have a model that has amenities with a 1:1 relationship:
class Listing < ActiveRecord::Base
attr_accessible :address1, :address2, :bath, :bedroom, :city, :description, :neighborhood, :sleeps, :sqft, :state_id, :title, :zip, :images_attributes, :amenity_attributes
has_many :images, :dependent => :destroy
accepts_nested_attributes_for :images, :allow_destroy => true
has_one :amenity
accepts_nested_attributes_for :amenity, :allow_destroy => true
end
And Amenities table:
class Amenity < ActiveRecord::Base
attr_accessible :air_conditioning, :balcony
belongs_to :listing
end
Lastly, my view:
<%= simple_nested_form_for (#listing), :html => {:multipart => true} do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :title %>
<%= f.input :sleeps %>
<%= f.input :bath %>
<%= f.input :bedroom %>
<%= f.input :sqft %>
<%= f.input :neighborhood %>
<%= f.input :address1 %>
<%= f.input :address2 %>
<%= f.input :city %>
<%= f.input :state_id %>
<%= f.input :zip %>
<%= f.input :description %>
</div>
<!-- amenities -->
<%= f.fields_for :amenities do |a| %>
<div class="amenities">
<label><%= a.check_box :smoking %> Smoking Allowed</label>
</div>
<% end %>
<!-- end amenities -->
<!-- Submit button -->
<% end %>
When I hit submit I get the error:
Can't mass-assign protected attributes: amenities
Any idea what's up here? It won't submit even though I allow :amenities_attributes and accepts_nested tags.
You have a has_one association so amenities should not be plural.
change
<%= f.fields_for :amenity do |a| %>
EDIT
<%= f.fields_for :amenity do |a| %>
<div class="amenities">
<%= a.label :smoking, 'Smoking Allowed' %>
<%= a.check_box :smoking %>
</div>
<% end %>
<p><%= f.submit "Submit" %></p>
<% end %>
Also, checkout this documentation for a one to one association, http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html
Fixed:
class Listing < ActiveRecord::Base
has_one :amenity
accepts_nested_attributes_for :amenity
after_initialize do
self.amenity ||= self.build_amenity()
end
end

Updating unused field after initial creation does not work rails

For reference, this is using Rails 3.0.9.
I can't seem to figure out why, but I cannot update a field which was left blank at the initial creation of the object/row.
If my model looks like this:
name - string
date - date
message - string
If I put info in all of the fields upon initial creation, everything can be updated without a hitch later on. But if I do not put info in one of the fields, say the title, I cannot update that field after initial creation.
I'm not doing anything out of the ordinary, the form is pretty plain jane:
<%= form_for #event do |f| %>
<%= f.error_messages %>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<p>
<%= f.label :date %><br />
<%= f.date_select :date %>
</p>
<p>
<%= f.label :message %><br />
<%= f.text_field :message %>
</p>
<p><%= f.submit %></p>
<% end %>
And my controller is equally as simple:
def update
if #event.update_attributes(params[:event])
redirect_to #event, :notice => "Successfully updated event."
else
render :action => 'edit'
end
end
And the model:
class Event < ActiveRecord::Base
has_many :races, :dependent => :destroy
has_many :price_groups, :dependent => :destroy
accepts_nested_attributes_for :races, :reject_if => lambda{ |a| a[:name].blank? }, :allow_destroy => true
accepts_nested_attributes_for :price_groups, :reject_if => lambda{ |a| a[:name].blank? }, :allow_destroy => true
attr_accessible :name, :date, :message, :races_attributes, :price_groups_attributes
end

Nested forms fields_for :prices, repeat forms few time

i have many to many throught asociation and then i do this
fields_for :device
this displaying in good way, but i cannot save it i get unknown attribute :price
And fields_for :devices
And so on, one device makes one more repeat, if i write f.fields_for :price it gives good text field count, but it write
unknown attribute: price
Rails.root: C:/Users/Ignas/mildai/baze4
Application Trace | Framework Trace | Full Trace
app/controllers/commercial_offers_controller.rb:74:in `block in update'
app/controllers/commercial_offers_controller.rb:73:in `update'
thank you
additional information:
controller
def edit_prices
#commercial_offer = CommercialOffer.find(params[:id])
end
link to edit prices
<%= link_to "Edit prices", :controller => "CommercialOffers", :action => "edit_prices", :id => #commercial_offer %>
_edit_price.html.erb
<%= form_for #commercial_offer do |f| %>
<% CommercialOffer.find(params[:id]).devices.each do |device| %>
<%= check_box_tag "commercial_offer[device_ids][]", device.id, #commercial_offer.devices.include?(device) %>
<%= device.name %>
<%= f.fields_for :prices do |builder| %>
<%= render 'prices/new_price', :f => builder, :commercial_offer => #commercial_offer, :device => device %>
<% end %>
<% end %>
<div class="actions">
<%= f.submit "Save"%>
</div>
<% end %>
for one device it have render only one time, but it rendering for one device such times how many devices is with same commercial_offer_id
_new_price.html.erb
Price:
<%= f.text_field :price %></br>
Quantity:
<%= f.text_field :quantity %></br>
Device id:
<%= f.text_field :device_id, :value => device.id %></br>
class CommercialOffer < ActiveRecord::Base
has_many :prices
has_many :devices, :through => :prices
accepts_nested_attributes_for :prices
accepts_nested_attributes_for :devices
end
class Device < ActiveRecord::Base
has_many :prices
accepts_nested_attributes_for :prices
has_many :commercial_offer, :through => :prices
class Price < ActiveRecord::Base
belongs_to :device
belongs_to :commercial_offer
end
There is no any field_for method.
Also your question isn't clear. What actually you want to do? Show only one device? Wich one? First, last?
UPD
commercial_offer.rb:
class CommercialOffer < ActiveRecord::Base
has_many :prices
has_many :devices, :through => :prices
accepts_nested_attributes_for :prices
accepts_nested_attributes_for :devices, :allow_destroy => true
end
Your view
<%= form_for #commercial_offer do |f| %>
<%= f.fields_for :devices do |device| %>
<p>
<%= device.check_box :_destroy %>
<%= device.label "Destroy?" %>
</p>
<p>
<%= device.text_field :name %>
</p>
<%= device.fields_for :prices do |builder| %>
<%= render 'prices/new_price', :f => device %>
<% end %>
<% end %>
<% end %>
<div class="actions">
<%= f.submit "Save"%>
</div>
<% end %>
_new_price partial
<%= f.text_field :price %></br>
Quantity:
<%= f.text_field :quantity %></br>
Device id:
<%= f.text_field :device_id %></br>