# Using 'validates\_inclusion\_of' to validate foreign key

**URL:** <https://www.ruby-forum.com/t/using-validates-inclusion-of-to-validate-foreign-key/61758>\
**Category:** Rails\
**Created:** [May 26, 2006, 10:30pm UTC](https://www.ruby-forum.com/t/using-validates-inclusion-of-to-validate-foreign-key/61758 "2006-05-26T22:30:55Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![mgreenly](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/85f322/32.png) [@mgreenly](https://www.ruby-forum.com/u/mgreenly)\
**Post date:** [May 26, 2006, 10:30pm UTC](https://www.ruby-forum.com/t/using-validates-inclusion-of-to-validate-foreign-key/61758/1 "2006-05-26T22:30:55Z")

</div>

I seem to be missing something trying to use ‘validates\_inclusion\_of’ to  
validate a foreign key and was hoping some one could piont out my  
mistake?

The problem seems to be that Order.find\_all.collect is not returning an  
array that contains the order\_id, if I replace it with a hardcoded array  
everything works as expected.

The model:

class OrderItem \< ActiveRecord::Base  
validates\_inclusion\_of :order\_id, :in =\> Order.find\_all.collect {  
|order| order.id }  
belongs\_to :order  
end

The test:

class OrderItemTest \< Test::Unit::TestCase  
fixtures :orders, :order\_items  
def test\_validates\_inclusion\_of\_order\_id\_in\_orders  
orderitem = OrderItem.new(:order\_id =\> 1)  
assert( orderitem.save, orderitem.errors.full\_messages.join(‘\n’))  
end  
end

The fixture:  
first:  
id: 1  
sid: ‘ON001’

All of the code can be found at [http://metaspot.net/dev/browser/?rev=46](http://metaspot.net/dev/browser/?rev=46)

---

<div class="post-metadata">

**Author:** ![mgreenly](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/85f322/32.png) [@mgreenly](https://www.ruby-forum.com/u/mgreenly)\
**Post date:** [May 26, 2006, 11:41pm UTC](https://www.ruby-forum.com/t/using-validates-inclusion-of-to-validate-foreign-key/61758/2 "2006-05-26T23:41:55Z")

</div>

Michael G. wrote:

> The problem seems to be that Order.find\_all.collect is not returning an  
> array that contains the order\_id, if I replace it with a hardcoded array  
> everything works as expected.

Guess I’ll respond to my own post…

This was most likley a bad idea anyway. I really don’t want to suck an  
entire table index into an array every time I want to create or update a  
new row. I should of just created a validation that did something like  
this…

def validate  
begin  
Order.find(self.order\_id)  
rescue ActiveRecord::RecordNotFound  
errors.add(:order\_id, “invalid foreign key reference”)  
end  
end

---

<div class="post-metadata">

**Author:** ![mgreenly](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/85f322/32.png) [@mgreenly](https://www.ruby-forum.com/u/mgreenly)\
**Post date:** [May 26, 2006, 11:49pm UTC](https://www.ruby-forum.com/t/using-validates-inclusion-of-to-validate-foreign-key/61758/3 "2006-05-26T23:49:18Z")

</div>

You might have difficulty using :in =\> to achieve that. A custom  
validation is probably in order. For performance reasons, it’s  
probably worth adding a method to ActiveRecord::Base to select just  
the model ids. That will save you from having to instantiate all the  
model objects each time the validation occurs.

class ActiveRecord::Base  
def self.ids  
connection.select\_values(“select #{primary\_key} from  
#{table\_name}”).collect(&:to\_i)  
end  
end

class OrderItem  
belongs\_to :order

def validate  
errors.add\_to\_base “Invalid order” unless  
Order.ids.include?(order\_id)  
end  
end

-Jonathan

---

<div class="post-metadata">

**Author:** ![mgreenly](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/85f322/32.png) [@mgreenly](https://www.ruby-forum.com/u/mgreenly)\
**Post date:** [May 27, 2006, 2:02am UTC](https://www.ruby-forum.com/t/using-validates-inclusion-of-to-validate-foreign-key/61758/4 "2006-05-27T02:02:28Z")

</div>

That is probably a better approach. Using Order.exists? will make the  
code a bit shorter:

errors.add\_to\_base ‘Invalid order’ unless Order.exists?(order\_id)

-Jonathan.

---

<div class="post-metadata">

**Author:** ![mgreenly](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/85f322/32.png) [@mgreenly](https://www.ruby-forum.com/u/mgreenly)\
**Post date:** [May 27, 2006, 4:06am UTC](https://www.ruby-forum.com/t/using-validates-inclusion-of-to-validate-foreign-key/61758/5 "2006-05-27T04:06:14Z")

</div>

Jonathan V. wrote:

> That is probably a better approach. Using Order.exists? will make the  
> code a bit shorter:
> 
> errors.add\_to\_base ‘Invalid order’ unless Order.exists?(order\_id)
> 
> -Jonathan.

Much better, it’s starting to look a bit more like ruby… now that it’s  
been expressed in a single line 😉

Thanks
