collection_select content is not showing - ruby-on-rails

I'm currently trying to display the organization which a content identifies themselves with via a collection_select form.
The issue is that after creating a new contact and choosing an organization. The organization doesn't display.
I have tried searching the web for an answer so far but nothing has helped. I have also tried everything that I can think of is the issue with my code.
Here are my models:
class Contact < ApplicationRecord
has_many :contact_orgs
has_many :organizations, through: :contact_orgs
accepts_nested_attributes_for :organizations
end
class Organization < ApplicationRecord
has_many :contact_orgs
has_many :contacts, through: :contact_orgs
end
class ContactOrg < ApplicationRecord
belongs_to :contact
belongs_to :organization
accepts_nested_attributes_for :organization
end
Here is my schema.rb:
create_table "contact_orgs", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "contact_id"
t.integer "organization_id"
t.index ["contact_id"], name: "index_contact_orgs_on_contact_id"
t.index ["organization_id"], name: "index_contact_orgs_on_organization_id"
end
create_table "contacts", force: :cascade do |t|
t.string "first_name"
t.string "last_name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "organizations", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "industry"
end
Here is my contact_controller.rb:
private
def contact_params
params.require(:contact).permit(:first_name, :last_name,
organizations_attributes: [:name, :industry])
end
def new
#contact = Contact.new
end
def show
#contact = Contact.find(params[:id])
end
def create
#contact = Contact.new(contact_params)
if #contact.save
redirect_to #contact
else
render 'new'
end
end
Here is my contact/new.html.erb:
<%= form_with scope: :contact, url: contact_path, local: true do |form| %>
<p>
<%= form.label :first_name %><br>
<%= form.text_field :first_name %>
</p>
<p>
<%= form.label :last_name %><br>
<%= form.text_field :last_name %>
</p>
<p>
<%= form.label :organization_id, "Organization:" %><br>
<%= form.collection_select :organization_id, Organization.order(:name), :id, :name, {}, {multiple: true} %>
</p>
<p>
<%= form.submit %>
</p>
<% end %>
Here is my contact/show.html.erb:
<p>
<strong>First name:</strong>
<%= #contact.first_name %>
</p>
<p>
<strong>Last Name:</strong>
<%= #contact.last_name %>
</p>
<hr>
<p>
<strong>Organizations:</strong>
<ul>
<% #contact.organizations.each do |organization| %>
<li><%= organization.name %></li>
<% end %>
</ul>
</p>
Here is what my Rails Server is saying when I refresh my localhost:3000/contact/2 page.
Here is what is in my Rails Console:
2.4.1 :001 > Contact.find(2).organizations
Contact Load (0.2ms) SELECT "contacts".* FROM "contacts" WHERE "contacts"."id" = ? LIMIT ? [["id", 2], ["LIMIT", 1]]
Organization Load (0.2ms) SELECT "organizations".* FROM "organizations" INNER JOIN "contact_orgs" ON "organizations"."id" = "contact_orgs"."organization_id" WHERE "contact_orgs"."contact_id" = ? LIMIT ? [["contact_id", 2], ["LIMIT", 11]]=> #<ActiveRecord::Associations::CollectionProxy []>
Here is my routes.rb file:
Rails.application.routes.draw do
get 'welcome/index'
resources :contacts, :organizations
root 'welcome#index'
end
Thank you ahead of time :)
Edit:
Added Contacts#Show method and Contact.find(2).organization via Rails c command.
Added routes.rb

Since you’re using a joins table (ContactOrg) you really are trying to create a new ContactOrg record when you create a Contact, not assign it to Organization, which is how your code reads.
EDIT
While my first statement above still has a (little) bit of merit (you are in fact creating a joins record), you can definitely let rails help you out and you were pretty close in your original answer. Here's code only where there are updates, I tried to highlight changes.
app/models/contact.rb
class Contact < ApplicationRecord
has_many :contact_orgs
has_many :organizations, through: :contact_orgs
accepts_nested_attributes_for :organizations # you were correct here
end
app/views/contact/new.html.erb
<%= form_with model: :contact, local: true do |form| %>
# use :model here so you can ultimately use this form for both new and edit.
# The model method will infer the correct path
... contact fields here as you have them ...
<p>
<%= form.collection_select :organization_ids, Organization.order(:name), :id, :name, {}, {multiple: true} %>
# the attribute for organization_id should be plural because you're accepting multiple
<p>
<p>
<%= form.submit %>
</p>
<% end %>
app/controllers/contacts_controller.rb
class ContactsController < ApplicationController
... new, show, and create as you have them ...
private # private methods should go after all public methods
def contact_params
params.require(:contact).permit(:first_name, :last_name, organization_ids: [])
# again, the attribute you're passing in is called organization_ids, and you give it an empty array
end
end

