次の投稿はRailsに基づいています4。
実際には、複数のネストされたリソース(1つ以上)、およびオプションshallow:trueについてのベストプラクティスを探しています。
最初に私のルートで、これがありました:
resources :projects do
resources :collections
end
関連するルートは次のとおりです。
project_collections GET /projects/:project_id/collections(.:format) collections#index
POST /projects/:project_id/collections(.:format) collections#create
new_project_collection GET /projects/:project_id/collections/new(.:format) collections#new
edit_project_collection GET /projects/:project_id/collections/:id/edit(.:format) collections#edit
project_collection GET /projects/:project_id/collections/:id(.:format) collections#show
PATCH /projects/:project_id/collections/:id(.:format) collections#update
PUT /projects/:project_id/collections/:id(.:format) collections#update
DELETE /projects/:project_id/collections/:id(.:format) collections#destroy
projects GET /projects(.:format) projects#index
POST /projects(.:format) projects#create
new_project GET /projects/new(.:format) projects#new
edit_project GET /projects/:id/edit(.:format) projects#edit
project GET /projects/:id(.:format) projects#show
PATCH /projects/:id(.:format) projects#update
PUT /projects/:id(.:format) projects#update
DELETE /projects/:id(.:format) projects#destroy
ネストされたリソースの制限に関するドキュメントを読みました:
リソースを1レベル以上深くネストすることはできません。
ソース: http://guides.rubyonrails.org/routing.html#limits-to-nesting OK。次に、ドキュメントで述べたように、ルートで「浅い」を使用します。
shallow do
resources :projects do
resources :collections
end
end
関連するルートは次のとおりです。
project_collections GET /projects/:project_id/collections(.:format) collections#index
POST /projects/:project_id/collections(.:format) collections#create
new_project_collection GET /projects/:project_id/collections/new(.:format) collections#new
edit_collection GET /collections/:id/edit(.:format) collections#edit
collection GET /collections/:id(.:format) collections#show
PATCH /collections/:id(.:format) collections#update
PUT /collections/:id(.:format) collections#update
DELETE /collections/:id(.:format) collections#destroy
projects GET /projects(.:format) projects#index
POST /projects(.:format) projects#create
new_project GET /projects/new(.:format) projects#new
edit_project GET /projects/:id/edit(.:format) projects#edit
project GET /projects/:id(.:format) projects#show
PATCH /projects/:id(.:format) projects#update
PUT /projects/:id(.:format) projects#update
DELETE /projects/:id(.:format) projects#destroy
私が見る大きな違いは、コレクションの「ショー」です。これは次のとおりです。
collection GET /collections/:id(.:format) collections#show
私が正しい場合、コレクションのshowアクションのリンクは次のとおりです。
<%= link_to 'Show", collection_path(collection)%>
そして、次のようなものを返すはずです: " http://example.com/collections/1 "
しかし! 2つのこと:
安静時アクションの大きな利点を失うことである場合、浅瀬の興味が何であるか理解できません。興味は何ですか?そして、「ショー」アクションを失うことへの関心は何ですか?私はすでにこれをSOに投稿しましたが、私が受け取った唯一のコメントは「それは普通のことです」です。 WTF?これがREST APIからアクションを「削除」する通常の動作とは何ですか?
私は中立プロジェクトで問題を再現しました。何か間違ったことをしていないことを確かめるために、同じ問題が発生しました。そのため、はい、ヘルパーは浅いものを使用するのが便利かもしれませんが、AT ALLには便利ではありません。「1つのコレクションが1つのプロジェクトにネストされるため、これは反映されます」 URLで」。
これを行う別の方法があるかどうかはわかりません。浅いことでヘルパーの柔軟性が増すのは事実ですが、それが準拠しているのは間違っています。だから、「ヘルパー」を動作させる機会はありますか(「nested1_nested2_nested3([nested1.nested2.nested3、nested1.nested2、nested1])」の代わりに「nested3_path(collection)」を持ち、「 url部分」と「nested1/123/nested2/456/nested3/789を保持しますか?
ありがとう!
Railsは、URLが完全な階層を使用するための組み込みの方法を提供する(たとえば、/projects/1/collections/2
)ショートカットヘルパーもあります(例:collection_path
の代わりに project_collection_path
)。
これを本当にやりたい場合は、次のような独自のカスタムヘルパーを展開できます。
def collection_path(collection)
# every collection record should have a reference to its parent project
project_collection_path(collection.project, collection)
end
しかし、リソースごとに手動で行うのは非常に面倒です。
shallow
ルートの使用の背後にあるアイデアは、ドキュメントで最もよく要約されていると思います。
深いネストを回避する1つの方法(上記で推奨)は、親の下にスコープされたコレクションアクションを生成し、階層の意味を取得しますが、メンバーアクションはネストしません。言い換えると、リソースを一意に識別するために最小限の情報でルートのみを構築すること
ソース: http://guides.rubyonrails.org/routing.html#shallow-nesting
したがって、これはRESTに準拠していない可能性がありますが(あなたが言うように)、各リソースを一意に識別でき、関連付けが適切に設定されていれば階層を遡ることができるため、情報を失うことはありません。
id
にはCollection
があるので、index
およびcreate
アクションを除き、プロジェクトの下にルートをネストすることは冗長です。
URLには、特定のリソースをGET(200で)するURLが1つだけであるというルールがあります。他のURLがある場合は、リダイレクトする必要があります。そのため、/projects/:id/collections/:collection_id
にリダイレクトする/collections/:collection_id
ルートがある場合があります。
あなたの場合、コレクションはプロジェクトに関連付けられていますが、必ずしもすべての関係に当てはまるわけではありません。 :collection_id
を取得したら、それにアクセスするためにProject
のコンテキストを参照する必要はありません。
レベル
ネストされたリソースで1レベルのみを使用する必要があるという概念は、システムの設計にのみ実際に適用できます。
対応するルートヘルパーはpublisher_magazine_photo_urlであり、3つのレベルすべてでオブジェクトを指定する必要があります。確かに、この状況は十分に混乱しているので、Jamis Buckの人気のある記事は、良いRails design:
Railsはまだ複数のレベルを処理できますが、使いやすさの観点からはお勧めしません
浅い
以前は浅いものを使用したことがありますが、自分で使用したことはありません
documentation を見ると、浅いことにはかなりあいまいな目的があるように見えます(実際になぜ存在するのかはわかりません)。問題は、post_id
パラメーターをコントローラーに追加し、重要なパラメーターなしでcollection
をロードできるようにします
私は推測します(そしてこれは単なる推測です)、目的は舞台裏で必要なパラメーターを渡すことなので、パブリックな「浅い」ルートが残っているということです:
#config/routes.rb
resources :projects do
resources :collections, shallow: true
end
次のようなURLヘルパーが得られると思います。
collection_path(project.id, collection.id)
これはdomain.com/collection/2
一部のモデルでのみこれが必要な場合は複雑になりますが、 Inherited Resources (IR)をチェックアウトすると良いかもしれません。ポリモーフィックが属するリソースのネストをサポートし、探している短いパスとURLヘルパーメソッドを自動的に生成できます。あなたがもうIRについてあまり聞いていないのは、元の作者や他の開発者が、コントローラーを拡張しようとする際に生じる複雑さのためにIRをやめたからです。ただし、まだコミュニティがあり、 Irie を使用して、もう少し拡張して、コントローラの拡張の容易さにさらに焦点を当てようとしました。
Railsの「ベストプラクティス」は、誰と話すかによって異なります。
Railsは従来、(ネストされていない)リソースのほとんど基本的なCRUDを対象としていました。はい、ネストされたリソースを取得および更新できますが、それほど頻繁には発生しないと想定されています。
ただし、Railsコミュニティでは、 ActiveModel :: Serializers / json-api アプローチこの場合、通常、リソースのネストは1レベル以下であり、ネストされたリソースはリンクのリストまたは子リソースのサイドロードされた小さなバージョンのいずれかです。さらに、そのリソースでクエリを実行して、より多くのデータを取得できます。これは、 Ember / Ember Dataにも含まれています。 。
また、 roar や、Roy Fieldingの元々のRESTのビジョンに近い何かについての理解に近いものを実装することを目的とする他の多くのプロジェクトがあります。
それは、あなたのデザインが何であり、何が必要かによって決まるだけだと思います。効率性が目標である場合、明示的でより多くネストするために開発するための追加の時間は成果を上げるかもしれません。現在、 AngularJS および Irie を使用しています。しかし、それぞれに。
最後の注意として、クエリでincludes(...)
(または同様の)を使用してn + 1ルックアップを回避するようにしてください。そうしないと、ネストがすべてパフォーマンスに悪影響を与える可能性があります。
この回答から 浅いルートはIMOのRailsの慣習に多少反しているようです。
ショールートの明示的なパスヘルパーは必要ないと思います。 link_toヘルパーは、オブジェクトのto_paramメソッドから推論できるはずです。
#your helper becomes
link_to "show", collection
上記のようにヘルパーを自分の方法で使用する場合は、おそらく親リソースのネストされたIDもヘルパーに渡す必要があります。
link_to "show", collection_path([project, collection])