2009-08-11 12 views
7

Ich bekomme keine REST mit Ruby on Rails, und ich hoffe, dass jemand hier mich richtig stellen kann.Rails: Wie RESTful Query-Modelle durch Assoziationen?

Stellen Sie sich vor, dass ich eine Website erstelle, die Widgets und die Benutzer, denen diese Widgets gehören, verfolgt. Also würde ich einen Userscontroller und eine WidgetsController, und ich konnte eine Liste von Widgets oder Benutzern mit der Index Aktionen erhalten:

GET /users 
GET /widgets 

und ich konnte einen bestimmten Benutzer oder Widget mit der Show Aktionen erhalten:

GET /users/id 
GET /widgets/id 

So viel verstehe ich.

Wo bekomme ich verwirrt ist, welche RESTful Anfrage würde ich verwenden, um eine Liste von Widgets eines bestimmten Benutzers zu erhalten? Wird eine Anfrage an den UsersController oder den WidgetsController gesendet? Welche der 7 RESTful-Aktionen wird verwendet?

Ist eine dieser Situationen, in denen ich eine benutzerdefinierte Aktion erstellen würde? Ich hatte den Eindruck, dass benutzerdefinierte Aktionen selten sein sollten, aber das scheint ein ziemlich häufiger Anwendungsfall zu sein.

Danke!

+0

Sie sollten wirklich auf Darrel Miller's Antworten hören - URI Formatierung hat nichts mit REST zu tun. Sie sollten sich vielleicht auch einige REST-Themen zu StackOverflow ansehen, die es ausführlicher erklären, oder sich Fieldings Dissertation ansehen. – aehlke

+1

Meine Frage ging nicht um hübsche URLs - es ging darum, welchen Rails-Controller ich für die Anfrage verwenden würde und welche Aktion verwendet werden würde. –

Antwort

4

Die URL für die Liste der Widgets zu einem Benutzer gehören foo würde wie folgt aussehen:

/users/foo/widgets 

Sie haben dann die Wahl, wie Sie Ihre URLs für jede dieser Widgets zu tun. Dies ist möglich:

/users/foo/widgets/bar 

Aber ich ziehe diese:

map.resources :users, :has_many => :widgets, :shallow => true 
map.resources :widgets, :has_many => :users, :shallow => true 

(Dies ist aus dem Gedächtnis, ich vermasselt haben ein oder:

/widgets/bar 

Ihre Routen würde wie folgt aussehen mehr Details)

Die Controller-Methode, die /user/foo/widgets behandelt, ist die index Aktion der WidgetController. Es testet auf die Existenz des Parameters user_id und beschränkt die darauf zurückgegebenen Widgets. (Oder ruft die foo Benutzer und setzt @widgets zu @user.widgets.)

Update: Es gibt einen guten Überblick über verschachtelten Routing, die meine ursprüngliche Frage in den Rails Guides beantwortet.

Update 2 Oh ja, ich wollte auch mit einigen documentation verknüpfen.

+0

Ah, das macht viel Sinn. Mir war die Option: seicht für map.resources nicht bekannt. Vielen Dank! –

+0

Spot on, aber die Beziehung hier ist "has_and_belongs_to_many", da ein Benutzer viele Widgets haben kann, und ein Widget kann zu vielen Benutzern gehören. – askegg

+0

Du würdest vermutlich has_many und has_many: durch Beziehungen zu etwas wie einem 'UserWidget' (lahmen Namen) anstatt einem' habtm' verbinden, hätte ich gedacht. – wombleton

1

Sie finden den Entwurfsprozess schwierig, weil Sie versuchen, Ihre Website basierend auf einem URL-Bereich zu entwerfen, wenn Sie stattdessen Ihre Inhaltsdokumente entwerfen sollten.

Hier sind eine Reihe von Medientypen, die Ihre Anforderungen erfüllen.

Medientyp: application/vnd.yourcompany.collections + xml

<Collections> 
    <Widgets href="http://yoursite.com/{9BCCD309-644C-4fb8-A35E-A8B5E6AC4AE8}"/> 
    <Users href="http://yoursite.com/{BE57DC2D-8FE7-45e3-9362-AF5F607D62B6}"/> 
</Collections> 

Medientyp: application/vnd.yourcompany.Widgets + xml

<Widgets> 
    <Widget href="http://yoursite.com/{4A7B5583-5D09-4cf3-9781-1084977769C0}"/> 
    <Widget href="http://yoursite.com/{0D6A72E8-6088-462c-A97A-70BC43E25475}"/> 
