Skip to content

Instantly share code, notes, and snippets.

@jerhinesmith
Created March 11, 2012 21:48
Show Gist options
  • Save jerhinesmith/2018326 to your computer and use it in GitHub Desktop.
Save jerhinesmith/2018326 to your computer and use it in GitHub Desktop.
Simple has_many :through
###########
# Classes #
###########
class Group < ActiveRecord::Base
has_many :memberships,
:class_name => 'GroupUser'
has_many :users,
:through => :memberships,
:source => :user
has_many :owners,
:through => :memberships,
:source => :user,
:conditions => {'groups_users.role' => GroupUser::OWNER_ROLE}
has_many :newbies,
:through => :memberships,
:source => :user,
:conditions => {'groups_users.role' => GroupUser::NEWBIE_ROLE}
end
class User < ActiveRecord::Base
has_many :group_memberships,
:class_name => 'GroupUser',
:dependent => :destroy
has_many :groups,
:through => :group_memberships
end
class GroupUser < ActiveRecord::Base
OWNER_ROLE = 'owner'
NEWBIE_ROLE = 'newbie'
belongs_to :group
belongs_to :user
end
########
# So, I want a "group" to always have an owner, here's how I'm doing it now,
# I'm not enamored of this approach
########
# Add an attr_accessor and a callback to the Group class
class Group < ActiveRecord::Base
# Same shit as above
# New stuff
attr_accessor :created_by
after_create :set_owner
private
def after_create
memberships.create(:user => created_by) do |m|
m.role = GroupUser::OWNER_ROLE
end
end
end
# For Newbies, the shit is a little trickier, because I want to do
# things like validate roles for adding newbies, send invitation
# emails, etc. So, instead of trying to do all of that shit in
# the join model, I created a new class
class GroupNewbie
extend ActiveModel::Callbacks
include ActiveModel::Validations
# Attributes
attr_accessor :group_id, :created_by, :email, :user, :group
# Bunch of validations
# Bunch of callbacks
def save
_run_create_callbacks do
GroupUser.create(:user => user, :group => group) do |gu|
gu.role = GroupUser::NEWBIE_ROLE
end
end if valid?
end
end
# Then, in the controller, I can just do:
newb = GroupNewbie.new(:group_id => 1, :created_by => current_user, :email => 'newbie@example.com')
if newb.save
# blah
else
# worse blah
end
# So, that's where I'm at now. What I'd like to do... what feels most "Rails-ish"
# is this:
# Adding a newbie
# This does create the GroupUser record, but it doesn't populate the 'role' attribute
group = Group.find(params[:id])
group.newbies << User.find_by_email('newbie@example.com')
# Adding a new group
# This creates the Group record, but does NOT create the GroupUser record. Leading to
# the code mentioned above
group = current_user.groups.build(params[:group])
group.save
# What do you think?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment