Can't mass assign protected attributes in has_many belongs_to association - ruby-on-rails-3

Am using rails 3.2.13 and I have models for two entities like so
class Restaurant < ActiveRecord::Base
attr_accessible :description, :menu, :restaurant_name
has_many :cuisines
end
class Cuisine < ActiveRecord::Base
attr_accessible :cuisine_name, :restaurant_id
attr_accessible :cuisine_ids
belongs_to :restaurant
end
The controller action for creating a restaurant look like this
I have a form for creating a restaurant using simple form gem like so
<%= simple_form_for #restaurant do |f| %>
<%= f.input :restaurant_name %>
<%= f.input :description %>
<%= f.input :menu %>
<%= f.association :cuisines, label_method: :cuisine_name %>
<%= f.button :submit %>
<% end %>
Am basically suppose to chose from a group of cuisines which simple form helps with. However when i select the cuisine and try to create the restaurant. It brings back the error.
ActiveModel::MassAssignmentSecurity::Error at /restaurants
Can't mass-assign protected attributes: cuisine_ids
As you can see in the model. I placed attribute as accessible but it didn't work. I even tried the singular version cuisine_id with no luck. I have no idea what is wrong? I would prefer not to tamper with the rails defaults for protecting against mass assignment. Any clues?

Cuisine doesn't have cuisine_ids, Restaurant does.
Move your attr_accessible :cuisine_ids into the Restaurant model.

Related

Rails Form Objects with multiple nested resources

7 Patterns to Refactor Fat ActiveRecord Models - here is a great article about different refactoring approaches using PORO. Under the 3rd caption there is a Form Object pattern, which I really liked and already implemented in one of the projects. There is only an example using one nested resource, but I would like to implement this pattern for multiple nested resources. Maybe someone here had already dealt with this? I don't necessarily need any code examples, just the basic idea would be fine.
Update
Consider this example. I have two models.
class Company
has_many :users
accepts_nested_attributes_for :users
end
class User
belongs_to :company
end
In case of one nested user for company using Form Object Pattern I would write the following:
<%= form_for #company_form do |f| %>
<%= f.text_field :name %>
<%= f.text_field :user_name %>
<%= f.submit %>
<% end %>
Form Object
class CompanyForm
include Virtus
extend ActiveModel::Naming
include ActiveModel::Conversion
include ActiveModel::Validations
attr_accessor :company, :user
def user
#user ||= company.users.build
end
def company
#company ||= Company.new
end
def submit(params={})
company.name = params[:name]
user.name = params[:user_name]
persist!
end
private
def persist!
company.save!
user.save!
end
end
But what if I have a form, where a company with multiple users can be created. The usual approach is to write it like this, using nested_form:
<%= nested_form_for #company do |f| %>
<%= f.text_field :name %>
<%= fields_for :users, do |user_form| %>
<%= user.form.text_field :name %>
<% end %>
<%= f.link_to_add "Add a user", :users %>
<%= f.submit %>
<% end %>
What I am asking is how do I implement that Form Object Pattern in this case?
the rails fields_for helper checks for a method in this format: #{association_name}_attributes=
so, if you add this method to CompanyForm:
def users_attributes=(users_attributes)
# manipulate attributes as desired...
#company.users_attributes= users_attributes
end
def users
company.users
end
the fields_for generators will generate the nested users fields for a CompanyForm as if it were a Company. the above could be rewritten as a delegation since nothing is happening in the methods:
delegate :users, :users_attributes=, :to => :company, :prefix => false, :allow_nil => false

