views:

59

answers:

3

Hi,

I'm working on a rake task which imports from a JSON feed into an ActiveRecord called Person.

Person has quite a few attributes and rather than write lines of code for setting each attribute I'm trying different methods.

The closest I've got is shown below. This works nicely as far as outputing to screen but when I check the values have actually been set on the ActiveRecord itself it's always nil. So it looks like I can't use .to_sym to solve my problem?

Any suggestions?

I should also mention that I'm just starting out with Ruby, have been doing quite a bit of Objective-c and now need to embrace the Interwebs :)

        http = Net::HTTP.new(url.host, url.port)
http.read_timeout = 30
json = http.get(url.to_s).body
parsed = JSON.parse(json)
if parsed.has_key? 'code'
    updatePerson = Person.find_or_initialize_by_code(parsed['code'])
    puts updatePerson.code
    parsed.each do |key, value|
    puts "#{key} is #{value}"
      symkey = key.to_sym
      updatePerson[:symkey] = value.to_s
      updatePerson.save
      puts "#{key}....." # shows the current key
      puts updatePerson[:symkey] # shows the correct value
      puts updatePerson.first_name # a sample key, it's returning nil

end
+1  A: 

You're probably looking for update_attributes():

if parsed.has_key?('code')
  code = parsed.delete('code')
  person = Person.find_or_initialize_by_code(code)
  if person.update_attributes(parsed)
    puts "#{person.first_name} successfully saved"
  else
    puts "Failed to save #{person.first_name}"
  end
end
Pär Wieslander
Thanks Pär,That seems very convenient, it's not quite the silver bullet though as the parsed JSON also contains some arrays too. I'm guessing that I would need to filter those out (maybe if class = Array) as I'm getting an error:rake aborted!uninitialized constant Person::Result
Andrew
You should make sure that the hash you pass to `update_attributes` only contains key/value pairs that correspond to attributes of the model. Those could be filtered out by comparing the keys in the hash to `Person#attribute_names` (http://api.rubyonrails.org/classes/ActiveRecord/Base.html#M001868). However, the error message you get seems to indicate another problem -- that you try to reference `Person::Result` in your code without having defined it. Could you update the question with any changes you made to the code?
Pär Wieslander
A: 

You can use write_attribute:

parsed.each do |key, value|
  updatePerson.write_attribute(key, value)
end
updatePerson.save
Voyta
Thanks for the suggestion, it's lead me to use the following code:parsed.each do |key, value| if value.class != Array updatePerson.write_attribute(key, value) endendupdatePerson.save
Andrew
A: 

Your code can not assign any attribute, because you are always assigning to the single attribute named "symkey":

symkey = key.to_sym
updatePerson[:symkey] = value.to_s # assigns to attribute "symkey", not to the attribute with the name stored in variable symkey

If you want to make key into a symbol (which is probably not even necessary) and then use that as an index to access the attribute in updatePerson, you can write:

updatePerson[key.to_sym] = value.to_s 
updatePerson.save

But this - more or less - is the same as

updatePerson.updateAttribute(key.to_sym, value.to_s) # update and save

except that no validation is triggered, so use with care.

And performancewise it might not be such a good idea to save the person after each assignment, so maybe you want to defer the .save() call until after you have assigned all attributes.

Nevertheless, updateAttributes(...) is something you might want to be looking into - if you do, do not forget to inform yourself on attr_protected or attr_accessible, as they protect attributes from "bulk assignment"

Enno Brehm