2014-04-25 2 views
2

ActiveRecord가 자동으로 : id 속성을 별도의 열에도 기본 키로 할당하여 고군분투하고 있습니다.레일스 ActiveRecord가 기본 키가 아닌 id 열을 처리합니다.

Table - legacy-table 

    id - int 
    pk_id - int (primary key) 
    name - varchar2 
    info - varchar2 

모델

class LegacyModel < ActiveRecord::Base 
    self.table_name = 'legacy-table' 
    self.primary_key = 'pk_id' 
    default_scope {order(:name => :asc)} 
    alias_attribute :other_id, :id 

end 

내가 액티브가 자동으로 기본 키 (pk_id) 할당하는 것을 걱정하지 않는다 : ID는 그러나 내가 실제 id 컬럼에 대한 모든 액세스 권한을 잃게 때문이다. 별칭을 사용하면 간단히 기본 키를 다시 나타냅니다.

그러나이 문제에 대한 한 가지주의 사항은 @legacymodel [: id]를 사용하여 뷰에서 id 열에 액세스 할 수 있다는 것입니다. 그러나 다시 @ legacymodel.id를 호출 할 때 pk_id 열의 값을 얻습니다. 내가 원하는 것은 @ legacymodel.other_id를 호출하여 id 컬럼을 가리킬 수 있도록하는 것이다. 대신 @ legacymodel.service_id, @ legacymodel.id 및 @ legacymodel.pk_id는 모두 같은 열을 가리 킵니다. pk_id

이 열은 기존 DB이므로 열을 수정하는 것은 의문의 여지가 있습니다. 레일즈 4를 MySql과 함께 사용하고 있습니다.

어쨌든이 코드를 작성 하시겠습니까? @legacymodel [: id]가 왜 @ legacymodel.id에서 다른 결과를내는 이유는 무엇입니까?

답변

2

read_attribute method@attributes 해시 값을 읽습니다. [] methodread_attribute을 사용합니다. 따라서 @legacymodel[:id]id 열의 값을 가져옵니다.

write_attribute method는 항상 ... 기본 키의 이름으로 id 번역

# ActiveRecord::AttributeMethods::Write 
def write_attribute(attr_name, value) 
    attr_name = attr_name.to_s 
    attr_name = self.class.primary_key if attr_name == 'id' && self.class.primary_key 

을 시도 ... 그리고 []= methodwrite_attribute를 사용합니다. 따라서 @legacymodel[:id] = <value>은 기본 키 열 pk_id에 값을 설정합니다.

# ActiveRecord::AttributeMethods::PrimaryKey 
if attr_name == primary_key && attr_name != 'id' 
    generated_attribute_methods.send(:alias_method, :id, primary_key) 
end 

그래서 @legacymodel.idpk_id 열의 값을 얻을 것이다 :

id method 여기 primary_key 별명이 붙을 특별한 방법이다.

방금 ​​@legacymodel.other_id 통해 id 열을 읽으려면, 다음과 같은 방법을 정의 할 수 있습니다 :

# LegacyModel class 
def other_id 
    self[:id] 
end 

을하지만 당신은 또한 @legacymodel.other_id= 통해 id 열을 작성해야하는 경우에, 당신은해야 할 수도 있습니다 write_attribute 메서드를 재정 의하여 안전한 방법을 찾아 attr_name = self.class.primary_key if attr_name == 'id' && self.class.primary_key 문을 해결할 수 있도록하십시오.

+0

동의, write_attribute 로직을 전달하는 쉬운 해결 방법이 있습니까? 아니면 ActiveRecord를 재정의 유일한 방법입니까? – Matt

+1

나는 이것을 극복 할 수있는 좋은 방법을 생각할 수 없다. 고려해야 할 한가지 옵션은'write_id_attribute'라는 새로운 메서드를 만드는 것입니다.이 메서드는'primary_key' 로직없이'write_attribute'의 복사본입니다. 그런 다음 모델에서'def other_id = (value) write_id_attribute (: id, value) end'를 가질 수 있습니다. 이것은 특별한 논리가이 한 모델에서'id'를 위해서만 사용될 것이고 표준'write_attribute'가 다른 모든 것에 여전히 사용 될 것이라고 확신 할 것입니다. – cschroed

1

최신 Rails (v4.2)에서는 @cschroed의 응답이 나에게 적합하지 않았습니다. 이후

ID = 'id'.freeze 

    # Returns the value of the attribute identified by <tt>attr_name</tt> after 
    # it has been typecast (for example, "2004-12-12" in a date column is cast 
    # to a date object, like Date.new(2004, 12, 12)). 
    def read_attribute(attr_name, &block) 
    name = attr_name.to_s 
    name = self.class.primary_key if name == ID 
    _read_attribute(name, &block) 
    end 

https://github.com/rails/rails/blob/4-2-stable/activerecord/lib/active_record/attribute_methods/read.rb

상기 [] 방법 read_attribute 사용없이 이렇게 : 레일 소스 코드 파고, 상기 키 같음 'ID'를 통과하는 경우 read_attribute 또한 차 키 값을 사용하는 것으로 보인다 더 오래 작동합니다.이 _read_attribute을 흉내 read_attribute을 우회하는 수단을 제공

# LegacyModel class 
def other_id 
    @attributes.fetch_value('id') 
end 

:

나는 속성 대신 일 해시에서 그 직접 읽어 냈다.

관련 문제