2012-04-27 4 views
6

현재 런타임 상태에 따라 임의의 모듈을 포함해야하는 상황이 내 Rails 응용 프로그램에 있습니다. 이 모듈은 특정 조건이 충족 될 때만 필요한 사용자 정의 응용 프로그램 코드를 제공합니다. 기본적으로, 현재 상황에서 회사의 이름을 당겨 사용하고 그 모듈의 파일 이름과 그 정의와 같은 :Ruby : 동적 모듈 이름 포함

내 테스트 모듈은 다음과 같습니다
p = self.user.company.subdomain + ".rb" 
if File.exists?(Rails.root + "lib/" + p) 
include self.class.const_get(self.user.company.subdomain.capitalize.to_sym) 
    self.custom_add_url 
end 

: 이제

module Companyx 
    def custom_add_url 
    puts "Calling custom_add_url" 
end 
end 

콘솔에서이 실제로 작동합니다. 나는 사용자를 끌어과 같이 모듈을 포함 할 수 있습니다 :

[1] pry(main)> c = Card.find_by_personal_url("username") 
[2] pry(main)> include c.class.const_get(c.user.company.subdomain.capitalize)=> Object 
[3] pry(main)> c.custom_add_url 

호출 custom_add_url이

내 모델에서 포함 줄을 실행하려고하면 내가 얻을

NoMethodError: undefined method `include' for #<Card:0x007f91f9094fb0> 

사람이 왜 제안 할 수 있습니다를 include 문은 콘솔에서 작동하지만 내 모델 코드에서는 작동하지 않습니다.

답변

5

포함은 클래스에 대한 메서드입니다.

모델 내부에서 코드를 호출하려는 경우 코드를 싱글 톤 클래스의 컨텍스트에서 실행해야합니다.

p = self.user.company.subdomain + ".rb" 
if File.exists?(Rails.root + "lib/" + p) 
myself = self 
class_eval do 
    include self.const_get(myself.user.company.subdomain.capitalize.to_sym) 
end 
self.custom_add_url 

편집 :

클래스 블록을 허용하지 않습니다 < < 자기; class_eval은 지역 변수의 상태를 보존합니다. 나는 그것을 사용하기 위해 내 솔루션을 수정했습니다.

+0

컨텍스트를 변경하면 자체 개체가 더 이상 존재하지 않게됩니다 (또는 더 정확하게는 사용자 개체와 연관 됨). 나는이 문제를 해결하기 위해 다양한 방법을 시도해 왔으며이 글을 읽으면 여기서 무슨 일이 벌어지는 지 이해할 수있다. (http://yehudakatz.com/2009/11/15/metaprogramming-in-ruby-its-all-about-the-self/) 성공없이. –

+0

오, 내 잘못이야. 기본적으로 새로운 맥락에서 자아가 클래스입니다. 그것은 클래스 평가를하는 것과 비슷합니다. 개인 프로젝트에서 실험을했습니다. 이 파일의 맨 위에 도움이 될 것입니다 : https://github.com/Hitonagashi/UndergroundFootball/blob/master/app/models/player.rb –

+0

잘 모르겠다. 나는 가능한 모든 기술을 클래스 메서드로 동적으로 추가하는 코드에서 initialize 메서드에 대해 이야기하고 있다고 생각한다. 클래스에 연결된 객체를 추가 할 수 없기 때문에이 객체가 내 문제에 어떻게 적용되는지 알 수 없습니다. 클래스 블록 내부의 코드에 대한 인스턴스의 관계에 액세스 할 수있는 방법이 있습니까? –

8

나는 비슷한 일을하고 있습니다. 나는이 대답이 유용하다는 것을 알았다 : How to convert a string to a constant in Ruby?

나는 밖으로 나가 constantize 방법을 찾고 있었다. 이것은 내가 내 코드에서 사용하고 라인입니다 :

include "ModuleName::#{var.attr}".constantize 

편집 :

그래서 ACK, 실제로 그 선 자신을 사용하여 다양한 문제에 달렸다. 부분적으로는 클래스의 메서드 내에서 호출하려고했기 때문입니다. 난 단지 클래스에서 하나 개의 메소드를 호출하는거야하지만 이후 새 제거 할 수 있도록 내가 가지고있는 최종 작업 버전 지금, methodName로는 인스턴스 메서드입니다 분명히

"ModuleName::#{var.attr}".constantize.new.methodname 

입니다 (호출하는/그 외 모든 것을 실행) 너의 것이 클래스 메소드라면.