web-dev-qa-db-ja.com

Rails 4 [ベストプラクティス]ネストされたリソースと浅い:true

次の投稿は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つのこと:

  • これは機能していません。代わりに「 http://example.com/projects/1 」を取得しています。 WTF?
  • 「コレクションはプロジェクトの子であり、URLは「localhost/project/1/collections/1」でなければならない」というRESTの基本を失うため、実際にはかなり悪い

安静時アクションの大きな利点を失うことである場合、浅瀬の興味が何であるか理解できません。興味は何ですか?そして、「ショー」アクションを失うことへの関心は何ですか?私はすでにこれを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を保持しますか?

ありがとう!

27
Erowlin

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に準拠していない可能性がありますが(あなたが言うように)、各リソースを一意に識別でき、関連付けが適切に設定されていれば階層を遡ることができるため、情報を失うことはありません。

20

idにはCollectionがあるので、indexおよびcreateアクションを除き、プロジェクトの下にルートをネストすることは冗長です。

URLには、特定のリソースをGET(200で)するURLが1つだけであるというルールがあります。他のURLがある場合は、リダイレクトする必要があります。そのため、/projects/:id/collections/:collection_idにリダイレクトする/collections/:collection_idルートがある場合があります。

あなたの場合、コレクションはプロジェクトに関連付けられていますが、必ずしもすべての関係に当てはまるわけではありません。 :collection_idを取得したら、それにアクセスするためにProjectのコンテキストを参照する必要はありません。

10
aceofspades

レベル

ネストされたリソースで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

2
Richard Peck

一部のモデルでのみこれが必要な場合は複雑になりますが、 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ルックアップを回避するようにしてください。そうしないと、ネストがすべてパフォーマンスに悪影響を与える可能性があります。

2
Gary S. Weaver

この回答から 浅いルートはIMOのRailsの慣習に多少反しているようです。

ショールートの明示的なパスヘルパーは必要ないと思います。 link_toヘルパーは、オブジェクトのto_paramメソッドから推論できるはずです。

#your helper becomes 
link_to "show", collection

上記のようにヘルパーを自分の方法で使用する場合は、おそらく親リソースのネストされたIDもヘルパーに渡す必要があります。

link_to "show", collection_path([project, collection])
1
engineerDave