Your contract_controller do not initialize #contact used in show.html.erb because there isn't any show method does it that.
Try to add in contact_controller
def show
#contact = Contact.find(param[:id])
end
PS: when you call show method be sure to pass to it a contact.id
I hope this help you.

There are two problems:
You are not able to save the organizations to your contract.
You can check in your rails c by Contact.find(2).organizations.
We never use to write new and create in the private method.
Your private method should not contain any of the curd.
In your app/controllers/contacts_controller.rb
private
def contact_params
params.require(:contact).permit(
:first_name,
:last_name,
organizations_attributes: [
:name,
:industry
]
)
end
In your app/views/contact/new.html.erb
<%= form_with scope: :contact, url: contact_index_path, local: true do |form| %>
<p>
<%= form.label :first_name %><br>
<%= form.text_field :first_name %>
</p>
<p>
<%= form.label :last_name %><br>
<%= form.text_field :last_name %>
</p>
<p>
<%= form.fields_for :organizations do |o| %>
<%= o.label :organization %><br>
<%= o.collection_select(:organization_id, Organization.all,
:id, :org_name,
{:prompt => 'Please select the organization'}) %>
</p>
<p>
<%= form.submit %>
</p>
<% end %>

Related

How can a user update another model's table's values using a form?

I have a user that contains their addresses. Now, I have another table, called search address, that contains a search_address.
This should be a one to one relationship, where a user can only create one search address on the search address table.
I want it so a user can submit a form, and create, in the address search table, a search_address. Afterwards, I want to callback that search_address's latitude and longitude (I'm using the geocoder gem).
This is the code I have so far:
Schema:
create_table "users", force: :cascade do |t|
t.string "address"
t.float "latitude"
t.float "longitude"
end
create_table "search_addresses", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "search_address"
t.float "search_latitude"
t.float "search_longitude"
end
User model:
class User < ActiveRecord::Base
geocoded_by :address
after_validation :geocode
end
Search Address model:
class SearchAddress < ActiveRecord::Base
belongs_to :user
geocoded_by :search_address, :latitude => :search_latitude, :longitude => :search_longitude
end
My current view (I based this answer off another Stack answer, but it isn't working):
<%= semantic_form_for #users do |f| %>
<%= fields_for #user.searchaddresses do |g| %>
<div class="field">
<%= g.label :search_address, 'Search Address' %>
<br/>
<%= g.text_field :search_address, :class => "form-control" %>
</div>
<%= f.submit 'Save Search Address' %>
<% end %>
<% end %>
Also, my intended view would display something like this:
<%= #user.searchaddress.latitude %>
<%= #user.searchaddress.longitude %>
Based on this information, what should I do to the form so a user can add in one search address, and then have another view show the latitude and longitude of this search address?
1 => Use Nested Attributes for User
class User < ActiveRecord::Base
has_many : search_addresses, dependent: :destroy
geocoded_by :address
after_validation :geocode
accepts_nested_attributes_for :search_addresses
end
2 => Fix Typo
<%= semantic_form_for #user do |f| %>
<%= fields_for #user.search_addresses do |g| %>
<div class="field">
<%= g.label :search_address, 'Search Address' %>
<br/>
<%= g.text_field :search_address, :class => "form-control" %>
</div>
<% end %>
<%= f.submit 'Save Search Address' %>
<% end %>
3 => users_controller.rb
def update
#fetch user to be updated along with search_addresses
#user.update(update_user_params)
#after update
end
private
def update_user_params
params.require(:user).permit(search_addresses_attributes: [:search_address])
end
References: - Ruby on Rails Nested Attributes,
Active Record Nested Attributes

Rails 5: Many-to-Many Relationship Not Working

I am trying to create a many-to-many table relationship in a Rails 5 project.
One Shop can have many Categories, which are indexed in the Shop_Categories table.
I seem to be missing one key step though. When I submit my Shop form, I receive the soft error: "Unpermitted parameter: :shop_category"
I can see my shop_category parameters being successfully sent in the Rails server log, but the Shop_Categories table doesn't get updated at all.
What am I missing, and what can I change so that pressing save on the Shop view form updates the Shop_Categories table?
Here's my code.
Shop Model
class Shop < ApplicationRecord
belongs_to :type
has_many :shop_categories
has_many :categories, through: :shop_categories
accepts_nested_attributes_for :shop_categories
enum status: [:open, :closed, :opening_soon, :closing_soon]
end
Shop_Category Model
class ShopCategory < ApplicationRecord
belongs_to :shop
belongs_to :category
end
Category Model
class Category < ApplicationRecord
has_many :subcategories, dependent: :destroy
has_many :shop_categories
has_many :shops, through: :shop_categories
end
Shop Controller (Excerpt)
def new
#shop = Shop.new
#shop.shop_categories.build
end
def create
#shop = Shop.new(shop_params)
#shop.open_date = params[:shop][:open_date]+"-01"
#shop.close_date = params[:shop][:close_date]+"-01"
if #shop.save
redirect_to #shop
else
render 'new'
end
end
def update
#shop = Shop.find(params[:id])
if #shop.update(shop_params)
redirect_to #shop
else
render 'edit'
end
end
private
def shop_params
params[:shop][:open_date] = params[:shop][:open_date]+"-01"
params[:shop][:close_date] = params[:shop][:close_date]+"-01"
params.require(:shop).permit(:shop_name, :type_id, :status,
:phone_number, :mobile_number, :email_address, :open_date,
:close_date, shop_categories_attributes: [ :shop_id, :category_id] )
end
Shop Form View (Excerpt)
<p>
<%= form.label :shop_name %><br>
<%= form.text_field :shop_name %>
</p>
<%= form.fields_for :shop_category do |category_fields| %>
<p>
<%= category_fields.label :category %><br />
<%= category_fields.collection_select(:category_id, Category.all, :id, :category_name, include_blank: true) %>
</p>
<% end %>
<p>
<%= form.submit %>
</p>
And finally, the Database Schema
create_table "categories", force: :cascade do |t|
t.string "category_name"
t.text "category_description"
t.string "visible_category"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "shop_categories", force: :cascade do |t|
t.string "visible_category_override"
t.integer "shop_id"
t.integer "category_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["category_id"], name: "index_shop_categories_on_category_id"
t.index ["shop_id"], name: "index_shop_categories_on_shop_id"
end
create_table "shops", force: :cascade do |t|
t.string "shop_name"
t.integer "status"
t.integer "sale"
t.string "phone_number"
t.string "mobile_number"
t.string "email_address"
t.date "open_date"
t.date "close_date"
t.integer "type_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["type_id"], name: "index_shops_on_type_id"
end
Any suggestions would be greatly appreciated. I just can't work out which piece of the puzzle I'm missing!
Update: Including the Dev log, and the full Shop Form.
Dev Log
Started PATCH "/shops/1" for 127.0.0.1 at 2018-01-14 11:08:39 +0000
Processing by ShopsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"2qydDj9JovMrg9VT6Lo5xbcNSHl5MH0ylmq3IMMX4iRTAVSgK6JlXWpG+CyuwQK6svZJn9wtnEnZANUlOZYzXA==",
"shop"=>{"shop_name"=>"test", "type_id"=>"1",
"shop_categories"=>{"category_id"=>"1"}, "subcategory_id"=>"",
"status"=>"open", "phone_number"=>"123", "mobile_number"=>"13212",
"email_address"=>"hello#test.com", "open_date"=>"2017-12",
"close_date"=>"2017-12"}, "commit"=>"Update Shop", "id"=>"1"}
Shop Load (0.5ms) SELECT "shops".* FROM "shops" WHERE "shops"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
Unpermitted parameters: :shop_categories, :subcategory_id
(0.1ms) begin transaction
Type Load (0.2ms) SELECT "types".* FROM "types" WHERE "types"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
(0.1ms) commit transaction
Redirected to http://localhost:3000/shops/1
Completed 302 Found in 10ms (ActiveRecord: 0.9ms)
Full view/shops/_form.html.erb file
<%= form_with model: #shop, local: true do |form| %>
<% if #shop.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(#shop.errors.count, "error") %> prohibited
this shop from being saved:
</h2>
<ul>
<% #shop.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= form.label :shop_name %><br>
<%= form.text_field :shop_name %>
</p>
<p>
<%= form.label :type %><br />
<%= form.collection_select(:type_id, Type.all, :id, :type_name) %>
</p>
<%= form.fields_for :shop_categories do |category_fields| %>
<p>
<%= category_fields.label :category %><br />
<%= category_fields.collection_select(:category_id, Category.all, :id, :category_name, include_blank: true) %>
</p>
<% end %>
<p>
<%= form.label :subcategory %><br />
<%= form.grouped_collection_select :subcategory_id, Category.all, :subcategories, :category_name, :id, :visible_subcategory, include_blank: true %>
</p>
<p>
<%= form.label :status %><br />
<%= form.select :status, Shop.statuses.keys %>
</p>
<p>
<%= form.label :phone_number %><br>
<%= form.telephone_field :phone_number %>
</p>
<p>
<%= form.label :mobile_number %><br>
<%= form.telephone_field :mobile_number %>
</p>
<p>
<%= form.label :email_address %><br>
<%= form.email_field :email_address %>
</p>
<p>
<%= form.label :open_date %><br>
<%= form.month_field :open_date %>
</p>
<p>
<%= form.label :close_date %><br>
<%= form.month_field :close_date %>
</p>
<p>
<%= form.submit %>
</p>
<% end %>
It should probably be :shop_categories, not :shop_category
<%= f.fields_for :shop_categories do |category_f| %>
...
<% end %>
You also kind of lost me in the Shop_Category Model part. The actual class name is different (ShopSubcategory) and it belongs_to a subcategory? This will probably cause some errors as well. I guess what you meant is the ShopCategoryjoin model and it belongs_to :category
Update
Also be sure to build your nested resource when creating a new form:
#shop_controller
def new
#shop = Shop.new
#shop.shop_categories.build
...
end

