7
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

モジュールとrefinementを組み合わせて使おうとして、依存関係でハマった話

Posted at

最近、モジュールとrefinementsを組み合わせて使ってみようとして、requireがループしてハマったため回避策を書いておく。

Railsでこんなファイル構成を取っていた。

app/models/post.rb
class Post < ActiveRecord::Base
  include Commentable
  belongs_to :user
end
app/models/concern/commentable.rb
using CommentableRefinement

module Commentable
  extend ActiveSupport::Concern

  included do
    has_many :comments, as: :commentable
  end

  def thread_author
    author
  end
end
app/models/concern/commentable_refinement.rb
module CommentableRefinement
  refine Post do
    def author
      user
    end
  end
end

(これはサンプルで適当に書いたので、正確ではない)

こうやっていれば、commentable.rbでのみrefinementで拡張したメソッドを元々持っていたかのように振舞える。

とは言え、こういう書き方をすると、usingもrefineもincludeもファイルを読み込んだ時点で評価されてしまう。

なので、Postを定義している途中で、Commentableが必要になり、Commentableを読みにいくと冒頭でCommentableRefinementが必要になり、CommentableRefinementでrefineを定義しようとするとPostが必要になって読み込みがループして、Post::Commentableが見つからねえよ、と言われて死ぬ。

仕方が無いので、includeの評価をCommentable読み込み後まで遅延させるように工夫した。

app/models/post.rb
class Post < ActiveRecord::Base
  klass = self
  ActiveSupport.on_load :commentable do |mod|
    klass.send(:include, mod)
  end
  require "commentable"

  belongs_to :user
end
app/models/concern/commentable.rb
using CommentableRefinement

module Commentable
  extend ActiveSupport::Concern

  included do
    has_many :comments, as: :commentable
  end

  def thread_author
    author
  end

  ActiveSupport.run_load_hooks(:commentable, self)
end

これで、とりあえず依存関係のループは切れるのだが、なんかダサいw

ちなみに、refinementはAsakusa.rbでmoroさんからざっくり話を聞いて、自分なりにこんな感じか?と書いてみたもので、用途としてアリかどうかについてはまだ分かってない。

7
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?