Rating Model and DB Relationships

I am still learning Rails and the relationships are still a little
confusion. So I apologize in advance for the repetition of this
question.

I am building a user rating system for words and quotes. If I wanted a
user to be able to rate a word or quote only once, how can I set up
the ratings table so it will have the appropriate relationships. Since
the rating model is a bit polymorphic (rate words or quotes), I am not
sure if I need a "bridge table". I want to be able to do things like

word.rating.value
quote.rating.value
user.rating.value

Any direction is greatly appreciated, and if you can throw in some
comments behind the code, even better. Also, would you suggest putting
the only one rating per user constraint in the db or as a
validate_unique..

Thanks,
Jason

To quickly answer your second question, you need both. The reason for
that is that validates_uniqueness_of does not guarantee fully unique
column values, since it's at the application level. The unique
constraint in the db schema can be viewed as a backup.

I'll answer your main question shortly.

Thanks for the initial response. I look forward to the main answer.

Srdjan Pejic wrote:
[...]

The unique
constraint in the db schema can be viewed as a backup.

I'll answer your main question shortly.

A philosophical quibble: in my opinion, it is the unique constraint in
the DB that should be considered primary. The validation in the
application layer is only there to prevent the DB from throwing
duplicate key errors. Application-level validation cannot replace a
properly constructed database schema.

I'll get off my soapbox now...I just want to make it clear that the
database layer is the *only* place where it is possible to have airtight
integrity checking.

Best,

I appreciate the debate, and I agree the constraint should be the DB
as a primary.

Back to my main question though - how should the relationships be set
up for a rating system?

I don't know if STI is appropriate here.

You should probably have a model called Rating which is the many side
of one-to-many with the User model. The Rating model should be
polymorphic so that you can use it to rate both Word and Quote
objects.

So, it would most likely look like this:

class User
  :has_many => :ratings
end

class Rating
  :belongs_to => :user
  :belongs_to => :rated, :polymorphic => true
end

class Word
  :has_one :rating, :as => :rated
end

class Quote
  :has_one :rating, :as => :rated
end

The ratings table needs to have rated_id (integer) and rated_owner
(string) as columns in order to support the polymorphic behaviour.
What this will give you is a collection of ratings for a user (the
logic of adding this is something you need to figure out), and each
Rating instance will have a property called *rated*. That will reach
in and grab either the Quote or the Word being rated. The score, or
however you're rating them, needs to be in the Rating model.

Let me know if you need more clarification.

I don't know if STI is appropriate here.

You should probably have a model called Rating which is the many side
of one-to-many with the User model. The Rating model should be
polymorphic so that you can use it to rate both Word and Quote
objects.

So, it would most likely look like this:

class User
  :has_many => :ratings
end

class Rating
  :belongs_to => :user
  :belongs_to => :rated, :polymorphic => true
end

class Word
  :has_one :rating, :as => :rated
end

class Quote
  :has_one :rating, :as => :rated
end

The ratings table needs to have rated_id (integer) and rated_owner
(string) as columns in order to support the polymorphic behaviour.
What this will give you is a collection of ratings for a user (the
logic of adding this is something you need to figure out), and each
Rating instance will have a property called *rated*. That will reach
in and grab either the Quote or the Word being rated. The score, or
however you're rating them, needs to be in the Rating model.

Let me know if you need more clarification.

Those should be has_many...

I'm not sure if I understand you here. You mean that Word and Quote
should have more than one rating per instance? That's why I put them
as has_one.