2009-06-22 8 views
2

Je suis Ruby on Rails débutant et avait une question sur la logique de vue en cas d'objets associés:Affichage des objets associés

Mes modèles se ressemblent à

class Post < ActiveRecord::Base 
    has_many :comments 
end 

class Comment < ActiveRecord::Base 
    belongs_to :post 
end 

Et ce que je veux afficher est quelque chose comme une liste de tous les messages et les trois premiers commentaires pour chacun.

Alors, je gardais l'indice contoller action simple

class PostController < ApplicationController 
    #.. 
    def index 
    @posts = Post.find(:all) 
    end 
    #.. 
end 

Maintenant, dans le views/posts/index.html.erb que je peux faire quelque chose comme ça @posts.comments que je peux boucle pour les trois premières entrées. Mais Comment puis-je accéder à la fonctionnalité qui est normalement effectuée dans le modèle (dans ce cas, le modèle associé), comme la commande, la portée, etc. dans la vue (ou le contrôleur)?

Répondre

1

Vous devez éviter d'écrire une connexion d'entreprise complexe dans la vue. Dans ce cas, votre exécution est assez simple pour que vous puissiez écrire tout le code dans votre vue. Cela devrait ressembler à ceci

<% @posts.each do |post| %> 
    <% @post.comments.all(:limit => 3, :order => "created_at DESC").each do |comment| %> 
     do something 
    <% end %> 
<% end %> 

Il y a quelques améliorations possibles. D'abord, utilisez un named_scope.

class Post < ActiveRecord::Base 
    has_many :comments 
end 

class Comment < ActiveRecord::Base 
    belongs_to :post 
    named_scope :recent, proc { |limit| :limit => limit || 3, :order => "created_at DESC") } 
    # you can also hard-code the limit value (ScottD) 
    named_scope :recent, :limit => 3, :order => "created_at DESC" 
end 


<% @posts.each do |post| %> 
    <% @post.comments.recent.each do |comment| %> 
     do something 
    <% end %> 
<% end %> 

Si j'ai raison, le .each peut être supprimé.

<% @posts.each do |post| %> 
    <% @post.comments.recent do |comment| %> 
     do something 
    <% end %> 
<% end %> 

Si vous préférez, vous pouvez également définir une relation personnalisée (ce qui est des relations très complexes).

+1

Je voudrais apporter quelques petites modifications à votre exemple: 1) Vous n'avez pas besoin du proc sur la portée nommée. Faites juste named_scope: recent: limit => 3,: order ... 2) Dans la vue j'utiliserais un partiel: <% = render: partial "comment",: collection => @ post.comments.recent% > Rails enverra le tableau retourné par le named_scope et rendra le partiel dans une boucle pour vous. – scottd

+0

Merci ScottD! J'ai mis à jour l'exemple. –

+0

Merci Weppos et ScottD. Ça fonctionne parfaitement. Juste une clarification de débutant nécessaire. Dans le code ci-dessus, lorsque PostContoller charge @posts et que view/partail s'exécute @ post.comments.recent, à quel moment les appels sql sont-ils déclenchés? Y a-t-il un moyen de voir cela (traces, etc.)? – mataal

1

Vous pouvez utiliser une méthode de recherche sur l'association qui spécifie une limite comme:

@post.comments.find(:all, :limit => 3) 

à votre avis, ou vous pouvez créer une autre association dans votre modèle quelque chose comme message:

has_many :first_three_comments, :limit => 3, :class_name => "Comment" 

et puis vous pouvez simplement référencer cette association comme

@ post.first_three_comments.each faire | commentaire | ...

Espérons que ça aide.

+0

l'association supplémentaire sera-t-elle plus rapide/plus performante que la solution named_scope mentionnée dans la réponse http://stackoverflow.com/questions/1028830/displaying-associated-objects/1028873#1028873? – mataal

+0

les portées nommées sont une solution plus élégante et remplacent ma solution. named_cope: cheap,: conditions => {: price => 0..5} named_cope: récent, lambda {| * args | {: conditions => ["released_at>?", (args.first || 2.weeks.ago)]}} named_cope: visible,: include =>: category,: conditions => {'categories.hidden' = > false} http://railscasts.com/episodes/108-named-scope –

Questions connexes