Reputation: 710
Following to RailsGuides instruction, I have created an engine for blogging system in my app. This blog engine is mounted as /blog.
RailsGuides shows how to add belongs_to
association to the mounted engine's Article
model. However, the parent app's User
model still requires has_many
association to the engine's Article
model which is in different namespace.
How to set has_many association between parent app's model and mounted engine's model?
Thanks in advance.
Upvotes: 2
Views: 1034
Reputation: 1333
The accepted answer requires manual modification of main_app's parent model in order to set the has_many relationships to the engine's child model. So each time you add the engine to one your main_apps you would have to go into the main_apps models and set up all required relationships by hand.
A more robust, although more complicated, solution would be to use the decorator pattern in the engine so that the engine will auto-configure main_app's parent model with the relationships it needs.
By using this method you just need to add a setting to the engine initializer in your main_app and the engine will handle the rest.
In engine:
blog.gemspec.rb
s.add_dependency 'decorators' #this will install the decorators gem for use in engine
lib/blog/blog.rb
module Blog
class Engine < ::Rails::Engine
isolate_namespace Blog
engine_name 'blog'
#to set up main_app objects via decorators in engine
config.to_prepare do
Decorators.register! Engine.root, Rails.root
end
end
end
lib/blog.rb
require 'decorators'
module Blog
mattr_accessor :user_class #Can now reference this setting as Blog.user_class
class << self
#the following lets us add functionality to main_app user model
def decorate_user_class!
Blog.user_class.class_eval do
has_many :articles, :class_name => "Blog::Article", :foreign_key => "user_id"
end
end
end
end
app/decorators/lib/blog/user_class_decorator.rb
if Blog.user_class
Blog.decorate_user_class!
else
raise "Blog.user_class must be set in main_app blog.rb initializer"
end
In main app:
app/initializers/blog.rb
Blog.user_class = User
If you run rails console from main app, you will see relationships will have been set properly. The decorator pattern in the engine can also be used to extend the main_app's models and controllers in different ways, not just Activerecord relationships. Almost complete decoupling achieved!
Upvotes: 0
Reputation: 12719
In the rails application, you know what module you include, so you can simply specify the relation with the class name ;)
has_many :articles, class_name: 'Blog::Article'
check if this is the right syntax for your database adapter, e.g. I'm using this for Mongoid, but it should be the same with ActiveRecord AFAIK
Upvotes: 4