我有一个迁移,它添加了一个布尔列并为一些行设置值。保存模型时,新值不会保存到数据库中。以下是代码的简化版本:
class AddSmartToStudent
def change
add_column :students, :smart, :boolean
Student.where(grade: 'A').each do |student|
student.smart = true
student.save!
end
end
end
提前感谢!
在迁移中,添加一个布尔列,然后在模型中使用它。不确定这是否可能——当迁移尚未结束但事务尚未提交时。Student
模型可能还没有smart
字段。
正如LuisSilva所建议的,您可以使用reset_column_information
方法来刷新Student
的列信息。但问题是迁移并不是为了处理数据。如果你想更改一些数据,最好在rake
任务中进行。
如果出于某种原因,您必须在迁移中执行此操作,则可以在纯SQL查询中执行。对于PostgreSQL,它将是:
execute "UPDATE students SET smart='t' WHERE grade='A'"
尝试重置缓存的列信息,这将导致在下一次请求时重新加载这些列。
在所在的条款前执行此行
Student.reset_column_information
reset_column_formation
有两个问题我很清楚。
-
正如其他人所说,您正试图使用在同一迁移中添加的属性。安全的做法是像路易斯·席尔瓦的回答中解释的那样重置列信息。
-
第二个问题与使用
def change
有关,其中一些内容是不可逆的。变更方法中的所有内容都应该是可逆的。否则应使用def up
和def down
。
这里有两个选项可以解决您的问题:
-
使用CCD_ 10和CCD_。
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
-
使用CCD_ 12。
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
如果你不关心Rails回调、验证等,你也可以使用
Student.where(grade: 'A').update_all(smart: true)
作为的替代品
Student.where(grade: 'A').find_each { |student| student.update!(smart: true) }
这会用一个查询更新所有记录,但不会实例化记录,这意味着Rails回调、验证等不会运行。有关更多信息,请参阅update_all
。