开发者

Accessing all comments, on all posts, that a current_user has commented on

This is sorta related to another question I asked recently. But before I implement that question's answer, I wanted to try and do this in a more simple way.

I have built a ruby on rails application that allows users to track their workouts. Workouts also have the ability to be commented on. In my dashboard view for current_user I am trying to fish out all comments from workouts that current_user has commented on. Here is an example:

User A creates a workout and User B comments on it. User C comments on User A's workout. I want User B to see User C's comment in their dashboard view.

What is the most efficient way to loop through comments and pull out all comments from workouts that a user has commented on? It's like I want to say this but obviously开发者_运维知识库 this won't work:

<% current_user.comments.workouts.comments.each do |comment| %>

I have been experimenting with named_scopes for this but can't seem to figure it out. The associations are as you would expect.

User has_many :workouts
User has_many :comments

Workout belongs_to :user
Workout has_many :comments

Comment belongs_to :user
Comment belongs_to :workout


As you'd probably want to organize the comments according the the workouts that the user had commented on (as opposed to one long undifferentiated string of comments without any context), first I'd suggest using a :has_many => through to aggregate the workouts that the user had commented on, something roughly like (untested, obviously):

has_many :commented_workouts, :through => :comments, :class_name => 'Workout', :source =>  :workout, :uniq => true, :order => "created_at desc"

Then you could display the comments in your erb something like:

<% current_user.commented_workouts.each do |workout| %>
  <%= workout.name %>:
  <% workout.comments.each do |comment| %>
    <%= comment.text %>
  <% end %>
<% end %>

EDIT: you could also do:

<% current_user.commented_workouts.each do |workout| %>
  <% workout.comments.sort{|x,y| x.created_at <=> y.created_at }.each do |comment| %>
    <%= comment.user.name %> just commented on <%= workout.title %>:
    <div><%= comment.text %></div>
  <% end %>
<% end %>

EDIT: Or like so (note the limit added to the array):

class User
  def watched_comments
    commented_workouts.map(&:comments).flatten.sort{|x,y| x.created_at <=> y.created_at }
  end
end

# and in the erb: 

<% current_user.watched_comments[0,10].each do |comment| %>
  <%= comment.user.name %> just commented on <%= comment.workout.title %>:
  <div><%= comment.text %></div>
<% end %>

There's a bit of nasty n+1 query fu going on here that might not be real performant tho. Alternately you could try to get everything done in straight sql which would perform better. Something like (sql ninjas no doubt could do better):

EDIT: You can also add a 'limit' option directly in the SQL

has_many :watched_comments, :class_name => 'Comment', :finder_sql => 'select * from comments, workouts where comments.workout_id = workout.id and workouts.id in (select workouts.id from workouts, comments where workouts.id = comments.id and comments.user_id = #{id}) order by comments.created_at desc limit 10'


Something like

<% workouts = []
   current_user.comments.each do |comment|
     unless workouts.include? comment.workout.id  # prevents duplicates
       workouts << comment.workout.id
       comment.workout.comments.each do |comment|
         # now comment refers to all comments for that workout
         puts "#{comment.user.name} says #{comment.text}"
       end
     end  
   end %> 

Essentially, you grab the workout associated with each of their comments and display all the comments for them.

For extra homework ;)

  1. Flag their own comment with something special


class User < ActiveRecord::Base

   has_many :workouts
   has_many :comments

   def workouts_on_which_i_commented
     comments.map{|x|x.workout}.uniq
   end

   def comment_stream
     workouts_on_which_i_commented.map do |w|
       w.comments
     end.flatten.sort{|x,y| y.created_at <=> x.created_at}
   end

end
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