Skip to main content

Use Multiple Checkboxes on a Rails Form

Rails • Asked by Brent Phillips

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?


Can you telll us a bit more about your database schema?


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.


Login or Create An Account to join the conversation.

Subscribe to the newsletter

Join 27,623+ developers who get early access to new screencasts, articles, guides, updates, and more.

    By clicking this button, you agree to the GoRails Terms of Service and Privacy Policy.

    More of a social being? We're also on Twitter and YouTube.