2010-06-03 43 views
14

Tôi có một công cụ xác định một số mô hình và bộ điều khiển. Tôi muốn để có thể mở rộng chức năng của một số mô hình/bộ điều khiển trong ứng dụng của tôi (ví dụ như thêm phương pháp) mà không mất chức năng mô hình/điều khiển ban đầu từ động cơ. Ở khắp mọi nơi tôi đọc rằng bạn chỉ cần xác định bộ điều khiển có cùng tên trong ứng dụng của bạn và Rails sẽ tự động hợp nhất chúng, tuy nhiên nó không hoạt động đối với tôi và bộ điều khiển trong công cụ chỉ đơn giản là bỏ qua (Tôi không nghĩ rằng nó thậm chí được nạp).Rails động cơ mở rộng chức năng

Trả lời

2

Chỉ cần nếu bất cứ ai khác chạy vào cùng một vấn đề một số thời gian trong tương lai, đây là mã tôi đã viết khắc phục sự cố của tôi:

module ActiveSupport::Dependencies 
    alias_method :require_or_load_without_multiple, :require_or_load 
    def require_or_load(file_name, const_path = nil) 
    if file_name.starts_with?(RAILS_ROOT + '/app') 
     relative_name = file_name.gsub(RAILS_ROOT, '') 
     @engine_paths ||= Rails::Initializer.new(Rails.configuration).plugin_loader.engines.collect {|plugin| plugin.directory } 
     @engine_paths.each do |path| 
     engine_file = File.join(path, relative_name) 
     require_or_load_without_multiple(engine_file, const_path) if File.file?(engine_file) 
     end 
    end 
    require_or_load_without_multiple(file_name, const_path) 
    end 
end 

Điều này sẽ tự động yêu cầu tệp từ động cơ trước khi yêu cầu từ ứng dụng nếu đường dẫn tệp bắt đầu bằng 'ứng dụng'.

+0

Công việc của giải pháp này doen cho Rails 3, hãy xem http://stackoverflow.com/questions/5045068/extending-controllers-of-a-rails-3-engine-in-the -main-app – Andrei

+0

Bây giờ nó cũng hoạt động cho Rails 3. – Andrei

+0

Tôi tạo ra một viên ngọc từ câu trả lời này khoảng một năm trước nhưng quên đăng nó ở đây. Nó hoạt động tốt cho chúng tôi: https://github.com/EPI-USE-Labs/activesupport-decorators –

1

Điều đó đúng. Bộ điều khiển được tìm thấy đầu tiên sẽ được sử dụng.

Vì vậy, để làm cho nó hoạt bạn có thể có hai lựa chọn:

  • tạo ra một bản sao cục bộ của bộ điều khiển, và sửa đổi các phương pháp bạn cần
  • nếu bạn có quyền kiểm soát các plugin, bạn có thể tạo một Module chứa mã và include mã trong cả hai bộ điều khiển, chỉ ghi đè phương thức trong bộ điều khiển cục bộ của bạn. Theo tôi, vì không có nhiều thừa kế, đó là cách duy nhất.

Hy vọng điều này sẽ hữu ích.

0

Tôi chưa bao giờ sử dụng động cơ trước nhưng bạn không thể xác định một bộ điều khiển mới được thừa kế từ bộ điều khiển được cung cấp bởi động cơ

+0

Không nếu họ có cùng tên. – Andrius

+0

Điều gì sẽ xảy ra nếu chúng ở một không gian riêng biệt –

7

Bạn có thể thêm những dòng này cho bạn tập tin mô-đun của động cơ trong thư mục gốc lib:

def self.root 
    File.expand_path(File.dirname(File.dirname(__FILE__))) 
end 

def self.models_dir 
    "#{root}/app/models" 
end 

def self.controllers_dir 
    "#{root}/app/controllers" 
end 

Sau đó, bạn có khả năng trong việc áp dụng chính (làm cho ứng dụng sử dụng động cơ) để yêu cầu các tập tin cần thiết từ động cơ. Điều này là tốt đẹp bởi vì bạn duy trì Rails Engines chức năng mặc định và cũng có một công cụ dễ dàng để làm cho việc sử dụng thừa kế ruby ​​bình thường, mà không cần phải vá.

EX:

#ENGINE Model - 

class User < ActiveRecord::Base 
    def testing_engine 
    puts "Engine Method" 
    end 
end 

#MAIN APP Model - 

require "#{MyEngine.models_dir}/user" 
class User 
    def testing_main_app 
    puts "Main App Method" 
    end 
end 

#From the Main apps console 

user = User.new 

puts user.testing_engine #=> "Engine Method" 

puts user.tesing_main_app #=> "Main App Method" 
+0

lợi ích của việc làm theo cách này so với Mô hình APP CHÍNH kế thừa từ mô hình ENGINE? – westonplatter

+0

Nếu tệp model.rb có trong MAIN APP và APP ENGINE nhưng APP ENGINE .rb không được yêu cầu trong APP CHÍNH .rb, Rails bỏ qua ENGINE APP .rb. ENGINE để MAIN ứng dụng không theo di sản ruby ​​bình thường, ít nhất là khi tôi đã viết câu trả lời này. – joshmckin

+0

Tôi thích giải pháp này! Câu hỏi của tôi là: nếu Người dùng trong công cụ trong không gian tên thì sao? – user3281384

16
require MyEngine::Engine.root.join('app', 'models', 'my_engine', 'my_model') 

trước khi định nghĩa lớp mô hình trong ứng dụng của bạn.

1

Bạn có thể thay đổi thứ tự tải của động cơ để tránh yêu cầu trên từng kiểu máy của bạn.

Trong config/application.rb thêm dòng này:

module MyApp 
    class Application 
    config.railties_order = [MyEngine::Engine, :main_app, :all] 
    end 
end 

Điều này sẽ đảm bảo rằng các mô hình từ MyEngine được nạp trước khi MyApp

+0

Theo như tôi biết, Rails tự động tải tìm định nghĩa đầu tiên (mô hình động cơ trong trường hợp của bạn) và sử dụng nó, nó không đi qua các đường dẫn khác để tải các định nghĩa có thể khác của cùng một mô hình. – linkyndy

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