2011-03-05 5 views
11

after_initialize을 사용하여 개체의 일부 기본값을 설정하려고합니다. 내가 가지고있는 문제는 객체가 어떻게 생성되었는지에 관계없이 이것을 호출하기를 바란다는 것이다.블록 3과 after_initialize가 실행되지 않습니다.

내 클래스 : 나는 Foo.new, Foo.new(:bar => "things")Foo.create(:baz => 'stuff')를 호출하는 경우

class Foo < ActiveRecord::Base 

    serialize :data 

    after_initialize :init 

    def init 
    self.data ||= {} 
    self.bar ||= "bar" 
    self.baz ||= "baz" 
    end 

end 

모든 것이 잘 작동합니다. 그러나 create 블록을 사용하면 after_initialize 콜백이 실행되지 않습니다.

obj = Foo.create do |f| 
    f.bar = "words" 
    f.data = { :attr_1 => 1, :attr_2 => 2 } 
end 

이 단지 =>nil 대신 올바르게 설정 다른 속성 "baz"obj.baz을 얻을 수 있습니다.

콜백을 실행하는 방식에 뭔가 빠졌는데, 블록을 사용하여 create를 호출하는 것과의 차이점이 있거나 기본값이 블록에 의해 clobbered 되는가?

UPDATE 문제를 발견.

블록이있는 create은 미묘하게 다릅니다. 블록없이 create을 호출하고 매개 변수의 해시를 전달할 때 모든 의도와 목적을 위해 Foo.new({<hash of argument>}).save을 호출하고 after_initialize 콜백이 예상 한 것처럼 저장되기 직전에 실행됩니다.

블록을 사용하여 create으로 전화를 걸면 약간 다른 결과가 발생합니다. 이벤트의 순서는 당신이 전달하는 인자와 함께 호출되고 이 호출 된 다음 after_initialize이 호출되면 블록이 실행됩니다. 따라서 해시 매개 변수와 상호 교환 가능하게 블록을 사용한다면 설정하려는 모든 매개 변수가 실제로 설정되기 전에 after_initialize이 실행되기 때문에 좀 더 읽기 쉽도록 비트를 읽을 수 있습니다.

after_initialize에서 몇 가지 추가 작업을 수행했기 때문에 약간의 가치가 있습니다. after_initialize이 호출되었을 때 아무 것도 실제로 설정되지 않았기 때문에 아무 것도 올바르게 설정되지 않았으며 유효성 검사에 실패했습니다.

나는 init을 호출해야했다. after_initialize에 한번, before_validation에 한번. 가장 깨끗한 것은 아니지만 문제가 해결되었습니다.

올바른 방향으로 나를 가리켜 주신 Brandon에게 감사드립니다.

+0

'Foo.new' (즉, 선언의 블록 메소드 사용)와 같은 일을하는 경우에도 동일한 일이 발생합니까? –

+0

블록이있는 Foo.new는 정상적으로 작동합니다. – HMCFletch

+0

@HMCFletch - 무슨 일이 일어 났는지에 대한 좋은 설명 - 공유해 주셔서 감사합니다. –

답변

7

이걸 재현 할 수 없습니다. 빈 해시에 after_initialize 방법으로 초기화되는

ruby-1.9.2-p136 :001 > obj = Service.create do |s| 
ruby-1.9.2-p136 :002 >  s.token = "abc" 
ruby-1.9.2-p136 :003?> end 
=> #<Service id: 22, user_id: nil, type: nil, data: {}, created_at: "2011-03-05 04:18:00", updated_at: "2011-03-05 04:18:00", token: "abc"> 
ruby-1.9.2-p136 :004 > obj.data 
=> {} 

하면, data을 볼 수 있듯이 :

class Service < ActiveRecord::Base 
    serialize  :data, Hash 
    after_initialize :create_default_data 
    attr_accessible :data, :token 

    protected 

    def create_default_data 
     self.data ||= Hash.new 
    end 
end 

여기 IRB 세션이있다 : 나는 다음 (간체) 클래스 편리한 응용 프로그램을 가지고 일 .Rails 코드는 이것이 의미가 있음을 나타냅니다. new

def create(attributes = nil, &block) 
    if attributes.is_a?(Array) 
    attributes.collect { |attr| create(attr, &block) } 
    else 
    object = new(attributes) 
    yield(object) if block_given? 
    object.save 
    object 
    end 
end 

그래서 create 호출하고 yield의 전 object에 값을 할당합니다 create인치 여기 new의 관련 부분 :

def initialize(attributes = nil) 
    # truncated for space 
    result = yield self if block_given? 
    run_callbacks :initialize 
    result 
end 

당신이 볼 수 있듯이, new은 무조건 반환하기 전에 initialize 콜백을 호출하고, 그래서 당신이 전달하는 블록에 create도 수율 전에. 블록이 개체를 가져올 때까지 after_initialize 메서드는 이미을 실행했습니다.

(1) 현재 사용중인 레일 버전이 최신 버전 (3.0.5)이고 (2) 아무 것도 설정하지 않고 baz을 설정하지 않았는지 확인하십시오.

+1

굵은 글씨 주셔서 감사합니다. 그게 내 문제를 일으키는 바로 그거야. 나는 일어난 일을 자세하게 설명하는 나의 질문 하단에 약간의 설명을 적었다. 도와 주셔서 감사합니다. – HMCFletch

+0

매우 흥미롭고 멋진 일을하고 있습니다. 네가 이걸로 물릴 수있는 유일한 사람이라고 상상할 수 없어. –

관련 문제