2010-11-22 2 views
5

저는 PHP 개발자입니다. 현재 Rails (3)와 물론 Ruby를 배우고 있습니다. I don't want to believe in magic 그래서 레일스에서 ​​일어나는 일들에 대해 최대한 이해하려고 노력합니다. 내가 흥미를 느낀 것은 ActiveRecord 모델에서 has_one 또는 belongs_to과 같은 메서드 호출입니다. Rails 메서드는 "has_one"처럼 작동합니까?

나는 그것을 재현하려고하고 순진 예와 함께 : "작동 것이다"
# has_one_test_1.rb 
module Foo 
    class Base 
    def self.has_one 
     puts 'Will it work?' 
    end 
    end 
end 

class Model2 < Foo::Base 
    has_one 
end 

그냥이 파일을 실행하면 출력합니다, 나는 예상대로.

레일 소스를 검색하면서 책임있는 기능을 찾았습니다 : def has_one(association_id, options = {}).

이것은 분명히 인스턴스 (?)이고 클래스 메서드가 아니기 때문에 작동하지 않아야합니다. 내가 할 수있는

# has_one_test_2.rb 
module Foo 
    module Bar 
    module Baz 
     def has_one stuff 
     puts "I CAN HAS #{stuff}?" 
     end 
    end 
    def self.included mod 
     mod.extend(Baz) 
    end 
    end 
    class Base 
    include Bar 
    end 
end 

class Model < Foo::Base 
    has_one 'CHEEZBURGER' 
end 

이제 실행 has_one_test_2.rb 파일가 출력이 CHEEZBURGER 있습니다

는 일부 연구 후에 나는 해답이 될 수있는 예를 찾아 냈다. 내가 잘 이해한다면, Base 클래스가 Bar 모듈을 포함하려고 시도한다는 것입니다. 이 시간에 self.included 메소드가 호출되며 Baz 모듈 (및 그 인스턴스 has_one 메소드)이있는 Bar 모듈을 확장합니다. 따라서 본질적으로 has_one 메서드가 포함됩니다 (혼합?)를 Base 클래스에 포함시킵니다. 그러나 아직도, 나는 그것을 완전히 얻지 못한다. Object#extend은 모듈에서 메소드를 추가하지만 여전히 확장을 사용하여이 동작을 재현하는 방법을 잘 모르겠습니다. 따라서 내 질문은 다음과 같습니다.

  1. 정확히 무슨 일이 일어 났습니까? 내 말은, 여전히 has_one 메서드가 클래스 메서드가되는 방법을 모르는 것입니까? 어떤 부분이 정확히 그것을 일으켰습니까?

  2. 이 메서드 호출 (구성처럼 보입니다)을 만들 가능성이 정말 좋습니다. 이것을 달성하기위한 대안 또는 간단한 방법이 있습니까?

답변

9

할 수 있습니다 extendinclude 모듈.

module Bar 
    def has_one stuff 
    puts "I CAN HAS #{stuff}?" 
    end 
end 

class Model 
    extend Bar 
    has_one 'CHEEZBURGER' 
end 

include

class Model 
    include Bar 
end 
Model.new.has_one 'CHEEZBURGER' 

레일이 사용 인스턴스 메소드와 같은 모듈에서 방법을 추가

extend

는 클래스 메소드 귀하의 예제의 간단한 구현과 모듈에서 방법을 추가 동적으로 클래스에 메서드를 추가하십시오.

예를 들어, 당신은 define_method을 사용할 수

module Bar 
    def has_one stuff 
    define_method(stuff) do 
     puts "I CAN HAS #{stuff}?" 
    end 
    end 
end 

class Model 
    extend Bar 
    has_one 'CHEEZBURGER' 
end 

Model.new.CHEEZBURGER # => I CAN HAS CHEEZBURGER? 
3

내가 마법을 믿는 거부를 칭찬한다. I 매우Metaprogramming Ruby 권의 도서를받을 것을 권장합니다.나는 최근에 그것을 얻었고 그것은 mah brainz에서 왼쪽과 오른쪽을 보여 주었다. 그것은 사람들이 일반적으로 '마법'이라고 부르는 많은 것들을 설명합니다. 일단 모두 다 커버하면 Active Record를 거쳐 이제는 주제를 이해할 수 있음을 보여줍니다. 무엇보다도 책은 매우 쉽게 읽을 수 있습니다. 매우 소화가 가능하고 짧습니다.

0

또한, 당신은 (일반적으로 많이 학대,하지만 때로는 매우 유용) method_missing 개념을 사용할 수 있습니다

class Foo 
    def method_missing(method, *arg) 
     # Here you are if was some method that wasn't defined before called to an object 
     puts "method = #{method.inspect}" 
     puts "args = #{arg.inspect}" 
     return nil 
    end 
end 

Foo.new.abracadabra(1, 2, 'a') 

는 일반적으로

method = :abracadabra 
args = [1, 2, "a"]

를 산출을,이 메커니즘은 자주

로 사용된다
def method_missing(method, *arg) 
    case method 
    when :has_one 
    # implement has_one method 
    when :has_many 
    # ... 
    else 
    raise NoMethodError.new 
    end 
end 
관련 문제