2014-02-19 11 views
27

Der folgende Beitrag basiert auf Rails 4.Rails 4 [Best Practices] Verschachtelte Ressourcen und flach: true

Ich suche eigentlich für eine gute Best-Practices über die mehr verschachtelten Ressourcen (mehr als 1), und die Option flach: wahr.

Erste in meiner Routen gab es dies:

resources :projects do 
    resources :collections 
    end 

Die Routen zugeordnet sind:

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 

ich in der Dokumentation über die Begrenzung der verschachtelten Ressourcen lesen:

Ressourcen sollten nie mehr als 1 Ebene tief verschachtelt sein.

Quelle: http://guides.rubyonrails.org/routing.html#limits-to-nesting Ok. Dann, wie die Dokumentation sagte, werde ich "seicht" auf meinen Routen verwenden.

shallow do 
    resources :projects do 
      resources :collections 
    end 
end 

Die zugehörigen Routen sind:

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 

Der wesentliche Unterschied sehe ich die "Show" von Sammlungen ist, diese:

collection GET /collections/:id(.:format)      collections#show 

Also, wenn ich ich habe recht, Der Link für die Show-Aktion für eine Sammlung lautet:

<%= link_to 'Show", collection_path(collection)%> 

und sollte so etwas zurückgeben: "http://example.com/collections/1"

ABER! 2 Dinge:

  • Dies funktioniert nicht. Ich bekomme stattdessen "http://example.com/projects/1". WTF?
  • Auch wenn es funktioniert, es ist eigentlich ziemlich schlecht ist, weil ich den Rest Grund verlieren, die sagen, localhost/Projekt/1/Sammlungen/1 ‚

„Collection ist Kind des Projektes, dann sollte die URL sein‘ Ich verstehe nicht, was das Interesse von seicht ist, wenn es den großen Vorteil von Ruheaktionen verliert. Was ist das Interesse? Und was ist das Interesse daran, die "Show" -Aktion zu verlieren? Ich habe dies bereits in SO gepostet, aber der einzige Kommentar Ich habe ist "Es ist etwas normales". WTF? In was das ist ein normales Verhalten zu "entfernen" eine Aktion aus dem Rest API?

Ich reproduzierte das Problem auf ein neutrales Projekt, um sicher zu sein, dass ich nicht tat etwas stimmt nicht, und das gleiche Problem ist passiert. Also, ja, es kann für die Helfer bequem sein, seicht zu verwenden, aber es ist NICHT ALLES bequem für den Rest, Sie verlieren alle Interessen von "eine Sammlung ist verschachtelt zu einem Projekt, so dass dies in der URL widergespiegelt wird".

