public
Last active

  • Download Gist
gistfile1.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
class User < ActiveRecord::Base
attr_accessible :name
 
has_many :admin_memberships, class_name: "Membership", conditions: {role: 'admin'}
has_many :editor_memberships, class_name: "Membership", conditions: {role: 'editor'}
 
def admin?
admin_memberships.exists?
end
 
def editor?
editor_memberships.exists?
end
end
 
class Group < ActiveRecord::Base
attr_accessible :name
 
has_many :admin_memberships, class_name: "Membership", conditions: {role: "admin"}
has_many :editor_memberships, class_name: "Membership", conditions: {role: "editor"}
has_many :admins, through: :admin_memberships, source: :user
has_many :editors, through: :editor_memberships, source: :user
end
 
class Membership < ActiveRecord::Base
attr_accessible :role
 
belongs_to :user
belongs_to :group
end
 
sam = User.new name: "Sam"
# => #<User id: 1, name: "Sam", created_at: "2012-04-05 11:45:54", updated_at: "2012-04-05 11:45:54">
rainbows = Group.new name: "Rainbows"
# => #<Group id: 1, name: "Rainbows", created_at: "2012-04-05 11:46:06", updated_at: "2012-04-05 11:46:06">
rainbows.admins << sam
# => [#<User id: 1, name: "Sam", created_at: "2012-04-05 11:45:54", updated_at: "2012-04-05 11:45:54">]
rainbows.admin_memberships
# => [#<Membership id: 2, user_id: 1, group_id: 1, role: "admin", created_at: "2012-04-05 11:48:58", updated_at: "2012-04-05 11:48:58">]
user.admin?
# Membership Exists (0.3ms) SELECT 1 FROM "memberships" WHERE "memberships"."user_id" = 1 AND "memberships"."role" = 'admin' LIMIT 1
# => true

You just helped me a great deal to simplify my code (from ~10 lines of very cluttered and ununderstandable has_many definitions to 2 very clean lines).
But I have a question where you can maybe help: would it be possible to set the role attribute also when calling build on the has_many relation?
I would like to be able to do this:

rainbows = Group.new name: "Rainbows"
rainbows.admins.build(name: "Sam")

Very nice. Note that the conditions syntax is very different in Rails 4

http://guides.rubyonrails.org/association_basics.html#the-has-many-association

And if you (like me) are tempted to use Rails 4.1 enums, the syntax is a bit more interesting pending the outcome of these:

https://github.com/rails/rails/issues/13918
https://github.com/rails/rails/pull/13433

In my case, I have the role in the Membership table (so Users can have a different role per Group) and here is what I'm using in gem 'rails', '4.1.0.beta1'

class Group
  has_many :admins, -> { where role: Membership::ROLE[:admin] }, class_name: 'Membership'

Here is the enum declaration

  enum role: {
    reader:   10,
    editor:   20,
    admin:    30
  }

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.