Book という名前の ActiveRecord モデルと Book::Author という名前のモデルがあります。著者は Book::Authorship モデル (1 対多の関連付け) を通じて多数の本を持っています。
オフトピック:
私のアプリでは、管理者のみが書籍と著者を作成/更新/削除できます。そこで、コントローラー用に Admin という名前空間を作成し、管理者専用にビューを作成しました。
Routes.rb ファイルには次のものがあります。
Rails.application.routes.draw do
# These are for the regular users:
# only #index and #show actions are defined in the respective controllers:
namespace :books do
resources :authors, only: %i[index show]
end
resources :books, only: %i[index show]
# These are for the admins only:
# all CRUD methods are defined in the respective controllers:
namespace :admin do
namespace :books do
resources :authors
end
resources :books
end
resources :admin
root "books#index"
end
次に、Admin::Books::AuthorsController コントローラーを作成しました。
ビューのパスは同じパス パターンに従うことが予想されます。
残念ながら、そうではありません。インデックス ページは機能しますが、_author.html.erb 部分が見つかりません。
/app/views/admin/books/authors/_index.html.erb で著者のリストをレンダリングしようとしている方法は次のとおりです。
<% @books_authors.each do |book_author| %>
<%= render book_author %>
<% end %>
これにより、次のエラーが発生します。
途中に 2 冊の「本」があります…しかしなぜでしょうか?
上記のコードは、テンプレートへの明示的なパスがある場合にのみ機能します。
<% @books_authors.each do |book_author| %>
<%= render "admin/books/authors/author", book_author: book_author %>
<% end %>
これは構成パラダイムに関する慣例を破るので、私は好きではありません。 Admin::Books:: 名前空間の下のすべてのビューに手動でパスを入力したくありません。
明示的なパスを使用せずに目的の機能を実現する方法を探しています。 Rails が部分を検索するときにパスに「books」を 2 回含めないようにするにはどうすればよいでしょうか?
コントローラーの名前空間は Admin::Books で、モデルは Books::Author なので、両方とも 2 つの「books」パスが得られます。ロジックは大まかに次のようになります。
[
File.dirname(Admin::Books::AuthorsController.new.lookup_context.prefixes.first),
Books::Author.new.to_partial_path
].join("/")
#=> "admin/books/books/authors/author"
lookup_context は変更できるものです (おそらく良いアイデアではありません)。
# app/controllers/admin/books/authors_controller.rb
def index
lookup_context.prefixes = ["admin/books", "application"]
@books_authors = Books::Author.all
end
もう 1 つの方法は、Books 名前空間の 1 つを削除することです。
# either change your controller
class Admin::AuthorsController < ApplicationController
def index
@books_authors = Books::Author.all
end
end
# or model, what if someone writes a book and a post?
class Admin::Books::AuthorsController < ApplicationController
def index
@books_authors = Author.joins(:books)
end
end
モデルをフラットに保つことは、名前空間がなくても問題なく、規則に従う一般的な方法です。
BookAuthor
PostAuthor