Ich weiß nicht, ob es einen anderen Weg, dies zu tun, es ist wahr, dass seichte mehr Flexibilität über die Helfer erlauben, aber es ist falsch, dass es konform Ruhe. Also, gibt es eine Chance, die "Helfer" zum Arbeiten zu bringen (es ist ziemlich toll, "nested3_path (collection)" anstelle von "nested1_nested2_nested3 ([nested1.nested2.nested3, nested1.nested2, nested1])" zu haben, und die " URL-Teil "und behalten" Nested1/123/Nested2/456/Nested3/789?

Danke!

+0

Haben Sie versucht, den Server neu zu starten, damit die Routen wirksam werden? Nach dem doc 'Ressourcen: Beiträge, seichte: true tun Ressourcen: Kommentare end' produzieren ' Ressourcen: Beiträge tun Ressourcen: Kommentare, außer: [: show, bearbeiten,: update, : destroy] ende resources: nur kommentare: [: show,: bearbeiten,: update,: destroy] ' die klingen wie du machst – jamesy829

+0

Der Server muss tatsächlich neu gestartet werden, damit die Routen wirksam werden. – 0112

Antwort

20

Ich glaube nicht, dass Rails integrierte Möglichkeit bietet, die URLs die vollständige Hierarchie (z. /projects/1/collections/2), haben aber auch die Abkürzungshelfer (z. B. collection_path anstelle von project_collection_path).

Wenn Sie wirklich tun möchten, können Sie Ihre eigenen Helfer wie folgt ausrollen:

def collection_path(collection) 
    # every collection record should have a reference to its parent project 
    project_collection_path(collection.project, collection) 
end 

Aber das wäre recht umständlich manuell für jede Ressource zu tun.


Ich denke, die Idee, die hinter dem Einsatz von shallow Routen wird am besten durch die Dokumentation zusammengefasst:

Eine Möglichkeit, tiefe Verschachtelung zu vermeiden (wie oben empfohlen) ist die Sammlung Aktionen scoped zu erzeugen unter dem Elternteil, um einen Sinn der Hierarchie zu bekommen, aber die Mitgliederaktionen nicht verschachteln.Mit anderen Worten, zu bauen nur Routen mit der minimalen Menge an Informationen zu eindeutig der Ressource identifiziert

Quelle: http://guides.rubyonrails.org/routing.html#shallow-nesting

So, während dies möglicherweise nicht REST-konform sein (wie Sie sagen), Sie verlieren keine Informationen, da jede Ressource eindeutig identifiziert werden kann und Sie in der Lage sind, die Hierarchie wieder zu durchlaufen, vorausgesetzt, Ihre Verknüpfungen sind ordnungsgemäß eingerichtet.

+0

Während es nicht in Rails integriert ist, [Inherited Resources] (https://github.com/josevalim/inherited_resources) (IR) hat Nisthilfen und Helfer, die helfen könnten. Es kann jedoch sinnvoll sein, explizit zu sein und IR nicht zu verwenden, wenn es nur eine Handvoll Fälle gibt, in denen dies geschieht, und es kann je nach Bedarf auch die Implementierung/das Debugging von Controllern einschränken oder komplizieren. –

2

Level

Der Begriff Sie haben 1-Ebene in Ihren verschachtelten Ressourcen nutzen, um das Design des Systems nur dann wirklich anwendbar ist:

Die entsprechende Route Helfer publisher_magazine_photo_url wären, Sie müssen Objekte auf allen drei Ebenen angeben. Tatsächlich ist diese Situation ist verwirrend genug, dass ein beliebter Artikel von Jamis Buck Faustregel für eine gute Rails Design schlägt:

Ich glaube, Rails noch mehrere Ebenen verarbeiten kann, obwohl es nicht aus Usability-Sicht empfohlen wird


Shallow

Obwohl ich flach, bevor sie verwendet gesehen, die ich benutzt habe es selbst nie

Aus dem Blick auf die documentation, scheint es seicht hat einen eher obskuren Zweck (ich weiß nicht wirklich, warum es da ist). Das Problem ist, dass Sie nicht öffentlich Passieren der post_id Parameter zu Ihrem Controller, Sie verlassen die collection ohne wichtigen param

ich vermuten würde laden (und das ist nur Spekulation), dass das Ziel, die param Sie passieren soll erfordern hinter den Kulissen, so dass Sie mit einem öffentlichen „flachen“ Route links:

#config/routes.rb 
resources :projects do 
    resources :collections, shallow: true 
end 

ich könnte mir vorstellen, eine URL-Helfer wie diese bekommen würde:

collection_path(project.id, collection.id) 

diese kommen würde als domain.com/collection/2

+0

Ja, Sie haben Recht auf den Routen, aber das hilft nicht viel für meine Frage =/ – Erowlin

10

Da es für ein Collection ein id, es ist überflüssig die Route unter dem Projekt Nest mit Ausnahme der index und create Aktionen.

Es gibt eine Regel über URLs, wo es nur eine URL geben soll, um eine gegebene Ressource zu GET (mit 200) zu bekommen, wenn es andere URLs gibt, die Sie dorthin umleiten sollten. Sie haben also möglicherweise eine Route /projects/:id/collections/:collection_id, die zu /collections/:collection_id umleitet.

In Ihrem Fall ist eine Sammlung an ein Projekt gebunden, aber das gilt nicht unbedingt für alle Beziehungen. Sobald Sie die :collection_id haben, müssen Sie nicht auf den Kontext der Project verweisen, um darauf zuzugreifen.

+0

Ja! Vielen Dank! Ich habe gegoogelt und nach einer grundlegenden Erklärung für den Zweck von flachen Routen gesucht! Annahme in der Dokumentation ist: Sie kennen das bereits. Nach einigen anderen Antworten hier zu urteilen, wissen viele auch nicht! Was Sie sagen, ist, wenn Sie zum Beispiel einen Kommentar bearbeiten von: id, macht es keinen Sinn, das unter einem Projekt zu verschachteln, weil der Kommentar: id unabhängig von der Projekt-ID ist. Shallow räumt nur die Routen auf, um dies zu reflektieren. – Colin

2

Obwohl es Dinge komplizieren kann, wenn Sie nur diese für einige Modelle benötigen, könnte es gut sein, Inherited Resources (IR) auschecken. Es unterstützt die Verschachtelung von Ressourcen, ist polymorph und gehört automatisch zu den kürzeren Pfad- und URL-Hilfsmethoden, nach denen Sie suchen. Der Grund, warum Sie nicht mehr viel von IR hören, ist, dass der ursprüngliche Autor und einige andere Entwickler es wegen der Komplikationen, die beim Versuch entstehen, Ihre Controller zu erweitern, etwas aufgegeben haben. Es hat jedoch immer noch eine Community und wir haben versucht, es ein wenig mehr zu erweitern und konzentrieren uns mehr auf die Leichtigkeit der Controller-Erweiterungen mit Irie.

Die "Best Practice" in Rails hängt davon ab, mit wem Sie sprechen.

Rails wurde traditionell auf meist grundlegende CRUD für (nicht verschachtelte) Ressourcen ausgerichtet. Ja, es ermöglicht das Abrufen und Aktualisieren von verschachtelten Ressourcen, aber es wird angenommen, dass dies nicht ganz so häufig passiert.

Was jedoch in der Rails-Community auftaucht, ist der ActiveModel::Serializers/json-api Ansatz. Dabei tritt normalerweise nicht mehr als eine Ebene der Verschachtelung von Ressourcen auf, und die verschachtelte Ressource ist entweder eine Liste von Links oder eine seitengeladene kleine Version der untergeordneten Ressourcen, die Sie dann auf dieser Ressource abfragen können, um mehr Daten zu erhalten. Dies wurde auch von Ember/Ember Data umfasst.

Es gibt auch roar und eine Reihe von anderen Projekten, die etwas näher an ihr Verständnis von etwas in der Nähe von Roy Fieldings ursprünglicher Vision von REST implementieren wollen.

Ich denke, es hängt nur davon ab, was Ihr Design ist und was Sie brauchen. Wenn Effizienz ein Ziel ist, dann kann sich die zusätzliche Zeit, die es braucht, um explizit zu sein und mehr zu nisten, auszahlen. Wir verwenden z. B. derzeit AngularJS und Irie. Aber für jeden sein eigenes.

Wie in der letzten Anmerkung, sollten Sie n + 1 Lookups durch die Verwendung von (oder ähnlich) in Ihren Abfragen vermeiden, da sonst die ganze Verschachtelung Sie bei der Leistung beeinträchtigen könnte.

1

From this answer scheint es flache Routen etwas die Konvention von Rails, IMO trotzen.

Ich würde denken, dass Sie den expliziten Pfadhelfer für eine Showroute nicht benötigen würden. Der link_to-Helper sollte in der Lage sein, dies aus der to_param-Methode des Objekts abzuleiten.

#your helper becomes 
link_to "show", collection 

Wenn der Helfer den Weg benutzen, wie Sie haben über Sie wahrscheinlich die verschachtelte ID des übergeordneten Ressource an den Helfer zu übergeben müssen.

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