この質問は、異なる名前空間に定義された同名のモデルが実行時に期待したようにロードされないことに関する質問です。

Ruby on Rails 4で作ったアプリケーションで、私は投稿とカテゴリを表す2つのモデルを使っています。

class Post < ActiveRecord::Base
  belongs_to :category, required: true
end

class Category < ActiveRecord::Base
  has_many :posts, dependent: :restrict_with_error
end

このアプリケーションは大きく分けて次の2つの画面を持っており、各モデルのパラメータに使う属性が異なります。

  • 管理画面: 変わらないURLを利用するために、モデルのパラメータにidを使う
  • 一般画面: わかりやすいURLを利用するために、モデルのパラメータにnameを使う

この仕様を満たすために、私は各画面に対応する2つのMountable Engineでモデルを以下のように定義しました。

module Content
  class Post < ::Post
    def to_param
      name
    end
  end

  class Category < ::Category
    def to_param
      name
    end
  end
end

module Admin
  class Post < ::Post
  end

  class Category < ::Category
  end
end

さて、実際の振る舞いを確認してみます。私は以下のようにCategoriesControllerでcategoryモデルに属するpostモデルのリンクを表示してみました。Content名前空間で実行しているため、パラメータはname属性になると私は期待しています。

しかし、パラメータがid属性になる時があったときがありました。この問題が難しい理由は、パラメータがname属性になる時もあったからです

module Content
  class CategoriesController < ApplicationController
    def show
      @category = Category.includes(:posts).find(params[:id])
    end
  end
end

ul
  - @category.posts.each do |post|
    li
      = link_to post.title, post

アプリケーションはdevelopment環境で実行しました。Rails Guidesの以下の章がヒントになるかと思いましたが、原因はわかりませんでした。

Autoloading and Reloading Constants
http://guides.rubyonrails.org/autoloading_and_reloading_constants.html

なお、モデルのアソシエーションを名前空間で再定義する方法でこの問題を解決することも考えました。しかし、それはDRYでなく良い解決方法と感じています。


追記します。

同一のアクション/ビューで、どちらの結果になるときもあるということです。
全くのランダムかは、確かめる方法がないため分かりません。

実際のサンプルアプリケーションを以下にコミットしました。

https://github.com/lhside/namespace_app

ふと思い当たるふしがあり、Admin::Postを保存した直後にContent::PostsControllerのindexアクションにリクエストすると、id属性がパラメータとして表示されました。
その時のログは、先のリポジトリのREADMEにコピーしています。