</Widgets> 

Medientyp: application/vnd.yourcompany .Users + xml

<Users> 
    <User href="http://yoursite.com/{6321D95E-7EDB-46b8-9430-AB57EA067B06}"/> 
    <User href="http://yoursite.com/{0D6A72E8-6088-462c-A97A-70BC43E25475}"/> 
</Users> 

Medientyp: application/vnd.yourcompany.Widget + xml

<Widget> 
    <Property1>99</Property1> 
    <Property2>A Description</Property2> 
    <UsersOfWidget href="http://yoursite.com/{26995C10-CA1D-4f1f-9065-2246A8426DA7}"/> 
</Widget> 

Medientyp: application/vnd.yourcompany.User + xml

<User> 
    <Name>Joe Smith</User> 
    <WidgetsOwnedByUser href="http://yoursite.com/{D718A2E6-6ADD-4d6e-A1E7-6DA68EDE0BD3}"/> 
</User> 

Offensichtlich dieser Satz von Medientypen ist nur eine von vielen möglichen Lösungen für Ihr Problem. Das Problem, auf das ich aufmerksam machen möchte, ist, dass die URL weitgehend irrelevant ist. Wie die Dokumente zusammenhängen, ist wichtig. Wenn Sie es auf diese Weise betrachten, ist es nicht schwierig, zwischen den Widgets, die von einem Benutzer verwendet werden, und den Benutzern, die ein Widget verwenden, zu unterscheiden.

Nun, wie Sie dies auf eine Reihe von Rails-Controller zuordnen, ist eine ganz andere Sache. Das Problem ist nicht, dass es schwierig ist, eine REST-konforme Lösung zu entwerfen, sondern es scheint, dass Rails nicht sehr natürlich zu mappen scheint. Nicht, dass ich viel Erfahrung mit Rails habe, also nimm das für das, was es wert ist. Ich glaube, dass Sie einen Controller pro Ressource haben sollten, und die Tatsache, dass Rails versucht, die Liste einer Ressource und die Ressource selbst in einen einzigen Controller zu pressen, ist ein Fehler. Kunden und Kunden sind meiner Meinung nach zwei verschiedene Ressourcen.

Bearbeiten: Möglicher Satz von URLs, die diese Ressourcen möglicherweise verknüpfen.

/Widgets 
/Users 
/Widget/1 
/User/99 
/Widget/1/UsersOfWidget 
/User/99/WidgetsOwned 

Ich würde einen Controller für jeden dieser Endpunkte erstellen.

+1

Danke für Ihre Antwort, aber ich habe NFI, wovon Sie reden. Sie scheinen nicht einmal Widgets im Besitz von Benutzern zu erwähnen? Ich suchte nach einer Antwort wie "Sie sollten eine benutzerdefinierte Aktion auf Ihrem Controller erstellen" oder "Sie sollten die Indexaktion auf Ihrem Widgets-Controller verwenden und XYZ darin tun". –

+0

:-) Ich habe den Namen einiger Elemente in den letzten beiden Dokumenten geändert, um zu klären. Eine Konvention, die ich in XML-Dokumenten verwende, die von RESTful-Schnittstellen zurückgegeben werden, besteht darin, dass ich, wenn ein Element über eine href verfügt, dieser Verknüpfung folgen kann, um eine vollständige Darstellung dieser Ressource abzurufen. Entschuldigung, ich wusste nicht, dass es so unklar ist. Ich denke, ich habe zu viel Zeit damit verbracht, Dokumente wie diese zu betrachten. –

+1

Ich wusste, dass Sie nach einem "wie funktioniert das in Rails" suchen, aber ich versuche herauszufinden, dass das Denken in Bezug auf URLs und Aktionen auf Controllern es wirklich schwer machen wird, wenn Sie härter schlagen Probleme beim Entwurf von RESTful-Schnittstellen. Ich zeige Ihnen die URLs, die ich verwenden würde, um dieses Problem zu modellieren, von dem aus es offensichtlich ist, wie es in Rails gemacht wird. –

1

Ich denke, dass Darrel versucht, Sie auf REST im Allgemeinen zu erziehen, wie er sagt, sich zu viel über URL-Design zu sorgen, könnte ein Zeichen dafür sein, dass Sie RESTful nicht wirklich entwerfen. Wie Darrel zeigt, könnte Ihre Benutzerdarstellung beispielsweise die Links zu den Widgets enthalten, die ihm gehören (oder einen Link zu einer URL, die eine Suche nach den Widgets durchführt, die der Benutzer besitzt).

Verwandte Themen