문제
좋아, 그래서 나는 중복을 제거하고 일반적으로 내 삶을 더 쉽게 만들기 위해 작은 Rails 앱에서 내 코드를 리팩터링해 왔습니다(나는 쉬운 삶을 좋아하기 때문에).이 리팩토링의 일부는 내 모델 중 두 개에 공통된 코드를 필요한 곳에 포함할 수 있는 모듈로 이동하는 것이었습니다.
여태까지는 그런대로 잘됐다.문제가 해결될 것 같지만 어떻게 해결해야 할지 잘 모르겠는 문제가 발생했습니다.(보내기 가능이라고 부르는) 모듈은 문서의 팩스, 이메일 또는 PDF 인쇄를 처리하는 코드일 뿐입니다.예를 들어, 구매 주문서가 있고 내부 판매 주문서(상상적으로 ISO로 축약됨)가 있습니다.
내가 겪은 문제는 개체가 로드된 후 일부 변수를 초기화(철자가 올바르지 않은 사람들을 위해 초기화:P)하고 싶다는 것입니다. 초기화 후 훅.괜찮아요...믹스인을 더 추가하기 전까지는 말이죠.
내가 가진 문제는 내가 after_initialize
내 믹스인 중 하나에 포함해야 하므로 감독자 처음에 전화해서 다른 믹스인이 있는지 확인하세요. after_initialize
전화가 걸려옵니다.훌륭합니다. 결국 super를 호출했는데 호출할 super가 없기 때문에 오류가 발생하기 전까지는 말입니다.
충분히 혼란스럽지 않은 경우를 대비해 작은 예를 들어 보겠습니다.
class Iso < ActiveRecord::Base
include Shared::TracksSerialNumberExtension
include Shared::OrderLines
extend Shared::Filtered
include Sendable::Model
validates_presence_of :customer
validates_associated :lines
owned_by :customer
order_lines :despatched # Mixin
tracks_serial_numbers :items # Mixin
sendable :customer # Mixin
attr_accessor :address
def initialize( params = nil )
super
self.created_at ||= Time.now.to_date
end
end
따라서 각 믹스인에 after_initialize 호출이 있는 경우 감독자 전화해, 마지막으로 어떻게 그만둘 수 있어? 감독자 오류를 제기하여 전화를 걸었나요?슈퍼 메소드를 호출하기 전에 슈퍼 메소드가 존재하는지 어떻게 테스트할 수 있나요?
해결책
다음을 사용할 수 있습니다.
super if defined?(super)
예는 다음과 같습니다.
class A
end
class B < A
def t
super if defined?(super)
puts "Hi from B"
end
end
B.new.t
다른 팁
시도해 보셨나요? alias_method_chain
?기본적으로 모든 것을 연결할 수 있습니다. after_initialize
전화.데코레이터처럼 작동합니다.각각의 새로운 메소드는 새로운 기능 계층을 추가하고 제어를 "재정의된" 메소드에 전달하여 나머지 작업을 수행합니다.
포함 클래스(다음에서 상속받는 것) ActiveRecord::Base
, 이 경우에는 Iso
) ~할 수 있었다 자신의 정의 after_initialize
, 그래서 이외의 다른 솔루션은 alias_method_chain
(또는 원본을 저장하는 다른 앨리어싱) 코드를 덮어쓸 위험이 있습니다.@Orion Edwards의 솔루션은 제가 생각해 낼 수 있는 최고의 솔루션입니다.다른 것들도 있지만 그들은 그렇습니다 멀리 더 해킹적입니다.
alias_method_chain
또한 after_initialize 메서드의 명명된 버전을 생성할 수 있다는 이점이 있습니다. 즉, 중요한 경우에 호출 순서를 사용자 정의할 수 있다는 의미입니다.그렇지 않으면 포함 클래스에 믹스인이 포함된 순서가 무엇이든 상관없습니다.
나중에:
모든 콜백의 기본 빈 구현 생성에 관한 질문을 ruby-on-rails-core 메일링 리스트에 게시했습니다.저장 프로세스는 어쨌든 그것들을 모두 확인하므로 왜 거기에 있으면 안되는지 모르겠습니다.유일한 단점은 빈 스택 프레임을 추가로 생성한다는 점이지만 알려진 모든 구현에서는 비용이 매우 저렴합니다.
거기에 간단한 조건문을 던질 수 있습니다.
super if respond_to?('super')
그리고 당신은 괜찮을 것입니다 - 쓸모없는 방법을 추가하지 마십시오;좋고 깨끗합니다.
슈퍼 메소드가 존재하는지 확인하는 대신, 그냥 정의하면 됩니다.
class ActiveRecord::Base
def after_initialize
end
end
이것은 내 테스트에서 작동하며 기존 코드를 손상시키지 않아야 합니다. 왜냐하면 이를 정의하는 다른 모든 클래스는 어쨌든 자동으로 이 메서드를 재정의하기 때문입니다.