mmag

ハマったことメモなど

Rails Engineでマウントする側のモデルとされる側のモデルのassociation

目論見

MyAppという普通のRailsアプリにMyBlogというエンジンをマウントする。 MyAppにUserモデルがあることをMyBlogが知っていると仮定(設定できるようにしたほうが良いけどとりあえず)。 MyBlogにはArticleモデルがあり、Userには複数Articleを持たせたい。

belongs_to

belongs_toは簡単で、Engine側のモデルに書けばいい。

module MyBlog
  class Article < ActiveRecord::Base
    belongs_to :user
  end
end

has_many

こっちが問題で、Userクラスはマウントする側のアプリにいるので、EngineをマウントするためにMyAppのUserモデルのコードをイジらなくてはいけない。とてもイケていない。

どうする

radar/foremのマネをしてdecoratorsを使う。

# my_blog.gemspec

s.add_dependency 'decorators'
# app/decorators/lib/my_blog/user_class_decorator.rb

MyBlog.decorate_user_class!
# lib/my_blog.rb

require "my_blog/engine"
require "decorators"

module MyBlog
  class << self
    def decorate_user_class!
      MyBlog.user_class.class_eval do
        has_many :articles, class_name: "MyBlog::Article"
      end
    end

    def user_class
      Object.const_get("User")
    end
  end
end
# lib/my_blog/engine.rb

module MyBlog
  class Engine < ::Rails::Engine
    isolate_namespace MyBlog

    config.to_prepare do
      Decorators.register! Engine.root, Rails.root
    end
  end
end

これで、マウントする側のコードを編集しなくてよくなった。 今回はUserで固定だったところを指定できるようにすると、少しメタプロが必要かも。

参考

テーマはFB matteをベースにしてます。作者さんに感謝を込めて。