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