0

when using find_or_create_by_name in rails, if the table is found and you pass in parameters for other attributes, will it update the table? for example:

College.find_or_create_by_name(name: 'University of Pittsburgh', calendar: 'semester')

Say the University of Pittsburgh table has already been created, but the calendar attribute is nil. Will this code update the calendar attribute to make it 'semester'?

Some context... I'm making a website with a bunch of pages for different colleges. Part of the website involves listing a bunch of data for the college. Right now I'm writing my seed file, but I anticipate having to change it. I'd like to have hundreds of schools on the website, and for each school, there are going to be hundreds of different pieces of data. I was thinking that having the seed file and using find_or_create_by_name would be a good way to do this, but if you have a better way, please let me know.

Adam Zerner
  • 17,797
  • 15
  • 90
  • 156

2 Answers2

2

That code won't update the record if it already exists. I would suggest:

@college = College.find_or_initialize_by_name("Robot House!!")
@college.attributes = {
  reputation: "partyhouse",
  occupants: "robots"
}
@college.save!

You could wrap this in a method if you needed to.

RobHeaton
  • 1,390
  • 1
  • 9
  • 13
0

find_or_create_by_ does exactly what it says: it either creates a new item (create saves to database) or finds the existing one, meaning reads it from the database.
It returns false on validation errors when creating an object

So to save changes you use the normal update methods:

if @college= College.find_or_create_by_name(given_attributes) &&
   @college.update_attributes(given_attributes)
else
  # handle validation errors
end

It won't hit the database twice, because update_attributes does'n apply any changes to newly created objects (but possible changes to existing ones)

To write it more explicit:

@college= College.find_or_create_by_name(given_attributes)
if @college.present?
   if @college.update_attributes(given_attributes)
     # do your success stuff
   else
     # handle update validation errors
   end
else
  # handle find_or_create errors
end
Martin M
  • 8,430
  • 2
  • 35
  • 53
  • so since update_attributes doesn't apply changes to newly created objects, I'd have to run rake db:seed twice to make sure everything is updated right? – Adam Zerner May 31 '13 at 17:40
  • no, I mean: if an object is new, it is created (written to DB) by `find_or_create_`. After that, `update_attributes` doesn't change anything, all attributes are identical, so the implicit `save` doesn't do anything. So a new object is written by `find_or_create_` while an existing one is updated by `update_attributes`. Either way, the object is saved. – Martin M May 31 '13 at 21:58
  • sorry, I didn't word that question correctly. I meant to ask... if I run rake twice it'll ensure that all Colleges will be updated, because if the College doesn't exist yet, it'll be created by the first rake, and updated by the second rake, and if the college does exist, it'll be updated by the first rake and the second rake won't do anything – Adam Zerner May 31 '13 at 22:07
  • for some reason it's saying that update_attributes is an undefined method when I run rake db:seed. do you know why that is or what I can do about it? – Adam Zerner Jun 07 '13 at 19:11
  • It means, that a `@college` is not valid, so `find_or_create` returns `nil` try an `!` at the end of the function name to raise an error. – Martin M Jun 08 '13 at 07:30
  • I tried it and it still gave me this error: undefined method `update_attributes' for nil:NilClass /Users/adamzerner/collegeanswers/db/seeds.rb:10:in `' Could it be because update_attributes doesn't "see" the newly created object? If so how can I fix this? – Adam Zerner Jun 08 '13 at 13:30
  • You have to find out, why @college is `nil`. Normally the second expression of `&&` is only executed, if the first part is true. Then `@college` would be set. If `find_or_create` returns `nil` the first expression `@college=...` is false, the whole if is false and the `# handle validation errors` should be executed. If you try `find_or_create_by_name!` it schould raise an error, explaining the failing validation, and it should not return `nil` – Martin M Jun 08 '13 at 14:06
  • the ! should be before the parenthesis right? like College.find_or_create_by_name!('University of Pittsburgh') – Adam Zerner Jun 08 '13 at 14:35
  • I spoke with someone on the Rails Hotline and he said that update_attributes might be running before find_or_create_by_name, so he had me take find_or_create_by_name out of the if statement like so @college= College.find_or_create_by_name(given_attributes) if @college.update_attributes(given_attributes) else # handle validation errors end however, that's getting me this error undefined method `update_attributes' for true:TrueClass do you know why that is or what I can do to fix it? – Adam Zerner Jun 08 '13 at 16:44
  • I actually think I just got it to work! The problem was that I only updated one college with the new code. When I commented all the other colleges out it worked. – Adam Zerner Jun 08 '13 at 16:53