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.