2012-04-27 43 views
6

Tôi có một tình huống trong ứng dụng Rails của mình, nơi tôi cần bao gồm các mô-đun tùy ý tùy thuộc vào trạng thái thời gian chạy hiện tại. Mô-đun này cung cấp mã ứng dụng tùy chỉnh chỉ cần thiết khi các điều kiện nhất định là đúng. Về cơ bản, tôi kéo tên của một công ty từ bối cảnh hiện nay và sử dụng đó như tên tập tin cho các mô-đun và định nghĩa của nó:Ruby: Bao gồm tên mô-đun động

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ô-đun thử nghiệm của tôi trông như thế này:

module Companyx 
    def custom_add_url 
    puts "Calling custom_add_url" 
end 
end 

Bây giờ trong giao diện điều khiển, điều này thực sự hoạt động tốt. Tôi có thể kéo một người sử dụng và bao gồm các mô-đun như vậy:

[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 

Calling custom_add_url

Nếu tôi cố gắng chạy dòng bao gồm từ mô hình của tôi, tôi nhận được

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

thể bất cứ ai đề nghị tại sao câu lệnh include sẽ hoạt động trên bảng điều khiển, nhưng không phải trong mã mô hình của tôi?

Trả lời

5

Bao gồm là phương thức trên lớp.

Nếu bạn muốn gọi nó bên trong một mô hình, bạn cần phải thực thi mã trong ngữ cảnh của lớp đơn.

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:

lớp < < tự không chấp nhận một khối; class_eval thực hiện, do đó nó bảo toàn trạng thái của các biến cục bộ. Tôi đã sửa đổi giải pháp của mình để sử dụng nó.

+0

Thay đổi ngữ cảnh có vẻ như thêm một biến chứng: đối tượng tự ngừng tồn tại (hoặc chính xác hơn, liên kết của nó với đối tượng người dùng không)? Tôi đã thử nhiều phương pháp khác nhau để giải quyết vấn đề này và đọc bài viết này để hiểu những gì đang xảy ra ở đây (http://yehudakatz.com/2009/11/15/metaprogramming-in-ruby-its-all-about-the-self/) không thành công. –

+0

Ồ, tệ lắm. Về cơ bản, bản thân trong bối cảnh mới là lớp học. Nó tương tự như làm một lớp eval. Tôi đã làm một cái gì đó như thế này như là một thử nghiệm trên một dự án cá nhân. Đầu tệp này sẽ giúp: https://github.com/Hitonagashi/UndergroundFootball/blob/master/app/models/player.rb –

+0

Không hoàn toàn chắc chắn tôi hiểu: Tôi nghĩ rằng bạn đang nói về phương pháp khởi tạo trong mã của bạn, nơi bạn đang thêm tất cả các kỹ năng có thể là phương pháp lớp học động? Tôi không thấy làm thế nào mà áp dụng cho vấn đề của tôi, vì tôi không thể thêm một đối tượng liên quan đến lớp. Có cách nào để truy cập các quan hệ của cá thể để mã bên trong khối lớp không? –

8

Tôi đang làm một điều tương tự. Tôi thấy câu trả lời này hữu ích: How to convert a string to a constant in Ruby?

Hóa ra tôi đang tìm phương pháp cố định. Đây là dòng Tôi đang sử dụng trong mã của tôi:

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

Edit:

Vì vậy, ack, tôi chạy vào vấn đề khác nhau với thực tế sử dụng dòng bản thân mình. Một phần vì tôi đã cố gắng gọi nó bên trong một phương pháp trong một lớp học. Nhưng kể từ khi tôi chỉ gọi một phương thức trong lớp (trong đó kêu gọi/chạy mọi thứ khác) phiên bản làm việc cuối cùng tôi có bây giờ là

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

Rõ ràng methodname là một phương pháp dụ, vì vậy bạn có thể thoát khỏi sự mới nếu bạn là một phương pháp lớp học.

Các vấn đề liên quan