# Has\_many with :uniq not working for me

**URL:** <https://www.ruby-forum.com/t/has-many-with-uniq-not-working-for-me/78396>\
**Category:** Rails\
**Created:** [December 5, 2006, 3:41pm UTC](https://www.ruby-forum.com/t/has-many-with-uniq-not-working-for-me/78396 "2006-12-05T15:41:19Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![liquid](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/47e85d/32.png) [@liquid](https://www.ruby-forum.com/u/liquid)\
**Post date:** [December 5, 2006, 3:41pm UTC](https://www.ruby-forum.com/t/has-many-with-uniq-not-working-for-me/78396/1 "2006-12-05T15:41:19Z")

</div>

Hi all,

I have a relationship (no really!)

class RiskMatrix \< ActiveRecord::Base  
has\_many :severities, :order =\> :position, :uniq =\> true  
end

class RiskFactor \< ActiveRecord::Base

```
belongs_to :risk_matrix

validates_presence_of :descriptor, :example
validates_uniqueness_of :descriptor, :example, :scope=> 

```

:risk\_matrix\_id  
end

class Severity \< RiskFactor  
acts\_as\_list :scope =\> :risk\_matrix  
end

I don’t want any duplicates for a given risk matrix of a risk factor so  
I  
wrote a couple of tests. Both of them fail but I’m not sure why.

def test\_no severity should be duplicated for a risk\_matrix  
sev = @rm.severities.find(:first ) # @rm is a risk matrix set during  
setup  
@rm.severities \<\< sev  
assert\_equal 1, @rm.severities.select{ |s| s == sev }.size  
end

def test\_descriptor should be uniq for a given risk matrix  
@sev = Severity.find(:first )  
@rm = @sev.risk\_matrix  
@rm.severities \<\< @sev.dup  
assert\_equal 1, @rm.severities.select{|s| s.descriptor == @  
sev.descriptor }.size  
end

The uniq option doesn’t seem to be doing anything. Am I using it  
incorrectly?

Thanx to anyone who can help me.

Cheers  
Daniel

---

<div class="post-metadata">

**Author:** ![liquid](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/47e85d/32.png) [@liquid](https://www.ruby-forum.com/u/liquid)\
**Post date:** [December 5, 2006, 11:35pm UTC](https://www.ruby-forum.com/t/has-many-with-uniq-not-working-for-me/78396/2 "2006-12-05T23:35:02Z")

</div>

Hi all… Sorry to bump but this is driving me nuts.

---

<div class="post-metadata">

**Author:** ![liquid](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/47e85d/32.png) [@liquid](https://www.ruby-forum.com/u/liquid)\
**Post date:** [December 6, 2006, 8:31am UTC](https://www.ruby-forum.com/t/has-many-with-uniq-not-working-for-me/78396/3 "2006-12-06T08:31:18Z")

</div>

Daniel ----- wrote:

> class RiskMatrix \< ActiveRecord::Base  
> has\_many :severities, :order =\> :position, :uniq =\> true  
> end
> 
> class RiskFactor \< ActiveRecord::Base
> 
> ```
> belongs_to :risk_matrix
> 
> validates_presence_of :descriptor, :example
> validates_uniqueness_of :descriptor, :example, :scope=> 
> 
> ```
> 
> :risk\_matrix\_id  
> end
> 
> class Severity \< RiskFactor  
> acts\_as\_list :scope =\> :risk\_matrix  
> end
> 
> I don’t want any duplicates for a given risk matrix of a risk factor so  
> I wrote a couple of tests. Both of them fail but I’m not sure why.
> 
> def test\_no severity should be duplicated for a risk\_matrix  
> sev = @rm.severities.find(:first ) # @rm is a risk matrix set during setup  
> @rm.severities \<\< sev  
> assert\_equal 1, @rm.severities.select{ |s| s == sev }.size  
> end
> 
> def test\_descriptor should be uniq for a given risk matrix  
> @sev = Severity.find(:first )  
> @rm = @sev.risk\_matrix  
> @rm.severities \<\< @sev.dup  
> assert\_equal 1, @rm.severities.select{|s| s.descriptor == @  
> sev.descriptor }.size  
> end
> 
> The uniq option doesn’t seem to be doing anything. Am I using it  
> incorrectly?

The :uniq option is really only useful for has\_many :through  
associations. How else would you get the same record in a has\_many  
association more than once? I don’t fully understand your modelling  
problem, but I’m guessing if you are worried about dupes you might be  
wanting to use a many-to-many mapping, like a has\_many :through. If not,  
and you just have a has\_many, you shouldn’t need to use :uniq.

What’s going on in your tests is that you are adding the sev object to  
the in-memory collection, then checking to see if it’s there, which it  
of course is. You haven’t saved anything to the database, or updated the  
in-memory collection with new content from the database. And since you  
aren’t saving your model, the validations don’t run, so the  
validates\_uniqueness\_of check won’t catch anything. Remember,  
ActiveRecord is an ORM system, and it only does something useful when  
you are either reading from or writing to the database.

If you want some examples of :uniq with has\_many :through, search in my  
blog for “uniq”. And you’re on the right track for the validation,  
you’ll just need to adjust for the new association.

–  
Josh S.  
[http://blog.hasmanythrough.com](http://blog.hasmanythrough.com)

---

<div class="post-metadata">

**Author:** ![liquid](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/47e85d/32.png) [@liquid](https://www.ruby-forum.com/u/liquid)\
**Post date:** [December 6, 2006, 11:43am UTC](https://www.ruby-forum.com/t/has-many-with-uniq-not-working-for-me/78396/4 "2006-12-06T11:43:06Z")

</div>

On 12/6/06, Josh S. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > I wrote a couple of tests. Both of them fail but I’m not sure why.  
> > @rm = @sev.risk\_matrix  
> > association more than once? I don’t fully understand your modelling  
> > ActiveRecord is an ORM system, and it only does something useful when  
> > you are either reading from or writing to the database.
> 
> If you want some examples of :uniq with has\_many :through, search in my  
> blog for “uniq”. And you’re on the right track for the validation,  
> you’ll just need to adjust for the new association.
> 
> –  
> Josh S.  
> [http://blog.hasmanythrough.com](http://blog.hasmanythrough.com)

Right on the money as usual. Thanx

My test ended up as follows:

specify “no severity should be duplicated for a risk\_matrix” do  
sev = @rm.severities.find(:first )  
@rm.severities \<\< sev  
@rm.save  
@rm.severities.reset  
assert\_equal 1, @rm.severities.select{ |s| s == sev }.size  
end

And  
specify “descriptor should be uniq for a given risk matrix” do  
@sev = Severity.find(:first )  
@rm = @sev.risk\_matrix  
sev = Severity.new( :descriptor =\> @sev.descriptor, :example =\>  
“this is  
some example”, :risk\_matrix =\> @rm )  
assert !sev.valid?  
end

I think it must’ve been a bit late for the second one last night because  
that seems really easy now.

The first test though seems to smell a bit. I don’t think I would  
remember  
to

```
@rm.severities << sev
@rm.save
@rm.severities.reset

```

everywhere in my code when I want to add a severity to the matrix.

Prior to this snippet, the RiskMatrix in @rm is read from the DB.

I also thought that the \<\< would automagically save the association.  
Do I  
need to do this everytime I want to add to the collecion?

Cheers  
Daniel

---

<div class="post-metadata">

**Author:** ![liquid](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/47e85d/32.png) [@liquid](https://www.ruby-forum.com/u/liquid)\
**Post date:** [December 6, 2006, 1:29pm UTC](https://www.ruby-forum.com/t/has-many-with-uniq-not-working-for-me/78396/5 "2006-12-06T13:29:24Z")

</div>

On 12/6/06, Daniel N [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > > acts\_as\_list :scope =\> :risk\_matrix  
> > > assert\_equal 1, @ rm.severities.select{ |s| s == sev }.size  
> > > The uniq option doesn’t seem to be doing anything. Am I using it  
> > > the in-memory collection, then checking to see if it’s there, which it
> 
> ```
> sev = @rm.severities.find(:first )
> sev = Severity.new ( :descriptor => @sev.descriptor, :example => "this
> @rm.severities << sev
> 
> ```
> 
> Cheers  
> Daniel

For posterities sake, the test

specify “no severity should be duplicated for a risk\_matrix” do  
sev = @rm.severities.find(:first )  
@rm.severities \<\< sev  
@rm.save  
@rm.severities.reset  
assert\_equal 1, @ rm.severities.select{ |s| s == sev }.size  
end

is a pain because I’ve selected the severities into an array. That’s  
why  
the severities need to be reset first. Instead, by using count on the  
association collection

specify “no severity should be duplicated for a risk\_matrix” do  
sev = @rm.severities.find(:first )  
initial\_severities = @rm.severities.count  
@rm.severities \<\< sev  
@rm.save  
assert\_equal initial\_severities, @rm.severities.count  
end

works as expected.
