RailsのmodelをEngineで共有する(実験中)

  • 23
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

まだ全然実験中

目的

PC用とmobile用を別プロジェクトにしたいとか
管理ツールを別プロジェクトにしたいとか
そういう時にEngineを使うとmodelの共有がしやすい。
(かもしれない)

基本的なEngineのつくりかた

rails plugin new my_engine --mountable
bin/rails g model hoge

生成されたファイルをいつもどおり弄ればおk

RSpecとFactoryGirl を使う

普通にgemspecにgemを追加したあと lib/my_engine/engine.rb に以下を追加してジェネレータがrspecとfactory_girlを使うようにする

  class Engine < ::Rails::Engine
    config.generators do |g|
      g.test_framework :rspec, fixtures: false
      g.fixture_replacement :factory_girl, dir: 'spec/factories'
    end
  end

これでジェネレータを実行すると

$bin/rails g model user
  invoke  active_record
  create  db/migrate/20141104193453_create_my_engine_users.rb
  create    app/models/my_engine/user.rb
  invoke    rspec
  create      spec/models/my_engine/user_spec.rb
  invoke      factory_girl
  create        spec/factories/my_engine_users.rb

な感じになる

アプリケーションからfactoryを使えるようにする

そのままではEngineを利用するアプリケーションからfactoryが見えない。
Engineの中でFactoryGirlにファイルのありかを教える。

  class Engine < ::Rails::Engine
    initializer 'my_engine.factories', after: 'factory_girl.set_factory_paths' do
      FactoryGirl.definition_file_paths.unshift File.expand_path('../../spec/factories', __FILE__)
    end
  end

FactoryGirl(Rails)を使っている場合は factory_girl.set_factory_paths が自動で呼ばれるので、その後にコードが実行されるようにする。
FactoryGirlを使っていない場合は実行されないので安心。

問題点 / 疑問点

まだよくわからんところ

Relationはどうなるの

特にアプリケーション側で条件を追加したりしたいときなど
Engineのmodelを拡張することになる。

もともとのコードが

class MyEngine::User
  has_many :articles
end

class MyEngine::Article
  belongs_to :user
end

な感じの時、
アプリケーション側で

class User < MyEngine::User
  default_scope { where(:banned, false) }
end

class Article < MyEngine::Article
  default_scope { where(:draft, false) }
end

とやったとき、 User.first.articles は MyEngine::Article を参照するようだ。
よってArticleで設定したdefault_scopeは効かない。
Engineのmodelを拡張して使いたいときはどうすればいいのだろうか?

  • 継承したクラスを作る
    • relationを定義し直す? めんどい
    • factoryも定義しなおしになる?
  • MyEngine::User を拡張する?
    • その場合どこに書く? initializerが太る
    • そもそもMyEngine::UserはEngineの中のコードしか見に行かない
    • MyEngine::User がロードされたら拡張のコードが走るようにinitializerでがんばる?
  • そもそもEngineのモデルを拡張なんて考えてはいけない
  • factoryはどうする?
    • factoryの再定義できないの辛い