Use Multiple Checkboxes on a Rails Form
Greetings,
I have a bit of a situation that I cannot find any good resources on and its driving me nuts! I have the following setup:
Gems: Devise, Rolify
Controllers: ProfilesController, UsersController
Models: Profile, User, and user_roles(its a join table)
All that I am trying to do is create a simple form partial to add and remove roles to users. I would like to use checkboxes to accomplish this. The form needs to be placed inside of a Profiles form.
So, what is the best strategy for doing this?
Schema
create_table "profiles", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
t.string "f_name", limit: 50
t.string "m_name", limit: 50
t.string "l_name", limit: 50
t.string "phone", limit: 12
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "roles", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
t.string "name"
t.string "resource_type"
t.integer "resource_id"
t.datetime "created_at"
t.datetime "updated_at"
t.index ["name", "resource_type", "resource_id"], name: "index_roles_on_name_and_resource_type_and_resource_id", using: :btree
t.index ["name"], name: "index_roles_on_name", using: :btree
end
create_table "users", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.string "username"
t.integer "status"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.boolean "archived", default: false
t.integer "failed_attempts", default: 0, null: false
t.string "unlock_token"
t.datetime "locked_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "workflow_state"
t.integer "organization_id"
t.integer "req_access_id"
t.index ["email"], name: "index_users_on_email", unique: true, using: :btree
t.index ["organization_id"], name: "index_users_on_organization_id", using: :btree
t.index ["req_access_id"], name: "index_users_on_req_access_id", using: :btree
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
t.index ["username"], name: "index_users_on_username", unique: true, using: :btree
end
```
```
create_table "users_roles", id: false, force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
t.integer "user_id"
t.integer "role_id"
t.index ["user_id", "role_id"], name: "index_users_roles_on_user_id_and_role_id", using: :btree
end
```
# HTML.ERB
```
<%= form_for @user do |f| %>
<%= f.collection_check_boxes(:role_ids, Role.all.order('id DESC'), :id, :name) do |b| %>
<div class="input-group mb-3">
<div class="input-group-prepend">
<div class="input-group-text">
<%= b.check_box %>
</div>
</div>
<%= b.label class: 'form-control text-center text-uppercase' %>
<% end %>
</div>
<%= f.submit "Assign Role", class: 'btn btn-primary btn-block' %>
<% end %>
Your profile table is not linked to the user which seems to be weird.
What you could do is sth like:
<%= form_for @user, html: { multipart: true } do |f| %>
<div class="form-group">
<%= f.label :role_ids, "User roles" %>
<%= f.collection_select :role_ids, Role.all.order(name: :asc), :id, :name, {}, { multiple: true, class: "form-control" } %>
<div class="explanation">Choose one or more roles</div>
</div>
</div>
....
<% end %>
Users controller
def new
@user = User.new
@user.user_roles.build
end
def create
@user = User.new(user_params)
if @user.save
........
end
def user_params
params.require(:product).permit(:name, ...., role_ids: [])
end
This is kinda the Rails convention. But all you have to do basically is showing the roles on the form to choose from. So you have to query those. In the code I added it to the view. If you like it more you can puy in the controller too. Then you have to send over the role ids that are chosen in the form. Of course you have to whitelist them. Then you can just save it to the db when user is saved. Nothing fancy.
The profile is linked to the user. A user has_one profile and a profile belongs_to a user. Also, the code provided produces a multiselect box. I am looking for a multiselect with checkbox solution.