简体   繁体   中英

Extending application's model in rails engine

I have an application which defines some models. I want to extend the functionality of some models(eg. adding methods,adding associations) from application to my engine. I tried adding a model in the engine with the same name as my application's model and Rails will automatically merge them, however it doesn't work.

eg: (Application's model)

class Article < ActiveRecord:Base 
 def from_application
    puts "application"
 end
end

(Inside my Engine)
module MyEngine
  class Article < ::Article
    has_many :metrics, :class_name => 'Metric'
  end 
end

has_many association is not getting applied to my Articles model when I try to access @articles.metrics. Any ideas ?

You have the right idea and are close. But your implementation is a little off.

Generally, your engine should have no knowledge of your host app. That way, your engine and the host app(s) stay loosely coupled. So, classes in your engine should not inherit from classes in your host app. (BTW, your approach doesn't work, I believe, because of the way ruby does constant lookups, but that's a different discussion.)

Instead, use the included hook . In the host app, you do something like:

  class Article < ActiveRecord:Base 
    include FooEngine::BarModule

    def from_application
      puts "application"
    end

  end

And inside the engine:

  module FooEngine
    module BarModule
      def self.included(base)
        base.class_eval do 
          has_many :metrics, :class_name => 'Metric'
        end
      end
    end 
  end

When the ruby interpreter goes to include FooEngine::BarModule in Article , it will look for and run (if found) the self.included method in FooEngine::BarModule , passing in the Article class as base .

You then call class_eval on the base ( Article ) which re-opens the Article class so that you can add methods or whatever monkey business you're up to (define new methods in situ , include or extend other modules, etc.).

In your example, you call the has_many method, which will create the various association methods provided by has_many .

If (a) you're going to add a lot of metrics-related functionality through your engine, (b) you want to have lots of classes make use of the metrics-related functionality, and (c) you want some of the functionality to vary from class-to-class (where included), you might consider creating an acts_as_having_metrics (or similar). Once you head down this path, it's a whole new world of wondrous metaprogramming.

Best of luck.

Do you have your metrics model have a belongs_to association with Articles.

You might want to give the other side of the association, Metrics a belongs_to Articles to have this work properly. Also, make sure to have a migration to hold articles_id on the metrics table. Everything should work fine.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM