2008-11-11 7 views
3

J'ai trois modèles (pertinents), spécifié comme ceci:rails map.resources avec has_many: through ne fonctionne pas?

class User < ActiveRecord::Base 
    has_many :posts 
    has_many :comments 
    has_many :comments_received, :through => :posts, :source => :comments 
end 

class Post < ActiveRecord::Base 
    belongs_to :user 
    has_many :comments 
end 

class Comment < ActiveRecord::Base 
    belongs_to :user 
    belongs_to :post 
end 

Je voudrais être en mesure de faire référence à tous les comments_received pour un user avec un itinéraire - disons que ce soit pour l'approbation des lots de commentaires sur tous les messages. (Notez que vous pouvez également obtenir comments faite par le user, mais les utilisateurs ne peuvent pas commenter sur leurs propres messages, de sorte que le comments par le biais d'un post sont différents et s'excluent mutuellement). Logiquement, cela devrait fonctionner avec:

map.resources :users, :has_many => [:posts, :comments, :comments_received] 

Cela devrait me donner des itinéraires de

user_posts_path 
user_comments_path 
user_comments_received_path 

Les deux premiers travaux, le dernier ne fonctionne pas. Je l'ai essayé sans le _ en comments_received en vain. Je cherche à obtenir une URL comme

http://some_domain.com/users/123/comments_received 

J'ai aussi nicher essayé, mais peut-être que je fais ce mal. Dans ce cas, je pense que la carte serait:

map.resources :users do |user| 
    user.resources :comments 
    user.resources :posts, :has_many => :comments 
end 

et l'URL pourrait être:

http://some_domain.com/users/123/posts/comments 

Peut-être que c'est la bonne façon de le faire, mais je la mauvaise syntaxe ? Est-ce que je pense à ceci de la mauvaise manière? Il me semble raisonnable que je devrais pouvoir obtenir une page de tous les comments ajoutés à tous les messages d'un utilisateur.

Merci pour votre aide!

Répondre

0

Je dois avouer, je suis un peu confus par les noms de variables, mais d'abord, je suis surpris de votre has_many: à travers les œuvres à tous les niveaux, il est défini. Est-ce que les modèles se comportent comme prévu, mettant de côté les itinéraires une seconde? Deuxièmement, et c'est là que les noms de variables entrent en jeu, les routes ont des dépendances sur la pluralisation, donc vos barres de foos et bazs peuvent être soit une cause du problème, ou peut-être cacher le problème. En tout état de cause, vous pouvez certainement écrire quelque chose comme ceci:

map.resources :users do |user| 
    user.resources :awards 
    user.resources :contest_entries do |contest_entry| 
    contest_entry.resources :awards 
    end 
end 

que je crois vous donnerait:

user_path, user_awards_path, user_contest_entry_path, and user_contest_entry_awards_path. 

Je ne sais pas si cela répond vraiment à votre question, et il pourrait aider à Obtenez une image plus claire de ce qui se passe ici si vous avez changé foo, bar et baz pour quelque chose de plus proche de la situation réelle.

+0

OK, ce n'est pas exactement ce que je fais, mais il est assez proche pour appeler Foo un utilisateur, Bar un message, Baz un commentaire, et xxx est "reçu". L'objectif est d'obtenir un itinéraire qui affiche tous les commentaires sur tous les messages d'un utilisateur donné, en notant que les utilisateurs ne peuvent pas commenter leurs propres messages. –

0

Une solution rapide-n-sale serait d'ajouter une méthode personnalisée (par ex.getusercomments) à vos utilisateurs-contrôleur qui rentreraient tous les commentaires:

def getusercomments 
@user = User.find(params[:id]) 
@comments = @user.posts.comments 
end 

Puis ajouter cette méthode à vos utilisateurs route:

map.resources :users, :member => { :getusercomments => :get } 

Ensuite, vous devriez être en mesure d'appeler ce qui suit pour obtenir tous commentaires d'un utilisateur:

http://some_domain.com/users/123/getusercomments 
2

Bien que la syntaxe de deinfe relation de ressources et le modèle est similaire, vous ne devriez pas être dupé en pensant qu'une des cartes de ressources à un modèle. Lire ce que David Black has to say.

Le problème que vous rencontrez concerne les routes que vous générez. En utilisant la syntaxe imbriquée comme ceci:

map.resources :users do |user| 
    user.resources :posts 
    user.resources :comments 
    user.resources :comments_received 
end 

Et puis en exécutant 'rake routes', me donne (parmi les charges d'autres choses!):

     users GET /users        {:action=>"index", :controller=>"users"} 
        user_posts GET /users/:user_id/posts    {:action=>"index", :controller=>"posts"} 
       user_comments GET /users/:user_id/comments   {:action=>"index", :controller=>"comments"} 
user_comments_received_index GET /users/:user_id/comments_received {:action=>"index", :controller=>"comments_received"} 

Il semble donc que des rails est l'ajout _index à la fin de la route comments_received. Je dois admettre que je ne sais pas pourquoi (quelque chose à voir avec les autres commentaires de route?) Mais cela explique votre problème.

Une plus belle alternative pourrait consister à définir une action de collecte sur votre ressource commentaires, comme ceci:

map.resources :users do |user| 
    user.resources :posts 
    user.resources :comments, :collection => {:received => :get} 
end 

Cela vous donnera les itinéraires suivants:

    users GET /users        {:action=>"index", :controller=>"users"} 
      user_posts GET /users/:user_id/posts    {:action=>"index", :controller=>"posts"} 
     user_comments GET /users/:user_id/comments   {:action=>"index", :controller=>"comments"} 
received_user_comments GET /users/:user_id/comments/received {:action=>"received", :controller=>"comments"} 

Note: l'action reçue est Maintenant, sur le contrôleur de commentaires

Questions connexes