# Tough modeling problem

**URL:** <https://www.ruby-forum.com/t/tough-modeling-problem/134888>\
**Category:** Rails\
**Created:** [April 15, 2008, 11:14pm UTC](https://www.ruby-forum.com/t/tough-modeling-problem/134888 "2008-04-15T23:14:48Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![Jables](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/58956e/32.png) [@Jables](https://www.ruby-forum.com/u/Jables)\
**Post date:** [April 15, 2008, 11:14pm UTC](https://www.ruby-forum.com/t/tough-modeling-problem/134888/1 "2008-04-15T23:14:48Z")

</div>

I have what I think is a fairly complex modeling problem for you guys.

So I have a user class. There are three link type classes: picture,  
video, and story. A user can vote, bookmark, and add any of those  
types. Essentially I want to be able to say:  
user.stories and get the stories the user has uploaded  
user.votes.stories and get the votes that are stories  
user.votes.videos and get the votes that are videos  
user.bookmarks.videos and get the bookmarks for the videos

So these are essentially join tables, but I can’t seem to get them to  
go properly, have tried polymorphism and has\_many\_polymorphs, limited  
success, limited knowledge.

Now I also want to be able to go the other way:

story.votes  
story.user  
story.bookmarks

I will be seriously impressed if anyone can tackle this

Thanks for the help,  
JB

---

<div class="post-metadata">

**Author:** ![Jables](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/58956e/32.png) [@Jables](https://www.ruby-forum.com/u/Jables)\
**Post date:** [April 15, 2008, 11:22pm UTC](https://www.ruby-forum.com/t/tough-modeling-problem/134888/2 "2008-04-15T23:22:26Z")

</div>

-----BEGIN PGP SIGNED MESSAGE-----  
Hash: SHA1

Jables wrote:  
| I have what I think is a fairly complex modeling problem for you guys.  
|  
| So I have a user class. There are three link type classes: picture,  
| video, and story. A user can vote, bookmark, and add any of those  
| types. Essentially I want to be able to say:  
| user.stories and get the stories the user has uploaded  
| user.votes.stories and get the votes that are stories  
| user.votes.videos and get the votes that are videos  
| user.bookmarks.videos and get the bookmarks for the videos  
|  
| So these are essentially join tables, but I can’t seem to get them to  
| go properly, have tried polymorphism and has\_many\_polymorphs, limited  
| success, limited knowledge.  
|  
| Now I also want to be able to go the other way:  
|  
| story.votes  
| story.user  
| story.bookmarks  
|  
| I will be seriously impressed if anyone can tackle this  
|  
| Thanks for the help,  
| JB

class Story \< ActiveRecord::Base  
~ has\_many :votes  
~ belongs\_to :user

~ end  
end

class User \< ActiveRecord::Base  
~ has\_many :stories  
~ has\_many :votes  
~ has\_many :stories\_voted\_on, :through =\> :votes, :source =\> :story  
end

class Vote \< ActiveRecord::Base  
~ belongs\_to :story, :counter\_cache =\> true  
~ belongs\_to :user

end

belongs\_to and has\_many and their friends are what you seek.

* * *

Phillip G.  
Twitter: [twitter.com/cynicalryan](http://twitter.com/cynicalryan)

~ - You know you’ve been hacking too long when…  
…your children do something they shouldn’t do, you tell them to stop,  
they  
do it just once more anyway, so you think “Well, they prefetched the  
instruction and are executing it in the delay slot.”  
-----BEGIN PGP SIGNATURE-----  
Version: GnuPG v1.4.8 (MingW32)  
Comment: Using GnuPG with Mozilla - [http://enigmail.mozdev.org](http://enigmail.mozdev.org)

iEYEARECAAYFAkgFHF8ACgkQbtAgaoJTgL+mOgCfbK0+naAuxc/btwkgbMCzUWWM  
wCcAn39aIRWnty2MugMBQM6GsaFeUiSB  
=KiQM  
-----END PGP SIGNATURE-----

---

<div class="post-metadata">

**Author:** ![Jables](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/58956e/32.png) [@Jables](https://www.ruby-forum.com/u/Jables)\
**Post date:** [April 15, 2008, 11:31pm UTC](https://www.ruby-forum.com/t/tough-modeling-problem/134888/3 "2008-04-15T23:31:52Z")

</div>

On 15 Apr 2008, at 22:13, Jables wrote:

> So these are essentially join tables, but I can’t seem to get them to  
> go properly, have tried polymorphism and has\_many\_polymorphs, limited  
> success, limited knowledge.
> 
> Now I also want to be able to go the other way:
> 
> story.votes  
> story.user  
> story.bookmarks

Well a user has\_many :videos (and the story :belongs\_to :user) which  
takes care of who uploaded what  
A user has\_many votes, has\_many bookmarks, again that’s not the  
complicated bit. From now on lets just think about bookmarks since  
it’s basically the same think at this point.

The bookmark model could belong\_to :user, and belongs\_to :  
bookmark\_content, :polymorphic =\> true  
Over on video, we can say video has\_many :bookmarks, :as =\>  
bookmark\_content

This takes care of video.bookmarks.

The only remaining bit is user.bookmarks.videos

off the top of my head you could solve it like this: replace the  
has\_many :bookmarks on user with

has\_many :bookmarks do  
def videos  
Video.find :all, :joins =\> :bookmarks, :conditions =\>  
[‘bookmarks.user\_id = ?’, proxy\_owner.id]  
end  
end

you can define bookmarks.stories, bookmarks.pictures in a similar way

Fred

---

<div class="post-metadata">

**Author:** ![Jables](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/58956e/32.png) [@Jables](https://www.ruby-forum.com/u/Jables)\
**Post date:** [April 15, 2008, 11:47pm UTC](https://www.ruby-forum.com/t/tough-modeling-problem/134888/4 "2008-04-15T23:47:41Z")

</div>

Thanks guys, it is becoming clear to me that I may have  
overcomplicated the issue.

---

<div class="post-metadata">

**Author:** ![Jables](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/58956e/32.png) [@Jables](https://www.ruby-forum.com/u/Jables)\
**Post date:** [April 16, 2008, 3:49am UTC](https://www.ruby-forum.com/t/tough-modeling-problem/134888/5 "2008-04-16T03:49:17Z")

</div>

Jables,

Fred’s suggestion is an excellent one: defining additional hooks right  
off the has\_many line. I’ve used that. In my case, I had: “user  
has\_many profiles” and then defined a “default” as an accessor off of  
that (using almost exactly the code Fred posted). Then, I could do:  
User.find(:first).profiles.default # =\> the profile flagged as  
“default” for that user.

You should be able to do exactly the same thing. So kudos to Fred.

Oh, and if you are really wanting the full association goodness, look  
at Nested “has\_many\_through”:  
[http://agilewebdevelopment.com/plugins/nested\_has\_many\_through](http://agilewebdevelopment.com/plugins/nested_has_many_through)

As that may do what you need.

Oh, and I also suggest rethinking. If you can capture your  
requirements with simpler associations, it’ll be much, much better in  
the long run.

Maybe stack different vote types using STI. I.e.: Vote (abstract  
class, even), VideoVote \< Vote, StoryVote \< Vote, etc.

Then you could say on the User class:  
has\_many :video\_votes  
has\_many :story\_votes  
etc.

Of course I could also envision trying to architect this using  
polymorphism and declaring a “votable” class, but that might  
overcomplicate things.

KISS (Keep It Simple, Sir!)

-Danimal

---

<div class="post-metadata">

**Author:** ![Jables](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/58956e/32.png) [@Jables](https://www.ruby-forum.com/u/Jables)\
**Post date:** [April 16, 2008, 7:31am UTC](https://www.ruby-forum.com/t/tough-modeling-problem/134888/6 "2008-04-16T07:31:35Z")

</div>

Thanks guys, great advice.
