I'm using Single Table Inheritance in a Rails project and attempting to change the type of one model to that of another. Here are the relevant schema and models:
create_table "images", force: true do |t|
t.string "url"
t.string "type"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "user_id", limit: 255
end
class Image < ActiveRecord::Base
validates :url, :user_id, presence: true
end
class UnconfirmedImage < Image
end
class ConfirmedImage < Image
end
I need to convert an UnconfirmedImage to a ConfirmedImage and vice versa. I should be able to do this using ActiveRecord::Persistance#becomes!.
However, when I attempt to save the change, it seems to fail silently:
foo = UnconfirmedImage.new(url: "foo", user_id:1)
=> #<UnconfirmedImage id: nil, url: "foo", type: "UnconfirmedImage", created_at: nil, updated_at: nil, user_id: 1>
foo.save
#sql omitted
=> true
bar = foo.becomes!(ConfirmedImage)
=> #<ConfirmedImage id: nil, url: "foo", type: "ConfirmedImage", created_at: nil, updated_at: nil, user_id: 1>
bar.save
Note the wrong sql generated here. The WHERE clause on type checks for the new type, rather than the old. This shouldn't return true.
[13891][12:32:05.583 +0000][DEBUG]: (0.1ms) begin transaction
[13891][12:32:05.598 +0000][DEBUG]: SQL (0.3ms) UPDATE "images" SET "type" = ?,"updated_at" = ? WHERE "images"."type" IN ('ConfirmedImage') AND "images"."id" = 2 [["type", "ConfirmedImage"], ["updated_at", Mon, 17 Feb 2014 12:32:05 UTC +00:00]]
[13891][12:32:05.599 +0000][DEBUG]: (0.1ms) commit transaction
=> true
This is confirmed when I attempt to query for the object.
UnconfirmedImage.all
[13891][12:33:59.525 +0000][DEBUG]: UnconfirmedImage Load (0.3ms) SELECT "images".* FROM "images" WHERE "images"."type" IN ('UnconfirmedImage')
=> #<UnconfirmedImage id: 2, url: "foo", type: "UnconfirmedImage", created_at: "2014-02- 17 12:31:15", updated_at: "2014-02-17 12:31:15", user_id: 1>]>
ConfirmedImage.all
[13891][12:33:39.646 +0000][DEBUG]: ConfirmedImage Load (0.2ms) SELECT "images".* FROM "images" WHERE "images"."type" IN ('ConfirmedImage')
=> #<ActiveRecord::Relation []>
Could anyone advise the best solution to this? I'm not sure if this is expected behaviour, or a bug in Rails.
Thanks