Reputation:
I want users to be able to select the languages they speak. I have setup the associations, the table attributes and the part of the form. When I select a language and submit the form I go to the rails console and do a u.languages
but I get an empty array back: => []
Here are the logs when I submit the form:
Started POST "/update_user_via_user" for 127.0.0.1 at 2016-03-18 13:26:03 +0200
ActiveRecord::SchemaMigration Load (0.4ms) SELECT "schema_migrations".* FROM "schema_migrations"
Processing by UsersController#update_user_via_user as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"CB1Qca0VrBcap9qO6VpKfoi2dG8GNG+tGGNDgCnFEv4E=", "user"=>{ "fullname"=>"John Doe", "languages"=>["", "1", "2"]}, "commit"=>"Save"}
User Load (28.6ms) SELECT "users".* FROM "users" WHERE "users"."id" = 3 ORDER BY "users"."id" ASC LIMIT 1
Unpermitted parameters: languages
(0.1ms) begin transaction
(0.1ms) commit transaction
Redirected to http://127.0.0.1:3000/setup_profile
Completed 302 Found in 163ms (ActiveRecord: 29.5ms)
Now if you look closely on the loogs you will see "Unpermitted parameters: languages".
In my users_controller I have the followings:
def user_params
params.require(:user).permit(:languages, :fullname)
end
and the custom action:
def update_user_via_user
if current_user.update(user_params)
flash.notice = "Your profile was sent for moderation. We will moderate it asap!"
else
flash.alert = "Something went wrong! Please try again."
end
redirect_to root_path
end
Some other references: (my question at the end)
schema.rb:
languages table:
create_table "languages", force: true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "user_id"
end
users table:
t.string "languages"
language.rb model:
class Language < ActiveRecord::Base
belongs_to :user
end
and user.rb model:
class User < ActiveRecord::Base
has_many :languages
end
The view:
<%= f.label :languages %>
<%= f.select :languages, Language.all.map{ |l| [l.name, "#{l.id}"] }, {}, { :multiple => true } %>
I am not sure why "languages" is not permitted and also if my concept of code is correct
Upvotes: 0
Views: 307
Reputation: 20263
I was thinking Deep's answer was the right one, based on this exchange.
I fired up my console and did this:
irb(main):001:0> x = ActionController::Parameters.new(user: {fullname: "John Doe", languages: ['','1','2']})
=> {"user"=>{"fullname"=>"John Doe", "languages"=>["", "1", "2"]}}
irb(main):002:0> y = x.require(:user).permit(:fullname, :languages => [])
=> {"fullname"=>"John Doe", "languages"=>["", "1", "2"]}
irb(main):003:0> y[:languages]
=> ["", "1", "2"]
So, hm.
What's the error message you're getting now? Same as original?
Upvotes: 0
Reputation: 102036
class Language < ActiveRecord::Base
belongs_to :user
end
This would setup a one two many relation between users and languages which is not what you want. What you want is a many to many relation:
So to keep track of this we need a third table:
language_users
is what is known as a join table. You can actually name the table whatever you want - calling it a + _ + bs
is just a convention.
We also need to setup our models to use the join table.
class User < ActiveRecord::Base
has_many :language_users
has_many :languages, through: :language_users
end
class Language < ActiveRecord::Base
has_many :language_users
has_many :users, through: :language_users
end
# this is a join model that links User & Language
class LanguageUser < ActiveRecord::Base
belongs_to :user
belongs_to :language
end
To create a form element where users can select languages you would use:
<%= f.collection_select(:languages_ids, Language.all, :id, :name, multiple: true) %>
Or:
<%= f.collection_check_boxes(:languages_ids, Language.all, :id, :name) %>
languages_ids
is a special accessor that ActiveRecord creates for has_many
associations that lets you set multiple associations at one by passing an array of ids.
Upvotes: 3