undefined method `collection_check_boxes'

I'm trying to make an invoicing app. The form to create an invoice should include a collection of check boxes so the user can choose which lessons to invoice, but I'm getting this error: undefined method 'collection_check_boxes'.
Here are the models involved:
class Lesson < ActiveRecord::Base
attr_accessible :lesson_time, :lesson_date, :invoice_id
belongs_to :invoice
end
class Invoice < ActiveRecord::Base
attr_accessible :amount, :due_date
has_many :lessons
end
And the view:
<%= form_for(#invoice) do |f| %>
<fieldset>
<%= f.label :lessons %>
<%= f.collection_check_boxes(:lessons, Lesson.all, :id, :lesson_date) %>
<%= f.submit %>
</fieldset>
<% end %>
collection_check_boxes is not a method of form_builder. Either put:
<%= collection_check_boxes(:lessons, Lesson.all, :id, :lesson_date) %>
This will generate html which won't associate with your model (you won't be able to use MyModel.new(params[my_model]) and expect to get proper response. You would either have to manually call my_model.lessons = params[:lessons] or you can pass a html name parameter to conform your check box name to rails convention).
Or, if you are using formtastic as you tagged it, you can use this:
<%= f.input :lessons, :as => :check_boxes, :collection => Lesson.all %>
I suspect that since you tagged your post ruby-on-rails-3, you might be trying to use a rails 4 method inside a rails 3 project.
http://makandracards.com/makandra/32147-rails-4-introduced-collection_check_boxes
You'll likely need to use good old check_box_tag instead.

How make view with two models using simple_form gem?

I have two models. User have_many articles. How can I make one view for this models with simple_form gem? I can't find this part in wiki and readme :(
For example, something like "simple_form_for [ user, articles ] do |f|"
You can use the simple_fields_for method to create sub-forms for your main model's associations.
<%= simple_form_for #user do |f| %>
<%= f.input :name %>
<%= simple_fields_for :articles do |article_form| %>
<%= article_form.input :title %>
<% end %>
<% end %>
Also, don't forget to tell your model to accept nested attributes, or the record will be invalid.
class User < ActiveRecord::Base
has_many :articles
attr_accessible :articles_attributes
accepts_nested_attributes_for :articles
end

How to create related models within a form in rails

Newbie question here.
I have two models which are related to each other:
class Relationship < ActiveRecord::Base
...
attr_accessible :source_item_id, :target_item_id
belongs_to :target_item, :class_name => "Item"
belongs_to :source_item, :class_name => "Item"
belongs_to :user
...
end
and:
class Item < ActiveRecord::Base
...
attr_accessible :address
...
end
Now, within my form, I already know the source_item_id. I want to be able to enter an address into the form, and create both a target_item, and the associated Relationship.
<%= form_for #new_relationship do |f| %>
<% #new_relationship.source_item_id = #current_item.id %>
<%= f.hidden_field :source_item_id %>
<%= f.submit "New Relationship" %>
<% end %>
You generally do the relationship in the controller and let the form just collect the data. If you are asking how to have a form with two models, check out this post here. I hope I understood your question right !!!

Can't mass-assign protected attributes:

I have pulled out all my hair. No more left... :(
I am using Spree 0.3.4, within an extension I need to register some retailers up. so I direct them to a retailers form which has many custom fields which belong to a retailer model...
So I am trying to validate/submit all the fields from one form like so
myextension/app/views/user_registrations/new.html.erb
<%= form_for (:user, :url => registration_path(#user, :type => "retailer) do |f| %>
<%= f.fields_for :retailer do |r| %>
<%= r.text_field :name %>
<% end %>
<%= f.text_field :email %>
<% end %>
etc etc
class Retailer < ActiveRecord::Base
belongs_to :user
validates :name,
:presence => true
end
class User < ActiveRecord::Base
has_one :retailer
accepts_nested_attributes_for :retailer
attr_accessible :retailer_attributes
# theres a whole lot more spree and devise stuff here. not sure worth mentioning
end
I have also added the abilities in the cancan ability.rb
The problem is the retailer feilds never get validated and the data is never inserted into the database...
I created a blank app, and tried this process from scratch with some plain old scaffolding and it works fine.
any ideas??
In your application helper, do something like this(assuming your have Ruby 1.9.* for the tap functionality, otherwise checkout rails returning here):
def setup_user(user)
user.tap do |u|
u.build_retailer if u.retailer.nil?
end
end
then in your view change it to this:
<%= form_for (setup_user(#user), :url => registration_path(#user, :type => "retailer) do |f| %>
See if that works.