I have a list of incorrect cities name in Philippines:
>> a = City.find_all_by_country_id(4)
=> [#<City id: 91, name: "Alaminos", country_id: 4, created_at: "2009-11-12 04:06:14", updated_at: "2009-11-12 04:06:14">, #<City id: 92, name: "Angeles", country_id: 4, created_at: "2009-11-12 04:06:14", ...
And I wanted to replace all the name开发者_开发百科s with the correct one:
=> b = ["Abra", "Agusan del Norte", "Agusan del Sur", ...
I wanted to use the replace
method because I wanted to update the existing city id, inserting/truncating them only if necessary.
But I still can't figure this one out, since a
is an array of arrays (correct me if I am wrong) while b
is just a simple, down-to-earth array.
a
should be an array of City models. For example if you wanted to change the city name of the city id 91 (the first record) to "Abra" (the first element in the array) you would just do a[0].name = b[0]
. I'm a little unclear on what exactly you're trying to do, but hopefully this will get you over the syntax part of the problem.
Have a look at at Array#zip, and ActiveRecord::Base#update_attribute. As Andy Gaskell points out, a is an array of City objects. So zip can be called on a, and update_attribute can be called on any element of a.
The short simple way of doing what you want is this:
a.zip(b){|array| array[0].update_attribute(:name, array[1])}
Zip will turn multiple arrays into an array of arrays. Where each index of the new array is an array composed of elements in the source arrays of the same index.
a.zip(b) = c #=> ∀i: c[i] = [a[i],b[i]]
If you pass a block to zip, Ruby will yield each array in c to the block. It's a handy shortcut for a.zip(b).collect(&block)
.
In the code above, array[0] = a[i]
, and array[1] = b[i]
, each iteration supplies a different value of i. update_attributes will update the record in the database bypassing validations and callbacks.
Caveats:
- If b has more elements then a you will get No Method Errors.
- If a has more elements than b, the extra elements will have their name set to "".
Again, Update_attributes bypasses validations and saves the updated record automatically. If this is not too your liking you can replace the innards of the block with:
array[0].name = array[1]; array[0].save
I decided to use a migration file instead, so this is the code:
class AddProvinces < ActiveRecord::Migration
def self.up
philippines = Country.find_by_name('Philippines')
old_cities = philippines.cities
new_cities = (['Abra', 'Agusan del Norte', 'And all the cities...'])
old_cities.each do |c|
unless new_cities.blank?
City.update(c.id, :name => new_cities.first)
new_cities.delete(new_cities.first)
else
City.delete(c.id)
end
end
unless new_cities.blank?
new_cities.each do |c|
City.create(:name => c, :country_id => 'philippines.id')
end
end
end
def self.down
end
end
精彩评论