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
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
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
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.
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