I have a migration which adds a boolean column and sets value for some of the rows. The new value doesn't get saved to the database when the model is saved. Here is a simplified version of the code:
class AddSmartToStudent
def change
add_column :students, :smart, :boolean
Student.where(grade: 'A').each do |student|
student.smart = true
student.save!
end
end
end
Thanks in advance!
In your migration, you add a boolean column, and right after that use it in the model. Not sure it is possible - when migration is not ended yet the transaction is not committed. The Student
model might not have smart
field yet.
As Luis Silva suggests you could use reset_column_information
method to refresh info about columns for Student
. But the problem is migrations are not for manipulating with data. If you want to change some data it's better to do in a rake
task.
If for some reason you HAVE TO do it in migration, you can do it in plain SQL query. For PostgreSQL it will be:
execute "UPDATE students SET smart='t' WHERE grade='A'"
Try to reset the cached information about columns, which will cause them to be reloaded on the next request.
Execute this line before your clause where
Student.reset_column_information
There are two issues that are clear to me right of the bet.
As stated by others you're trying to use an attribute that you add in that same migration. The safe thing to do is to reset the column information like explained in the answer of Luis Silva .
The second issue has to do with the fact that you use def change
where some of the content isn't reversible. Everything in the change method should be reversible. Otherwise def up
and def down
should be used.
Here are two options that might solve your issue:
Using def up
and def down
.
class AddSmartToStudent def up add_column :students, :smart, :boolean Student.reset_column_information Student .where(grade: 'A') .find_each { |student| student.update!(smart: true) } end def down remove_column :students, :smart end end
Using reversible
.
class AddSmartToStudent def change add_column :students, :smart, :boolean reversible do |change| change.up do Student.reset_column_information Student .where(grade: 'A') .find_each { |student| student.update!(smart: true) } end end end end
If you don't care about Rails callbacks, validations, etc. you could also use
Student.where(grade: 'A').update_all(smart: true)
as replacement for
Student.where(grade: 'A').find_each { |student| student.update!(smart: true) }
This updates all the records with a single query but doesn't instantiate the records, meaning Rails callbacks, validations, etc. won't run. For more info see update_all
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.