简体   繁体   English

Rails迁移设置布尔字段不起作用

[英]rails migration setting boolean field doesn't work

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. Student模型可能还没有smart领域。

As Luis Silva suggests you could use reset_column_information method to refresh info about columns for Student . 正如Luis Silva建议的那样,您可以使用reset_column_information方法刷新有关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. 如果要更改某些数据,最好在rake任务中进行。

If for some reason you HAVE TO do it in migration, you can do it in plain SQL query. 如果由于某种原因必须在迁移中执行此操作,则可以在普通SQL查询中执行。 For PostgreSQL it will be: 对于PostgreSQL,它将是:

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

reset_column_information reset_column_information

There are two issues that are clear to me right of the bet. 对我来说,有两个问题很明显。

  1. 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 . 安全的做法是重置列信息,如Luis Silva答案中所述。

  2. The second issue has to do with the fact that you use def change where some of the content isn't reversible. 第二个问题与以下事实有关:在某些内容不可逆的情况下使用def change Everything in the change method should be reversible. 更改方法中的所有内容都应该是可逆的。 Otherwise def up and def down should be used. 否则应使用def updef down

Here are two options that might solve your issue: 这里有两个选项可以解决您的问题:

  1. Using def up and def down . 使用def updef 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 
  2. Using reversible . 使用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 如果您不关心Rails回调,验证等,也可以使用

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. 这将通过单个查询更新所有记录,但不会实例化记录,这意味着Rails回调,验证等将不会运行。 For more info see update_all . 有关更多信息,请参见update_all

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM