# Uniqueness on has\_many associations

**URL:** <https://www.ruby-forum.com/t/uniqueness-on-has-many-associations/157013>\
**Category:** Rails\
**Created:** [January 6, 2009, 2:03pm UTC](https://www.ruby-forum.com/t/uniqueness-on-has-many-associations/157013 "2009-01-06T14:03:03Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![tron](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/3da27b/32.png) [@tron](https://www.ruby-forum.com/u/tron)\
**Post date:** [January 6, 2009, 2:03pm UTC](https://www.ruby-forum.com/t/uniqueness-on-has-many-associations/157013/1 "2009-01-06T14:03:03Z")

</div>

Dear List,

This may not be rails unique but what is the best practice to validate  
the uniqueness of has\_many associations.  
In particular the models are

class Word  
end

class PhraseComponent  
belongs\_to :word  
belongs\_to :dictionary\_entry  
acts\_as\_list :scope =\> :dictionary\_entry  
end

class DictionaryEntry  
has\_many :phrase\_components  
has\_many :words, :through =\> :phrase\_components  
end

Dictionary entries (words and phrases) are composed of words (which  
are uniq)  
and I want to check the same phrase occurs only once in the  
DictionaryEntry table.

Is there a better or more efficient way to do this than create and  
update a footprint  
of the word associations on dictionary entries?  
This means I would have a string field in the dictionary\_entries table  
which is a concatenation of  
the associated words and would check the uniquness of that.

If we generalize the problem, we need to assure uniqueness of lists of  
arbitrary objects (where a list is via a join table), in that case the  
only representation that I can create on the list is the concatenation  
of ids of list items and check the uniqueness of this?  
I begin to think there must be a more canonical way to handle this.  
Any help appreciated

Viktor

I found someone asking the same question but no reply followed.

[http://groups.google.com/group/rubyonrails-talk/browse\_thread/thread/e4b61e90dfaa7a8/4f6e24aa5863585a?hl=en&lnk=gst&q=has\_many+uniqueness#4f6e24aa5863585a](http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/e4b61e90dfaa7a8/4f6e24aa5863585a?hl=en&lnk=gst&q=has_many+uniqueness#4f6e24aa5863585a)

---

<div class="post-metadata">

**Author:** ![tron](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/3da27b/32.png) [@tron](https://www.ruby-forum.com/u/tron)\
**Post date:** [January 7, 2009, 5:50pm UTC](https://www.ruby-forum.com/t/uniqueness-on-has-many-associations/157013/2 "2009-01-07T17:50:14Z")

</div>

Hello,  
I am still trying to find a solution to this.  
Please feel free to throw any ideas at me or help me find the  
appropriate forum.  
Thank you  
V

---

<div class="post-metadata">

**Author:** ![tron](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/3da27b/32.png) [@tron](https://www.ruby-forum.com/u/tron)\
**Post date:** [January 7, 2009, 6:45pm UTC](https://www.ruby-forum.com/t/uniqueness-on-has-many-associations/157013/3 "2009-01-07T18:45:20Z")

</div>

tron wrote:

> class Word  
> end
> 
> class PhraseComponent  
> belongs\_to :word  
> belongs\_to :dictionary\_entry  
> acts\_as\_list :scope =\> :dictionary\_entry  
> end
> 
> class DictionaryEntry  
> has\_many :phrase\_components  
> has\_many :words, :through =\> :phrase\_components  
> end

Well from the database side of thing that’s easily solved by adding a  
unique index across the two foreign keys in the join table. That would  
definitely prevent duplicates in the join table.

CREATE UNIQUE INDEX idx\_word\_dictionary\_entry ON phrase\_components  
(word\_id, dictionary\_entry\_id);

From the Rails side you might be able to use something like the  
following example:

class TeacherSchedule \< ActiveRecord::Base  
validates\_uniqueness\_of :teacher\_id, :scope =\> [:semester\_id,  
:class\_id]  
end

Maybe (untested):

class PhraseComponent \< ActiveRecord::Base  
validates\_uniqueness\_of :word\_id, :scope =\> :dictionary\_entry  
validates\_uniqueness\_of :dictionary\_entry\_id, :scope =\> :word\_id  
end

Note: This may be an expensive method for validating uniqueness!

In any of the cases mentioned you’ll still have issues related to  
“Optimistic Concurrency Control:”

> **[Optimistic concurrency control](https://en.wikipedia.org/wiki/Optimistic_concurrency_control)**
>
> Optimistic concurrency control (OCC), also known as optimistic locking, is a concurrency control method applied to transactional systems such as relational database management systems and software transactional memory. OCC assumes that multiple transactions can frequently complete without interfering with each other. While running, transactions use data resources without acquiring locks on those resources. Before committing, each transaction verifies that no other transaction has modified the dat...

This section of the Rails documentation has a good explanation of these  
issues and some options on how to solve them:  
[http://www.railsbrain.com/api/rails-2.2.2/doc/index.html?a=M001824&name=validates\_uniqueness\_of](http://www.railsbrain.com/api/rails-2.2.2/doc/index.html?a=M001824&name=validates_uniqueness_of)

---

<div class="post-metadata">

**Author:** ![tron](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/3da27b/32.png) [@tron](https://www.ruby-forum.com/u/tron)\
**Post date:** [January 7, 2009, 8:58pm UTC](https://www.ruby-forum.com/t/uniqueness-on-has-many-associations/157013/4 "2009-01-07T20:58:42Z")

</div>

Hello Robert,

You misunderstood my problem I guess.

Think of bora as a unique word, with id 1.  
there is a dictionary entry for bora bora with id 2  
then the phrase components representing this association are not  
unique in word\_id X dictionary\_id (both are 1,2)  
only word\_id and dictionary\_id AND list index (position) meaning  
there can only be one word on the same position of a list.

The real problem is that I want to make sure  
bora bora is entered only once in the dictionary.

For those who like more examples, think of travel itineraries  
(which are a list of cities, say New York - London - Paris - Budapest)  
Cities are a table, Itineraries are another and there is a join  
model (Visits) which acts as a list.

How do I make sure an itinerary is created only once?

Thanks a million all

Vik

On Jan 7, 5:45 pm, Robert W. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)
