2014-02-17 3 views
0

입니다. Rails 프로젝트에서 단일 테이블 상속을 사용하고 한 모델의 유형을 다른 모델의 유형으로 변경하려고합니다. 다음은 관련 스키마 및 모델입니다.ActiveRecord :: Persistence #를 사용하는 단일 테이블 상속 모델 변환은

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 

UnconfirmedImage를 ConfirmedImage로 또는 그 반대로 변환해야합니다. 나는 ActiveRecord::Persistance#becomes!을 사용하여 이것을 할 수 있어야한다. 나는 변경 사항을 저장하려고 할 때

그러나, 자동으로 실패 할 것 같다

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 

참고 여기에 생성 된 잘못된 SQL. 타입에 대한 WHERE 절은 이전 타입이 아닌 새로운 타입을 검사합니다. 이것은 사실을 반환해서는 안됩니다.

[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 

개체를 쿼리 할 때 확인됩니다.

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 []> 

누구나 최선의 해결책을 제안 할 수 있습니까? 이것이 예상되는 동작인지 또는 레일스의 버그인지 확실하지 않습니다.

감사합니다.

+0

어디서나 정의 된 'default_scope'가 있습니까? – aceofspades

+0

@aceofspaces 나는 그렇지 않습니다. –

답변

1

이것은 여러 번 전에 물었습니다. 어딘가에 ActiveRecord 또는 ARel이 이전 유형에 매달려 있습니다. 내가 과거에 주위에 왔 방법은 간단하게 다음과 같은 일을하는 것입니다 : 쿼리가 구축 될 때

image = image.becomes(ConfirmedImage) 
Image.where(id: image.id).update_all(type: 'ConfirmedImage') 

그래서 후, type 열은 ARel 예상 올바른 값을 가지고 있으며, 업데이트가 전달합니다. #update_all은 STI 체인에서 상위 클래스의 범위에서 호출해야합니다. 그렇지 않으면 ActiveRecord가 해당 유형의 범위를 다시 지정합니다.

가끔은 이것이 상태 머신의 작업이고 모델의 이름을보고있을 때 state_machine gem이 STI를 사용하고 ActiveRecord를 구부리기보다 더 나은 호출이라고 생각합니다.

+0

답장을 보내 주셔서 감사합니다. 의도 한대로 작동합니다. 나는 state_machine 보석을 보지 못했다. 나는 그것에 대해 살펴볼 것이다. –