Hi everyone, I''m looking for a shortcut to finding and updating or creating record depending on the results of the find. So, is there a shorter way to do it than this? @stuff = Stuff.find_by_foo_and_bar("yay","hooray") if @stuff: Stuff.update(@stuff.id, {:foo => "boo", :bar => "hoo"}) else Stuff.create({:foo => "boo", :bar => "hoo"}) end By the way, I can''t believe that I want to do this in less than 3.1 lines of code. Rails is making me lazy. Anyway, anyone who can suggest something nicer & shorter gets my gratitude and an imaginary gold star. thanks! Dan -- Posted via http://www.ruby-forum.com/.
dan wrote:> I''m looking for a shortcut to finding and updating or creating record > depending on the results of the find. > > So, is there a shorter way to do it than this? > > @stuff = Stuff.find_by_foo_and_bar("yay","hooray") > if @stuff: Stuff.update(@stuff.id, {:foo => "boo", :bar => "hoo"}) > else Stuff.create({:foo => "boo", :bar => "hoo"}) > end@stuff = Stuff.find_by_foo_and_bar("yay","hooray") || Stuff.new @stuff.update_attributes(:foo => "boo", :bar => "hoo") -- We develop, watch us RoR, in numbers too big to ignore.
Mark Reginald James wrote:> dan wrote: > >> I''m looking for a shortcut to finding and updating or creating record >> depending on the results of the find. >> >> So, is there a shorter way to do it than this? >> >> @stuff = Stuff.find_by_foo_and_bar("yay","hooray") >> if @stuff: Stuff.update(@stuff.id, {:foo => "boo", :bar => "hoo"}) >> else Stuff.create({:foo => "boo", :bar => "hoo"}) >> end > > @stuff = Stuff.find_by_foo_and_bar("yay","hooray") || Stuff.new > @stuff.update_attributes(:foo => "boo", :bar => "hoo") > > -- > We develop, watch us RoR, in numbers too big to ignore.I think a term for this is called "Upsert" - so does rails or any existing plugin/helper already have the ability to do it. If not, then maybe a generic helper method would be in order. Stuff.upsert(...) I think this could be somewhat difficult to implement generically without knowing the fields that determine the uniqueness of a record (user keys). Michael -- Posted via http://www.ruby-forum.com/.
On 04/08/06, Michael Modica <codeslush@yahoo.com> wrote:> > I think a term for this is called "Upsert" - so does rails or any > existing plugin/helper already have the ability to do it. If not, then > maybe a generic helper method would be in order. Stuff.upsert(...) I > think this could be somewhat difficult to implement generically without > knowing the fields that determine the uniqueness of a record (user > keys). >The primary_key is guaranteed to be unique within a table. By default, this is called "id", if not, I''m certain there''s a way to look it up. What more do you need to know, pseudocode implementation below, in a class inheriting from ActiveRecord::Base? def upsert(id, fields) Record = self.find(:first, :id=> id) newRecord = Record.copy # deep copy method, consensus on Google seems to be that # there''s no built-in copy function in Ruby fields.each { |x| newRecord.x= fields[x] } newRecord.id = self.find(:all).length + 1 newRecord.save end -- Cheers, Hasan Diwan <hasan.diwan@gmail.com> -------------- next part -------------- An HTML attachment was scrubbed... URL: http://wrath.rubyonrails.org/pipermail/rails/attachments/20060805/bc0775e4/attachment.html
Hasan Diwan wrote:> On 04/08/06, Michael Modica <codeslush@yahoo.com> wrote: >> >> I think a term for this is called "Upsert" - so does rails or any >> existing plugin/helper already have the ability to do it. If not, then >> maybe a generic helper method would be in order. Stuff.upsert(...) I >> think this could be somewhat difficult to implement generically without >> knowing the fields that determine the uniqueness of a record (user >> keys). >> > > The primary_key is guaranteed to be unique within a table. By default, > this > is called "id", if not, I''m certain there''s a way to look it up. What > more > do you need to know, pseudocode implementation below, in a class > inheriting > from ActiveRecord::Base? > def upsert(id, fields) > Record = self.find(:first, :id=> id) > newRecord = Record.copy # deep copy method, consensus on Google seems > to > be that > # there''s no built-in copy > function > in Ruby > fields.each { |x| > newRecord.x= fields[x] > } > newRecord.id = self.find(:all).length + 1 > newRecord.save > endI think you are assuming he knows the id of the record. I believe if that were the case, then he would just do an update. An upsert is something you can do when you DO NOT know if it is an insert or an update. However, an ID field is rarely known in a true upsert. Take a contact for example. A user tries to add John Doe with phone 555-444-3333. Then, another user tries to add another John Doe with phone 333-444-5555. Is this a change in phone number or a new John Doe contact? The way you determine this is by defining the user keys that determine the uniqueness of a record. If you define this user key to be First Name, Last Name only then this John Doe example would be an update. If, however, you define the user key to be First Name, Last Name and Phone Number then this John Doe is an Insert. Does that make sense? You would need to know what fields define the uniqueness of a record in order to accomplish this task - thus making it difficult to make generic. Regards, Michael -- Posted via http://www.ruby-forum.com/.
The unique''nes is identified by the ''unique'' index on the table. Primary key has a "unique" index on it. So in your scenario if the user has defined a compound index on First Name + Last Name + Phone then it will throw an unique index error. Many DB supports the insert/update syntax now-a-days: In MYSQL it would be something like: INSERT INTO table (a,b,c) VALUES (1,2,3) ON DUPLICATE KEY UPDATE c=c+1; More information on: http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html Guess Oracle also has such feature. One idea of generic interface could be, if the underlying DB supports "upsert" delegate do it otherwise wrap a "insert/catch duplicate/update" statement. _Hari codeslush wrote:> > Hasan Diwan wrote: >> On 04/08/06, Michael Modica <codeslush@yahoo.com> wrote: >>> >>> I think a term for this is called "Upsert" - so does rails or any >>> existing plugin/helper already have the ability to do it. If not, then >>> maybe a generic helper method would be in order. Stuff.upsert(...) I >>> think this could be somewhat difficult to implement generically without >>> knowing the fields that determine the uniqueness of a record (user >>> keys). >>> >> >> The primary_key is guaranteed to be unique within a table. By default, >> this >> is called "id", if not, I''m certain there''s a way to look it up. What >> more >> do you need to know, pseudocode implementation below, in a class >> inheriting >> from ActiveRecord::Base? >> def upsert(id, fields) >> Record = self.find(:first, :id=> id) >> newRecord = Record.copy # deep copy method, consensus on Google seems >> to >> be that >> # there''s no built-in copy >> function >> in Ruby >> fields.each { |x| >> newRecord.x= fields[x] >> } >> newRecord.id = self.find(:all).length + 1 >> newRecord.save >> end > > I think you are assuming he knows the id of the record. I believe if > that were the case, then he would just do an update. > > An upsert is something you can do when you DO NOT know if it is an > insert or an update. However, an ID field is rarely known in a true > upsert. Take a contact for example. A user tries to add John Doe with > phone 555-444-3333. Then, another user tries to add another John Doe > with phone 333-444-5555. Is this a change in phone number or a new John > Doe contact? The way you determine this is by defining the user keys > that determine the uniqueness of a record. If you define this user key > to be First Name, Last Name only then this John Doe example would be an > update. If, however, you define the user key to be First Name, Last > Name and Phone Number then this John Doe is an Insert. > > Does that make sense? You would need to know what fields define the > uniqueness of a record in order to accomplish this task - thus making it > difficult to make generic. > > Regards, > > Michael > > -- > Posted via http://www.ruby-forum.com/. > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails > >-- View this message in context: http://www.nabble.com/create-or-update---tf2044153.html#a5860818 Sent from the RubyOnRails Users forum at Nabble.com.
On 8/3/06, dan <dgreig@magian.com> wrote:> > Hi everyone, > > I''m looking for a shortcut to finding and updating or creating record > depending on the results of the find. > > So, is there a shorter way to do it than this? > > @stuff = Stuff.find_by_foo_and_bar("yay","hooray") > if @stuff: Stuff.update(@stuff.id, {:foo => "boo", :bar => "hoo"}) > else Stuff.create({:foo => "boo", :bar => "hoo"}) > endI can name that tune in one note: @stuff = Stuff.find_or_create_by_foo_and_bar("yay","hooray") This assumes that you don''t have any validations which would block the creation of a record with only these attributes. -- Jim Kane fastjames@gmail.com -------------- next part -------------- An HTML attachment was scrubbed... URL: http://wrath.rubyonrails.org/pipermail/rails/attachments/20060818/56ed7fdf/attachment.html