1

그래서 요즘 단일 테이블 상속에보고되었으며,이 일반적인 질문/답변을 발견 :레일 - 단일 테이블 상속 - 잘못된 캐스트 방법?

질문 : 당신은 알파 베타 < 가정, 베타 알파에서 개체 obj의 클래스를 변경 어떻게 , STI에서?

답변 : 루비는 오리 형 언어이므로 캐스팅을 사용하지 않습니다. 그러나 당신이 할 필요가 "유형"변수를 "베타"를 설정하고 개체를 저장하고, 다음 번에 당신은 형 베타 될 것입니다 알파 개체를로드한다 : 그러나,이

obj = Alpha.new 
obj.save #now obj is of type Alpha 

obj.type = "Beta" 
obj.save #now obj is of type Beta 

을 접근 방식이 나를 위해 작동하지 않는 것 같습니다. obj는 올바르게 저장되지만 Beta 객체로는 작동하지 않습니다. 베타 유효성 검사를 실행하지 않고 저장하고 obj.respond_to?(:beta_method) #beta_method being a method in the beta class을 검사하면 false를 반환합니다. 이 방법이 효과가 없습니까? 올바른 접근 방법이 있습니까? 아니면 단순히 뭔가 잘못하고있는 것입니까? (: beta_method) (: beta_method) (참 Alpha.last와 베타 모두 반환 Beta.last.respond_to가하면서, 거짓 반환

편집

나는 Alpha.last.respond_to을했을 때 것을 발견했다. 마지막으로 동일한 객체가 반환되었습니다. 재미있는 개발? 아직도 누군가가 이것을 자세히 설명 할 수 있다면 (루비가 상속을 처리하는 방법과 관련하여) 그것은 굉장 할 것입니다.

답변

1

당신이 말했듯이 루비는 타입 캐스팅을 허용하지 않습니다. 오히려 여기서 일어나는 일은 ActiveRecord가 type 필드의 값에 따라 다른 클래스의 인스턴스를 인스턴스화한다는 것입니다. 그래서 당신이 그것을 "베타"로 바꿀 때 당신은 Ruby의 관점에서 아무 것도하지 않습니다.

그러나 ActiveRecord가 데이터베이스를 검색하여 레코드를 검색하면 Alpha이 아닌 Beta의 인스턴스를 인스턴스화하고 새로운 type 값을 찾습니다. 이 프로세스는 특히 ActiveRecord보다 Ruby와 관련이 적습니다.

경우에 따라 상황에 따라 좀 더 우아한 접근법이 있습니다. 한 유형에서 다른 유형으로 모델을 "변환"해야하는 경우 (예 : EmployeeManager이되며 다른 방법이 있음) 합리적인 방법입니다. 다른 경우에는 믹스 인 또는 다른 도구를 사용하여 더 나은 목표를 달성 할 수 있습니다.

# obj is an instance of Alpha 
obj = Beta.new(obj.attributes) 

하지만이 유사하게 대부분의 경우 수행해야하는 이상한 일이 :

이 같이해야 할 경우도 Alpha의 속성에서 Beta의 임시 인스턴스를 만들 수 있습니다.

+0

나는이 대답이 옳다고 생각하지 않습니다. OP에서,'obj.type = "Beta"; obj.save'는 DB를 업데이트하지만 메모리 내 버전은 Alpha로 타입 변환됩니다. 'obj.reload'를하는 것은 Rails가 알파가되기를 기대하기 때문에이 경우에는 작동하지 않습니다. obj2 = Beta.find (obj.id)' –

+0

...하지만 더 나은 점은 @Teoulas가 설명하는대로'obj.becomes (Beta) '를 사용하는 것입니다. –

+0

나는 데이터베이스가 업데이트되지 않았다는 것을 결코 암시하지 않았다. 내가 말했던 것은 타입을 "베타"로 바꾸면 루비는 신경 쓰지 않는다 (여전히 알파의 인스턴스를 가지고있다). 다음 단락에서 말했듯이 ActiveRecord가 데이터베이스에서 레코드를 새로 검색 할 때 베타 인스턴스가 생성됩니다. (나는 원래 게시물에서 #comomes에 대해 언급하지 않은 이유를 기억하지 못한다.하지만 당신이 말한 것처럼, 다른 누군가는 그것을 가져왔다.) –

4

수행하려는 작업에 따라 becomes을 사용하거나 (update_attribute을 통해 직접) 개체 유형을 변경하고 데이터베이스에서 다시로드 (또는 둘 다 가능) 할 수 있습니다.

becomes은 이전 개체와 동일한 특성을 사용하여 유일한 매개 변수로 전달 된 클래스의 새 개체를 인스턴스화하고 반환합니다. 이렇게하면 새 객체의 메소드를 호출 할 수 있습니다.예를 들면 다음과 같습니다.

a = Alpha.last 

# if you want to save the new type in the database: 
a.type = 'Beta' 
a.save 

b = a.becomes(Beta) 
b.respond_to?(:beta_method) 
=> true 

나는이 방법을 호출하는 순서가 중요하다는 것을 알았습니다. 우선 becomes을 사용하려고 시도한 다음 유형을 변경하고 저장하면 데이터베이스의 유형이 변경되지 않습니다.

관련 문제