Question

I have two models, Group and User. A user can create many groups and is then the owner of those groups. Other users can join those groups and therefore become members of those groups.

My question now is how to model this with Ruby on Rails.

I have created a join table between Group and Users and I added a reference from Group to the owner (foreign id to user).

Note: not sure if I did all this correctly.

Here are the attributes I currently have in Group and User (I don't know how to access the join table, so I can't show it to you).

Group: id, topic, home_town, created_at, updated_at, user_id

user_id was added with the following migration and I want it to reference the owner:

class AddOwnerReferenceToGroup < ActiveRecord::Migration
  def change
    add_reference :groups, :user, index: true
  end
end

User: id, name, email, password_digest, remember_token, created_at, updated_at

As for the relationships, here's what each class contains:

User -> has_many :groups

Group -> has_many :users

Is it possible (and do I have) to add a belongs_to relationship in the group class to reference to the owner?

Was it helpful?

Solution

I would set it up like so:

class User < ActiveRecord::Base
  has_many :group_users, :dependent => :destroy
  has_many :groups, :through => :group_users
  has_many :owned_groups, :through => :group_users, :class_name => "Group",  :conditions => ["group_users.owner = ?", true]
  ...
end

class Group < ActiveRecord::Base
  has_many :group_users, :dependent => :destroy
  has_many :users, :through => :group_users

  def owner
    self.users.find(:first, :conditions => ["group_users.owner = ?", true])
  end

  def owner=(user)
    if gu = self.group_users.find_by_user_id(user.id)
      gu.update_attributes(:owner => true)
    else
      self.group_users.create(:user_id => user, :owner => true)
    end
  end
  ...
end

#group_users table has fields user_id, group_id, owner(bool)
class GroupUser < ActiveRecord::Base
  belongs_to :group
  belongs_to :user

  after_save :enforce_single_owner

  def enforce_single_owner
    if self.changes["owner"] && self.owner
      GroupUser.find(:all, :conditions => ["group_id = ? and id <> ? and owner = ?", self.group_id, self.id, true]).each{|gu| gu.update_attributes(:owner => false)
    end
  end

  ...
end

In this schema, the join table model has responsibility for tracking which of the members of the group is the owner of the group. A group has many users, and one of those wil be the owner.

OTHER TIPS

Yes, it is possible and you should.

By adding to your Group

belongs_to :owner, class_name: 'User'

you can model your requirement that a group is created by one of the users.

In my snippet I used an arbitrary name in belongs_to just to make the code more readable. You don't have to but it definitely clears up things. The downside is that ActiveRecord cannot guess to which class you refer when using custom association names, thus, you need to manually specify it.

In a similar fashion you could change has_many :users to

has_many :members, class_name: 'User'

Whatever feels more natural when you read your code.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top