RoR: first_or_initialize block doesn't save
Asked Answered
T

3

5

I have the following code, which works fine with no errors but the models never get saved...

myarray.each do |item|

    r = MyModel.unscoped.where(:site_id => @site.id, :url => item['permalink_url']).first_or_initialize do |r|
        r.title              = 'asdasdadaddjfgnfd'
        r.save!
    end
end

Terminal shows the SQL SELECT statements when attempting to find the Models, but the UPDATE/INSERT statements never run.

What am I missing here?

Topless answered 23/8, 2013 at 17:42 Comment(0)
G
8

Rails first_or_* methods invoke passed block only for initialize or create part. If the record is found, the methods just return it so passed block will never run. Check the source

So you can use block in first_or_* methods only to initialize new items, not to update existing ones. Most likely, records with such conditions exist and don't get updated.

Try to move update code, something like

myarray.each do |item|

  r = MyModel.unscoped.where(:site_id => @site.id, :url => item['permalink_url']).first_or_initialize
  r.title              = 'asdasdadaddjfgnfd'
  r.save!

end
Gust answered 23/8, 2013 at 18:18 Comment(1)
Thanks, I ended up using .tap() so i could use my existing block structure but this is also a valid answerTopless
T
6

I solved this by using:

.first_or_initialize.tap() do |r|

But the comments below are also relevant

Topless answered 24/8, 2013 at 11:6 Comment(2)
Just what i was looking for for my seeds!Boltzmann
@Boltzmann You don't need to use tap(). find_or_initialize already returns the object.Xanthus
S
3

You're looking for first_or_create. first_or_initialize just initializes the object (possibly to prep for saving, but it doesn't have to be).

You're existing code would likely work as follows:

r = MyModel.unscoped.where(:site_id => @site.id, :url => item['permalink_url']).first_or_initialize do |r|
    r.title              = 'asdasdadaddjfgnfd'
end

r.save!
Smuggle answered 23/8, 2013 at 17:45 Comment(1)
Thanks but this will use 1 more sql query than necessary, first_or_initialize is better for my purposesTopless

© 2022 - 2024 — McMap. All rights reserved.