2012-04-27 18 views
6

Mam sytuację w mojej aplikacji Rails, w której muszę uwzględnić dowolne moduły w zależności od bieżącego stanu środowiska wykonawczego. Moduł zapewnia niestandardowy kod aplikacji, który jest potrzebny tylko wtedy, gdy spełnione są określone warunki. Zasadniczo, jestem ciągnięcie nazwę spółki z obecnej sytuacji i przy użyciu tego jako nazwy pliku dla modułu i jego definicja:Ruby: Dołącz nazwę modułu dynamicznego

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 

Mój moduł testowy wygląda następująco:

module Companyx 
    def custom_add_url 
    puts "Calling custom_add_url" 
end 
end 

Teraz w konsoli to faktycznie działa dobrze. Mogę wyciągnąć użytkownika i obejmują moduł tak:

[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 

Wywołanie custom_add_url

Jeśli próbuję uruchomić linię zawierać od mojego modelu, mam

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

Może ktoś sugerują, dlaczego instrukcja include działałaby na konsoli, ale nie w moim kodzie modelu?

Odpowiedz

5

Uwzględnij to metoda na zajęciach.

Jeśli chcesz wywołać go wewnątrz modelu, musisz wykonać kod w kontekście jego pojedynczej klasy.

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 

EDIT:

klasa < < siebie nie akceptuje bloku; class_eval ma, więc zachowuje stan zmiennych lokalnych. Zmodyfikowałem swoje rozwiązanie, aby z niego korzystać.

+0

Zmiana kontekstu wydaje się komplikować: obiekt sam przestaje istnieć (lub dokładniej jego powiązanie z obiektem użytkownika)? Próbowałem różnych metod obejść to i przeczytać ten artykuł, aby zrozumieć, co się tutaj dzieje (http://yehudakatz.com/2009/11/15/metaprogramming-in-ruby-its-all-about-theself/) bezskutecznie. –

+0

Och, moje złe. Zasadniczo, ja w nowym kontekście jest klasą. Jest podobny do robienia ewaluacji klasowej. Zrobiłem coś takiego jako eksperyment na osobistym projekcie. Góra tego pliku powinna pomóc: https://github.com/Hitonagashi/UndergroundFootball/blob/master/app/models/player.rb –

+0

Nie jestem pewien czy rozumiem: myślę, że mówisz o inicjalizacji w kodzie, gdzie dynamicznie dodajesz wszystkie możliwe umiejętności jako metody klasowe? Nie widzę, jak to dotyczy mojego problemu, ponieważ nie mogę dodać obiektu powiązanego do klasy. Czy istnieje jakiś sposób uzyskania dostępu do relacji instancji do kodu wewnątrz bloku klasy? –

8

Robię coś podobnego. Odpowiedź ta była przydatna: How to convert a string to a constant in Ruby?

Okazało się, że szukałem metody stałej. Jest to linia używam w moim kodu:

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

Edit:

Więc ACK, wpadłem na różne problemy z rzeczywistości za pomocą tej linii siebie. Częściowo dlatego, że próbowałem nazwać to wewnątrz metody w klasie. Ale ponieważ jestem tylko wywołanie jednej metody w klasie (który nazywa/biegnie wszystkiego innego) ostateczna wersja robocza mam to teraz

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

Oczywiście methodname jest metoda instancji, więc można pozbyć się nowa jeśli twoja jest metodą klasową.

Powiązane problemy