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

时间:2018-10-28 06:44:36

标签: ruby-on-rails ruby activerecord rails-migrations

我有一个迁移,该迁移添加了一个布尔列并为某些行设置了值。保存模型时,新值不会保存到数据库中。这是代码的简化版本:

class AddSmartToStudent
  def change
    add_column :students, :smart, :boolean

    Student.where(grade: 'A').each do |student|
      student.smart = true
      student.save!
    end
   end
end

谢谢!

3 个答案:

答案 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

reset_column_information

答案 2 :(得分:0)

在我看来正确的投注有两个问题。

  1. 正如其他人所述,您正在尝试使用在同一迁移中添加的属性。安全的做法是像answer of Luis Silva中所述重置列信息。

  2. 第二个问题与以下事实有关:您使用def change,其中某些内容不可逆。更改方法中的所有内容都应该是可逆的。否则,应使用def updef down

以下两种方法可以解决您的问题:

  1. 使用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. 使用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