ActiveRecord#becomes!记录不存储

ActiveRecord#becomes!记录不存储

问题描述:

我的数据模型中有一些STI。 Task记录有两种类型:PrimaryTaskSecondaryTask。所以我的ActiveRecord的模式是这样的:ActiveRecord#becomes!记录不存储

class Task < ActiveRecord::Base 
end 

class PrimaryTask < Task 
    has_many :secondary_tasks 
end 

class SecondaryTask < Task 
    belongs_to :primary_task 
end 

我想提供一个方法来“促进”一SecondaryTaskPrimaryTask永久(如,持久化到数据库)。从仔细阅读文档,看起来像the #becomes! method是我想要的,但我无法得到它来保存数据库中的更改。

id = 1 
secondary_task = SecondaryTask.find(id) 
primary_task = secondary_task.becomes!(PrimaryTask) 

primary_task.id   # => 1 
primary_task.class  # => PrimaryTask 
primary_task.type  # => "PrimaryTask" 
primary_task.new_record? # => false 
primary_task.changes  # => { "type"=>[nil,"PrimaryTask"] } 

primary_task.save!  # => true 
primary_task.reload  # => raises ActiveRecord::RecordNotFound: Couldn't find PrimaryTask with id=1 [WHERE "tasks"."type" IN ('PrimaryTask')] 

# Note: secondary_task.reload works fine, because the task's type did not change in the DB 

不知道怎么回事?我尝试了以下的东西,无济于事。我误解了becomes!

  • 队的战绩是万一“脏”的save!电话是一个空操作,因为没有任何属性被标记脏(primary_task.update_attributes(updated_at: Time.current) - 没有帮助)
  • 的情况下,实际上破坏secondary_task他们都有相同的id是一个问题。没有帮助。该SecondaryTask记录已被删除,但没有PrimaryTask创建(尽管调用save!返回true

更新1

该日志显示可能的问题:

UPDATE "tasks" SET "type" = $1 WHERE "tasks"."type" IN ('PrimaryTask') AND "tasks"."id" = 2 [["type", "PrimaryTask"]] 

所以更新失败,因为WHERE子句导致找不到记录。

+1

正显示出一些日志? – Aguardientico 2014-09-03 23:32:32

+0

啊哈!好问题,甚至没有想到在那里看。更新问题... – 2014-09-03 23:40:36

+0

您是否尝试过使用'#成为'而不是'#becomes!'? – Aguardientico 2014-09-04 00:16:49

想通了。结果发现在ActiveRecord版本4.0.0中有一个错误。 It has since been patched。引入此修补程序的关键是在两个实例中正确设置changes。因此,现在您可以在原始实例上调用save(在我的示例中为secondary_task),它将更改数据库中的类型。请注意,在新实例上调用save(对于我来说primary_task)将不保存更改,因为问题中描述的行为:它将在SQL UPDATE调用中包含WHERE子句,这将导致记录找不到,因此该呼叫什么都不做。

下面是用ActiveRecord什么工作> 4.1.0:

id = 1 
secondary_task = SecondaryTask.find(id) 
primary_task = secondary_task.becomes!(PrimaryTask) 

secondary_task.changes # => { "type"=>["SecondaryTask","PrimaryTask"] } 
primary_task.changes # => { "type"=>["SecondaryTask","PrimaryTask"] } 

secondary_task.save! # => true 

primary_task.reload # => works because the record was updated as expected 
secondary_task.reload # => raises ActiveRecord::RecordNotFound, as expected