Fearless Fool wrote:
> I'll preface this by saying I (still) consider myself a relative
> newcomer to Rails, and its likely that I'm missing something obvious in
> ActiveRecords, but this has been bugging me...
> 
> I've written a function that I use all the time, but I get a nagging
> feeling that this functionality MUST already exist, and even if it
> doesn't, there's a better way than I'm doing it.  Anyway, thus:
> 
>   ActiveRecord.create_or_update_if_needed(attrs_to_match,
> attrs_to_update)
> 
> which lets me do things like:
> 
>   Address.create_or_update_if_needed({:street=>"1600 Pennsylvania
> Avenue, NW", :state=>"DC"}, {:zip=>"20500"})
> 
> If no records match on attrs_to_match then create one with those
> attributes AND with attrs_to_update.  If a record does exist but doesn't
> match the given attrs_to_update, then update only those attributes.
> Otherwise, leave the record alone - no change needed.
> 
> If there's an obvious way to do this, you can stop reading here and
> simply give me the recipe!! :)

Well, update_all with the :conditions option will get you most of the 
way there.  And what do you want to have happen if more than one record 
matches the conditions?

> 
> Still reading?  Really?  Okay, here's how I've defined it:
> =====
> class ActiveRecord::Base
> 
>   def self.create_or_update_if_needed(attrs_to_match, attrs_to_update)
>     record = find(:first, :conditions=>attrs_to_match)
>     if (record.nil?)

Lose the parentheses -- if isn't a function.

>       record = create(attrs_to_match.merge(attrs_to_update))
>     elsif (!record.attributes_match?(attrs_to_update))
>       record.update_attributes(attrs_to_update)
>     end
>     record
>   end
> 
>   def attributes_match?(attrs)
>     # use new() to convert attribute keys and values
>     mangled_attrs = self.class.new(attrs).attributes
>     mangled_attrs.all? {|k,v| v.nil? || self.attributes[k] == v }
>   end
> 
> end
> =====
> Note that the "obvious" definition of attributes_match? would NOT work:
> 
>   def attributes_match?(attrs)
>     attrs.all? {|k,v| self.attributes[k] == v}
>   end
> 
> ... because self.attributes use strings as hash keys, not symbols, and
> attribute values may be subject to type conversions.  

Then try HashWithIndifferentAccess or stringify_keys.  You're 
overcomplicating this.

> So I create a new
> record, using the given attrs, and let the ActiveRecord mechanism handle
> the conversions.
> 
> But by the time I've gone to this level of hackery, it seems prudent to
> harness the wisdom of the masses: is there a better way?
> 

Yes!  Work *with* the framework instead of around it, as I suggested 
above.

> - ff

Best,
--
Marnen Laibow-Koser
http://www.marnen.org
[email protected]
-- 
Posted via http://www.ruby-forum.com/.

-- 
You received this message because you are subscribed to the Google Groups "Ruby 
on Rails: Talk" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/rubyonrails-talk?hl=en.

Reply via email to