2010-06-03 17 views
14

Mam silnik, który definiuje niektóre modele i sterowniki. Chcę móc rozszerzyć funkcjonalność niektórych modeli/kontrolerów w mojej aplikacji (np. Dodawanie metod) bez utraty oryginalnego modelu/kontrolera z silnika. Wszędzie czytałem, że po prostu trzeba zdefiniować kontroler o tej samej nazwie w aplikacji i Railsy automatycznie je scalą, jednak nie działa to dla mnie i kontroler w silniku jest po prostu ignorowany (nie sądzę, że jest on załadowany).Silniki szynowe rozszerzające funkcjonalność

Odpowiedz

2

Tylko czy ktoś pracuje w tej samej kwestii jakiś czas w przyszłości, to jest Kod pisałem, że stały mój problem:

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 

Spowoduje to automatyczne wymagają plików z silnikiem przed wymagając od aplikacji, jeśli ścieżka do pliku zaczyna się od „app”.

+0

To rozwiązanie działa dla Rails 3, zobacz http://stackoverflow.com/questions/5045068/extending-controllers-of-a-rails-3-engine-inhe -main-app – Andrei

+0

Teraz działa również dla Rails 3. – Andrei

+0

Z tej odpowiedzi stworzyłem klejnot około roku temu, ale zapomniałem go opublikować tutaj. Działa to dobrze dla nas: https://github.com/EPI-USE-Labs/activesupport-decorators –

1

To prawda. Zostanie użyty sterownik, który zostanie znaleziony jako pierwszy.

Więc aby to działało może masz dwie opcje:

  • utworzyć lokalną kopię sterownika i zmodyfikować metodę trzeba
  • jeśli masz kontrolę nad wtyczką, można utworzyć Moduł zawierający kod i include kod w obu kontrolerach, tylko przesłonięcie metody w lokalnym kontrolerze. Według mnie, ponieważ nie ma dziedziczenia wielokrotnego, jest to jedyny sposób.

Mam nadzieję, że to pomoże.

0

nigdy nie używane silniki wcześniej, ale nie można zdefiniować nowy kontroler, który dziedziczy ze sterownika dostarczonego przez silnik

+0

Nie, jeśli mają taką samą nazwę. – Andrius

+0

Co zrobić, jeśli są w oddzielnej przestrzeni nazw? –

7

Możesz dodać te linie do ciebie plik modułu silnika w lib katalogu:

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 

Wtedy masz możliwość w głównej aplikacji (dzięki czemu aplikacja korzysta z silnika) żądania niezbędnych plików z silnika. Jest to miłe, ponieważ zachowujesz domyślną funkcjonalność Rails Engines, a także masz proste narzędzie do korzystania z normalnego dziedziczenia ruby, bez potrzeby stosowania łatek.

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

jaka jest korzyść z robienia tego w ten sposób w porównaniu z GŁÓWNYM modelem APP dziedziczącym z modelu ENGINE? – westonplatter

+0

Jeśli plik MODA.rb znajduje się w aplikacji GŁÓWNEJ, a aplikacja ENGINE, ale APP ENGINE .rb nie jest wymagana w aplikacji GŁÓWNEJ .rb, Railsy ignorują APP ENGINE .rb. Aplikacja ENGINE to MAIN nie podąża za normalnym dziedzictwem ruby, przynajmniej wtedy, gdy napisałem tę odpowiedź. – joshmckin

+0

Podoba mi się to rozwiązanie! Moje pytanie brzmi: co jeśli użytkownik w silniku w nazwach? – user3281384

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

przed definicją klasy modelu w aplikacji.

1

Możesz zmienić kolejność ładowania silnika, aby uniknąć wymagań w każdym z modeli.

W config/environment.rb dodać ten wiersz:

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

Zapewni to, że modele z MyEngine są ładowane przed MojaApl

+0

O ile mi wiadomo, automatyczne ładowanie Railsów znajduje pierwszą definicję (model silnika w twoim przypadku) i używa go, nie przechodzi przez inne ścieżki, aby załadować możliwe inne definicje tego samego modelu. – linkyndy

Powiązane problemy