異なる名前空間に定義された同名のモデルのローディング
この質問は、異なる名前空間に定義された同名のモデルが実行時に期待したようにロードされないことに関する質問です。
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にコピーしています。