Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I pass multiple attributes to find_or_create_by in Rails 3?

I want to use find_or_create_by, but this statement does NOT work. It does not "find" or "create" with the other attributes.

productproperty = ProductProperty.find_or_create_by_product_id(:product_id => product.id, :property_id => property.id, :value => d[descname])

There seems to be very little, or no, information on the use of dynamic finders in Rails 3. "and"-ing these together gives me a an unknown method error.

UPDATE:

Originally I couldn't get the following to work. Please assume I'm not an idiot and "product" is an instance of Product AR model.

product.product_properties.find_or_create_by_property_id_and_value(:property_id => 1, :value => "X")

The error methods was:

no such keys: property_id, value

I couldn't figure that out. Only this morning did I find the reference to passing the values like this instead:

product.product_properties.find_or_create_by_property_id_and_value(1, "X")

And voilá, it works fine. I would have expected a hash to work in the same situation but I guess not.

So I guess you get a down vote if you miss something on the internet?

like image 948
AKWF Avatar asked Oct 22 '10 13:10

AKWF


2 Answers

If you want to search by multiple attributes, you can use "and" to append them. For example:

productproperty = ProductProperty.find_or_create_by_product_id_and_property_id_and_value(:product_id => product.id, :property_id => property.id, :value => d[descname])

There is one minor catch to be aware of. It will always return the object you've specified, even if that object can't be saved due to validation errors. So make sure you check to see if the returned object has an id (or is_valid?). Don't assume its in the database.

Alternatively, you can use the 'bang' version of the method to raise an error if the object cannot be saved:

http://guides.rubyonrails.org/active_record_querying.html#find-or-create-by-bang

This applies to Rails 3.

like image 178
Lelon Avatar answered Oct 22 '22 07:10

Lelon


See http://api.rubyonrails.org/classes/ActiveRecord/Base.html:

With single query parameter:

productproperty = ProductProperty.find_or_create_by_product_id(product.id) { |u| u.property_id => property_id, u.value => d[descname] } )

or extended with multiple parameters:

productproperty = ProductProperty.find_or_create_by_product_id(:product_id => product.id, :property_id => property_id, :value => d[descname]) { |u| u.property_id => property_id, u.value => d[descname] } )

Would work with:

conditions = { :product_id => product.id, 
               :property_id => property.id,
               :value => d[descname] }

pp = ProductProperty.find(:first, :conditions => conditions) || ProductProperty.create(conditions) 
like image 23
BvuRVKyUVlViVIc7 Avatar answered Oct 22 '22 06:10

BvuRVKyUVlViVIc7