has_many :through equivalent of :uniq option on habtm?

On has_and_belongs_to_many relationships you can use the :uniq option to ensure that duplicate records in the association table don't generate duplicate ActiveRecord objects when you traverse the relationship.

Is there any way to achieve the same effect when using a has_many :through relationship?

I can use:

   has_many :things, :through => :assocation_table, :select => 'DISTINCT things.*'

but that then precludes the use of :include when doing a find on the relationship.

Pete Yandell

You could add validation to your join model to disallow records that will cause duplicate entries when accessing the has_many :through association.


In this case I can't do that, because I'm doing a three-way association. So let's say my join table has:

id a_id b_id c_id 1 1 1 1 2 1 1 2

Now I want to get all the unique As corresponding to B id 1. How do I do it? (Assume there might be lots of As for a B, and I want to be able to do pagination, so would rather do the uniqueness test in the database rather than in Ruby.)

Obviously I can't put the validation you suggest on my join table, because then I can't have a particular combination of As and Bs linked to multiple Cs.

(There's a good chance that I need to re-evaluate my model, but I've looked at it from about twenty different angles and still haven't found a way of representing things that seems more comfortable.)

Pete Yandell

Can you not enforce uniqueness in the DB itself with a unique index? (And, SHOULD you not for some reason?)

Can you not enforce uniqueness in the DB itself with a unique index? (And, SHOULD you not for some reason?)

I thought I'd explained this pretty well, but I guess not. :slight_smile:

On what should I put the unique index? If I put it just on the pair
of a_id and b_id then I can no longer represent arbitrary 3-way
associations...even the simple example I gave would be ruled out. If
I put the unique index on the combination of a_id, b_id, and c_id
then it still doesn't solve my problem when querying a B for all
associated As, or vice versa.

The :uniq option on has_many :through in edge since May, and will be available in Rails 1.2 in a few weeks if you don't want to go the edge way.

Thanks Josh, that's very handy to know.

I don't really understand the problem you are trying to solve, but I've had no trouble using the :uniq option, the :select => 'DISTINCT *' option, or a unique index in the database. I've done all three at different times and each works as I'd expect.

I seem to have singularly failed to explain my problem in a way that anybody other than me can understand! Oh well, I've somehow ended up with a couple of useful answers anyway. :slight_smile:


Pete Yandell