Forum: Ruby on Rails Association properties

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
1cbcd04f1aa12775ce0f51d847bb4849?d=identicon&s=25 Lee Iverson (leei)
on 2005-11-21 20:10
(Received via mailing list)
One of the great advantages of relational modelling (over typical object
modelling) is the ability to easily extend an association (i.e. an
association table) with properties of the association itself.  In
general O/R mappings make this very difficult to access or take
advantage of.  RoR certainly makes the association properties available
by grabbing the association properties due to their participation in the
join, but I haven't yet figured out how to manage update of these
properties.

An example of this is below.  The question is, how can I update
'indirect_count', 'created_at' and `created_by` properties of the
association table when I add a member to a group? Do I need to add the
proper instance variables to the Actor object that I am adding to the
members set?  Or do I need to go to the SQL itself?  Maybe this should
be a FAQ?

--- MySQL ---
CREATE TABLE `users` (
  `id` int(11) NOT NULL auto_increment,
  `type` varchar(16) default 'null',
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `group_members` (
  `group_id` int(11) NOT NULL default '0',
  `member_id` int(11) NOT NULL default '0',
  `indirect_count` int(11) NOT NULL default '0',
  `created_at` datetime NOT NULL default '0000-00-00 00:00:00',
  `created_by` int(11) NOT NULL default '0',
  KEY `group_id` (`group_id`),
  KEY `member_id` (`member_id`),
  KEY `created_by` (`created_by`),
  CONSTRAINT `group_members_ibfk_3` FOREIGN KEY (`member_id`) REFERENCES
`users` (`id`),
  CONSTRAINT `group_members_ibfk_4` FOREIGN KEY (`group_id`) REFERENCES
`users` (`id`)
  CONSTRAINT `group_members_ibfk_5` FOREIGN KEY (`created_by`)
REFERENCES `users` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

--- actor.rb ---
class Actor < ActiveRecord::Base
  set_table_name 'users'
  has_and_belongs_to_many :groups, :join_table => 'group_members',
:foreign_key => 'member_id'
end

class Person < Actor
end

class Group < Actor
  has_and_belongs_to_many :members, :class_name => 'Actor', :join_table
=> 'group_members'
end

----
A2c85dc5ee81b12e3cc0a6522e8d079d?d=identicon&s=25 christopher.k.hall (Guest)
on 2005-11-21 20:54
(Received via mailing list)
I think maybe you are overcomplicating it...here's a simple example of
(i
think) what you are trying to accomplish. It's possible I'm not
understanding as well, so correct me if I am wrong.

users
----------
id
name
created_at

groups
----------
id
name
creator_id
created_at

groups_users (join table)
----------
group_id
user_id
date_joined

class User < ActiveRecord::Base
has_and_belongs_to_many :groups

def join_group(group, creator)
groups.push_with_attributes(group, :date_joined => Time.now, :creator_id
=>
creator.id <http://creator.id>)
end
end

class Group < ActiveRecord::Base
has_and_belongs_to_many :users

def add_user(user, creator)
users.push_with_attributes(user, :date_joined => Time.now, :creator_id
=>
creator.id <http://creator.id>)
end
end

this way you can do:

user = User.create(:name => "Bob")
group = Group.create(:name => "Geeks-R-Us")

# add a user/group association
user.join_group(group, user)
# or group.add_user(user, user)

# how many users in each group
groups = Group.find(:all)
groups.each do { |g| puts "group: #{g.name <http://g.name>}, members: #{
g.users.size}" }

# how many groups does user belong to
user.groups.size

# remove a user/group association
user.groups.delete(group)
# or group.users.delete(user)

hope this helps
1cbcd04f1aa12775ce0f51d847bb4849?d=identicon&s=25 Lee Iverson (leei)
on 2005-11-21 21:14
(Received via mailing list)
Chris Hall wrote:

> I think maybe you are overcomplicating it...here's a simple example of
> (i think) what you are trying to accomplish.  It's possible I'm not
> understanding as well, so correct me if I am wrong.
>
Actually, I'm not overcomplicating it, but 'push_with_attributes' is the
right answer it seems. Since a Group can contain other groups, I need
the inheritance I showed.  Thanks for the pointer.  It's still a bit
annoying that I have to make explicit reference to 'creator_id', but
that's the price of putting this information into the association table.
A2c85dc5ee81b12e3cc0a6522e8d079d?d=identicon&s=25 christopher.k.hall (Guest)
on 2005-11-21 22:39
(Received via mailing list)
if a group can belong to group, take a look at acts_as_tree:

groups
----------
id
parent_id (can be null)
name

class Group < ActiveRecord::Base
has_and_belongs_to_many :users
acts_as_tree

...
end

root_group = group.create(:name => "Root Group")
child_group = group_a.children.create(:name => "Child Group")

acts_as_tree ==>
http://api.rubyonrails.com/classes/ActiveRecord/Ac...
1cbcd04f1aa12775ce0f51d847bb4849?d=identicon&s=25 Lee Iverson (leei)
on 2005-11-21 22:43
(Received via mailing list)
Chris Hall wrote:

> if a group can belong to group, take a look at acts_as_tree:

Yes, but a group (or user) can itself potentially belong to many other
groups...  Trust me, I do know what I'm modelling.
Af95bdaf87958c40150b813e94381bfd?d=identicon&s=25 Christer Nilsson (christer)
on 2005-11-21 23:46
Can you specify the operations you want to do with some fixtures and
test cases?

fixtures:
G 1,2 (group 1 belongs to group 2)
G 1,3
G 4,3
G 4,5
U 6,4 (user 6 belongs to group 4)

tests:
UserBelongsToGroup(6,1)=false
UserBelongsToGroup(6,2)=false
UserBelongsToGroup(6,3)=true
UserBelongsToGroup(6,4)=true
UserBelongsToGroup(6,5)=true
UsersGroups(6)=[3,4,5] (All groups a user belongs to)
GroupsUsers(3)=[6] (All users belonging to a group)

The tables are ok, presuming Type is used to separate between user and
group.
After your confirmation, it's possible to dig into implementation.
Af95bdaf87958c40150b813e94381bfd?d=identicon&s=25 Christer Nilsson (christer)
on 2005-11-22 00:08
Maybe this link could be helpful:

http://wiki.rubyonrails.com/rails/pages/HowToCreat...
This topic is locked and can not be replied to.