undefined local variable or method error-attempting to link a comment to a blog

I am working on a Rails 4 project and I currently have a comment section that is tied to a group section-the group is almost like a blog. I need the group id number to be linked to a new comment. I do not want the user to select the group id but instead have it automatically show up. I currently have this in my comment form, my problem is coming in form the last form-group with the Group Id:
<div class="form-group">
<%= form.label :author %>
<%= form.text_field :author, autofocus: true, class: "form-control",
placeholder: "Author's Name" %>
</div>
<div class="form-group">
<%= form.label :comment %>
<%= form.text_field :comment, class: "form-control", placeholder: "Write
your hearts content" %>
</div>
<div class="hide">
<%= form.number_field :user_id, value: current_user.id %>
</div>
<div class="form-group">
<%= form.number_field :group_id, value: group.id %>
</div>
What I want to do is have something like the :user_id, value: current_user.id work with each group. The user id line works fine and I have no problems with it. It is only that group line that I receive the following error: undefined local variable or method `group' for #<#:0x007f873a161fc0>
My schema looks like the following:
create_table "comments", force: :cascade do |t|
t.string "author"
t.text "comment"
t.integer "user_id"
t.integer "group_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "groups", force: :cascade do |t|
t.string "topic"
t.integer "user_id"
t.text "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.float "latitude"
t.float "longitude"
t.string "address"
t.string "city"
t.string "state"
end
Finally, my comments controller looks like the following:
class CommentsController < ApplicationController
def new
#comment = Comment.new
end
def create
#comment = Comment.new(comment_params)
if #comment.save
redirect_to #group
else
render 'new'
end
end
def edit
end
def update
end
private
def comment_params
params.require(:comment).permit(:author, :comment, :user_id, :group_id)
end
end
Please let me know if any more information is needed. Thank you for the help!
Here are the models for groups and Comments:
Comment:
class Comment < ActiveRecord::Base
belongs_to :group
end
Group:
class Group < ActiveRecord::Base
has_many :collections
has_many :comments
has_many :users, :through => :collections
validates :topic, presence: true
validates :description, presence: true, length: { minimum: 10 }
geocoded_by :address
after_validation :geocode
end
Without specifying the :value option in a form_for method, Rails automatically infers the value from the column name, so leaving it out like below should work for your specific use case, otherwise instead of referring to group, use #comment.group_id:
<div class="form-group">
<%= form.label :author %>
<%= form.text_field :author, autofocus: true, class: "form-control",
placeholder: "Author's Name" %>
</div>
<div class="form-group">
<%= form.label :comment %>
<%= form.text_field :comment, class: "form-control", placeholder: "Write
your hearts content" %>
</div>
<div class="hide">
<%= form.number_field :user_id, value: current_user.id %>
</div>
<div class="form-group">
<%= form.number_field :group_id %>
</div>
However, I'm not totally sure whether you're approaching a few things right.
Some immediate changes, I'd probably propose would be:
Use nested routes:
# routes.rb
resources :groups do
resources :comments
end
In your CommentsController, you could now fetch the group_id from the route:
def create
group = Group.find(params[:group_id])
#comment = current_user.comments.new(comment_params)
#comment.group = group
if #comment.save
redirect_to group
else
render 'new'
end
end
private
def comment_params
params.require(:comment).permit(:author, :comment)
end
This way, in your view, you could easily do:
<div class="form-group">
<%= form.label :author %>
<%= form.text_field :author, autofocus: true, class: "form-control",
placeholder: "Author's Name" %>
</div>
<div class="form-group">
<%= form.label :comment %>
<%= form.text_field :comment, class: "form-control", placeholder: "Write
your hearts content" %>
</div>
Note: :user_id and :group_id have been removed from the form fields because those mappings are now done on the controller level.
Read more about nested routes and nested resources here
UPDATE
For a new comment, the group_id would be nil because it has not been associated to it yet(one of the benefits of nested resources), however if you know beforehand what the group might be, you might want to try:
#comment = group.comments.build
and instead use the value of this #comment.
When you create a comment do you know which group it belongs to:?
I think the issue is with this line
<%= form.number_field :group_id, value: group.id %>
So you are assigning an ID but your group is not initialized. Can you do something like this inside new method
def new
#group = Group.find(...) # load a group here and assign below
#comment = Comment.new(group: #group)
end
You could also refactor so when you create a comment you go to tested route like /groups/ID/comments and then the group ID will be inside params
Hope it helps
if you know which group a comment should belong to then you could do something like this
class CommentsController < ApplicationController
def new
#group = Group.find(...)
#comment = Comment.new
end
def create
comment = Comment.create(comments_params)
if comment.save
redirect_to comments_path
else
redirect_to :new
end
end
private
def comments_params
params.require(:comment).permit(:body, :group_id)
end
end
and inside your form you could have your comment linked to that group
<%= f.number_field :group_id, value: #group.id %>

Unpermitted parameters: user error when passing user params using nested attributes

I have a form that collects company information as well as the first user (the company admin). When I submit the form, the company attributes are saved to the db. However, the user attributes are not. I get the error Unpermitted parameters: user. I can't figure out why the user is not being created and saved.
I have:
class CompaniesController < ApplicationController
def new
#company = Company.new
#plans = Plan.all
end
def create
#company = Company.new(company_params)
#user = User.new
#user.role = "admin"
#user.save
if #company.save
redirect_to #company, notice: 'Company was successfully created.'
else
render action: 'new'
end
end
private
# Never trust parameters from the scary internet, only allow the white list through.
def company_params
params.require(:company).permit(:name, :plan_id, users_attributes: [:id, :company_id, :email, :password, :password_confirmation, :first_name, :last_name, :role, :rate])
end
end
and
class UsersController < ApplicationController
# include UsersHelper
def index
#users = User.all
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
#user.save
flash.notice = "User '#{#user.first_name} #{#user.last_name}' was successfully created."
redirect_to user_path(#user)
end
def show
#user = User.find(params[:id])
end
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
#user.update(user_params)
flash.notice = "User '#{#user.first_name}' has been updated."
redirect_to user_path(#user)
end
def destroy
end
private
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
params.require(:user).permit(:email, :password, :password_confirmation, :first_name, :last_name, :role, :rate)
end
end
and
class Company < ActiveRecord::Base
has_many :users
belongs_to :plan
accepts_nested_attributes_for :users, :allow_destroy => true
end
and
class User < ActiveRecord::Base
authenticates_with_sorcery!
validates_confirmation_of :password, message: "should match confirmation", if: :password
has_many :jobs
belongs_to :company
end
and
<%= form_for(#company) do |f| %>
<% if #company.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#company.errors.count, "error") %> prohibited this company from being saved:</h2>
<ul>
<% #company.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name, :id => "name" %>
</div>
<div class="field">
<%= collection_select( :company, :plan_id, #plans, :id, :name ) %>
</div>
<%= f.fields_for :user do |user| %>
<div class="field">
<%= user.label :email %><br>
<%= user.text_field :email %>
</div>
<div class="field">
<%= user.label :password %><br>
<%= user.password_field :password %>
</div>
<div class="field">
<%= user.label :password_confirmation %><br>
<%= user.password_field :password_confirmation %>
</div>
<div class="field">
<%= user.label :first_name %><br>
<%= user.text_field :first_name %>
</div>
<div class="field">
<%= user.label :last_name %><br>
<%= user.text_field :last_name %>
</div>
<div class="field">
<%= user.label :role %><br>
<%= user.text_field :role %>
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
and
ActiveRecord::Schema.define(version: 20140421235514) do
create_table "companies", force: true do |t|
t.string "name"
t.string "stripe_token"
t.integer "plan_id"
t.integer "user_id", limit: 255
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "companies", ["plan_id"], name: "index_companies_on_plan_id"
add_index "companies", ["user_id"], name: "index_companies_on_user_id"
create_table "plans", force: true do |t|
t.string "stripe_id"
t.string "name"
t.integer "amount"
t.string "interval"
t.string "currency"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "users", force: true do |t|
t.string "email", null: false
t.string "crypted_password", null: false
t.string "salt", null: false
t.datetime "created_at"
t.datetime "updated_at"
t.string "reset_password_token"
t.datetime "reset_password_token_expires_at"
t.datetime "reset_password_email_sent_at"
t.string "first_name"
t.string "last_name"
t.string "role"
t.integer "rate"
t.integer "company_id"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token"
end
Company and User are associated with 1-M Relationship , i.e., Company has_many :users
In that case, in your view for Company, the nested form should be
<%= f.fields_for :users do |user| %> ## Notice users in plural
and NOT
<%= f.fields_for :user do |user| %>
Refer to the Nested Attributes Examples for One to Many
Currently, fields_for is setup incorrectly with singular :user so in params hash you got the key as :user and again a warning Unpermitted parameters: user because of which the user attributes were not stored in database.
Now, as you have setup accepts_nested_attributes_for in Company model. Controller is expecting user attributes in key users_attributes within params hash.
Changing the fields_for with plural :users argument would result in creation of users_attributes key in params hash upon form submission.
UPDATE
Company has many users, its 1-M relationship
Only users table should have foreign key as company_id.
You need to remove user_id from companies table.
Also, update the CompaniesController#new action as below:
def new
#company = Company.new
#users = #company.users.build
#plans = Plan.all
end
Strong params permitting looks fine to me but i think the issue is in the nested form, you used wrong relation name user while its users which generates a params hash titled with user which is not permitted, instead you should do:
<%= f.fields_for :users do |user| %>
#rest of the form elements
<% end %>

rails 4 mass assignment error with protected_attributes gem

I'm trying to add a user profile sub module to a user module but having some problems.
Routes:
resources :users do
resources :userprofiles
end
userprofiles_controller.rb:
class UserprofilesController < ApplicationController
def edit
#user = current_user
#user.UserProfile ||= UserProfile.new
#userprofile = #user.UserProfile
end
def update
#user = current_user
#user.UserProfile ||= UserProfile.new
#userprofile = #user.UserProfile
if #userprofile.update_attributes(:userprofile => params[:userprofile])
redirect_to #user
flash[:notice] = "Changes saved."
else
render 'edit'
flash[:notice] = "Error."
end
end
end
user_profile.rb:
class UserProfile < ActiveRecord::Base
attr_accessible :first_name, :last_name, :summary
belongs_to :user
end
Error:
Can't mass-assign protected attributes for UserProfile: userprofile
Line:
if #userprofile.update_attributes(:userprofile => params[:userprofile])
EDIT
Form:
<%= form_for([#user, #userprofile], url: user_userprofile_path(#user, #userprofile)) do |form| %>
<%= form.label :first_name %>
<%= form.text_field :first_name %>
<%= form.label :last_name %>
<%= form.text_field :last_name %>
<%= form.label :summary %>
<%= form.text_area :summary %>
<%= form.submit "Update", class: "btn btn-block btn-primary" %>
<% end %>
Table:
create_table "user_profiles", force: true do |t|
t.string "last_name"
t.string "first_name"
t.text "summary"
t.integer "user_id", null: false
t.datetime "created_at"
t.datetime "updated_at"
end
You just want
#userprofile.update_attributes(params[:userprofile])
That's a hash with keys :first_name, :last_name, and :summary, which are allowed attributes. When you try to update :userprofile => params[:userprofile], the model checks to see if the key :userprofile is allowed - and it isn't.
I also had this problem. The issue is that you still have attr_accessible in your model controller. Since you don't need them anymore with Rails 4 remove them, add your strong parameters to the controller, and you'll be able to mass-assign without issue.

Resources