Goal: A user can create a User account (devise), and subsequently a Group. Each User only belongs_to
one group and a group has_many
Users.
After creating and running the Migrations - If I attempt to create a User i’m being presented with the following error: “1 error prohibited this user from being saved: Group must exist”.
Clearly the current setup wants a group_id to exist when creating a user.
@group.user_id = current_user.id
in GroupsController#create
a suitable way to assign the creating user to the group? I tried to do this in the Groups model, by using a callback but I wasn’t able to access the current_user
variable.unique => true
in the schema?.
class Group < ApplicationRecord
has_many :users
validates :users, presence: true
end
class User < ApplicationRecord
...
belongs_to :group
...
end
class GroupsController < ApplicationController
...
def create
@group = Group.new(group_params)
@group.user_id = current_user.id
...
end
...
private
...
def group_params
params.require(:group).permit(:name, :user_id)
end
...
end
class AddGroupReferenceToUser < ActiveRecord::Migration[5.0]
def change
add_reference :users, :group, foreign_key: true
end
end
class AddUserReferenceToGroup < ActiveRecord::Migration[5.0]
def change
add_reference :groups, :user, foreign_key: true
end
end
ActiveRecord::Schema.define(version: 20160903125553) do
create_table "groups", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.index ["user_id"], name: "index_groups_on_user_id"
end
create_table "users", force: :cascade do |t|
...
t.integer "group_id"
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["group_id"], name: "index_users_on_group_id"
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
end
- Is a belongs_to / has_many association correct for this situation? Should this be a has_one?
To setup a relationship where a user can only belong to a single group but groups have many users then you are on the right track.
class Group < ActiveRecord::Base
has_many :users
end
class User < ActiveRecord::Base
belongs_to :group
end
belongs_to
places the foreign key column as users.group_id
. Using has_one
would place it on groups.user_id
column which would only allow a one to one mapping - a group could only have a single user.
- Should both migrations have a foreign key attribute?
No - only the the users
table should contain a foreign key. The AddUserReferenceToGroup
should be removed or you should write another migration which removes the groups.user_id
column if you have pushed it to production.
- Is setting
@group.user_id = current_user.id
inGroupsController#create
a suitable way to assign the creating user to the group?
No - since the group_id
column is on the users
column you need to update the users table - not groups.
if @group.save
current_user.update(group: @group)
end
- I would also like to enforce (at the database level) that a user can only belong to one group - Is this achieved using unique => true in the schema?
No - since a row on the users
table can only have one id in the groups_id
column a user can only belong to one group anyways. Using unique => true
would create a uniqueness index on the users.groups_id
column which would only allow a single users to be associated with a group.
- How can I enforce (at the database level) that a group must have a user?
This is not actually possible. To be able to associate a user with a group you must first insert the group into the database so that it is assigned a id.
Adding a validation on the software level would also create a "chicken vs egg" situation where a group cannot be valid since it has no users and a user cannot be associated with a group since it is not persisted.
You can however setup a constraint on the belongs_to
end by declaring the foreign key column as NOT NULL
.