views:

242

answers:

1

First the data model:

class Forum < ActiveRecord::Base
  has_many :topics, :dependent => :destroy, :order => 'created_at desc'
end

class User < ActiveRecord::Base
  has_many :topics, :dependent => :destroy
  has_many :comments, :dependent => :destroy
  has_many :replies, :dependent => :destroy
end

class Topic < ActiveRecord::Base
  belongs_to :forum
  belongs_to :user
  has_many :comments, :dependent => :destroy
end

class Comment < ActiveRecord::Base
  belongs_to :user
  belongs_to :topic
  has_many :replies, :dependent => :destroy
end

class Reply < ActiveRecord::Base
  belongs_to :user
  belongs_to :comment
end

So Users can post Topics to Forums. They can also post Comments to the Topics in a Forum. And they can post Replies to the Comments.

I want to be able to get a list of Forums they've participated in by posting either Topics or Comments or Replies.

A: 

What you're looking for is a named scope in the Forum model.

The join can be greatly simplified by adding has_many :through relationships for your Comment and Reply models in the Forum model. But I can never remember how nested joins work out, so I've posted a solution that will work with what you've got.

class Forum < ActiveRecord::Base
  has_many :topics, :dependent => :destroy, :order => 'created_at desc'
  named_scope :user_posted, lambda {|user|
    { :joins => "JOIN topics t ON t.forum_id = forums.id " +
        "JOIN comments c ON c.topic_id = t.id " +
        "JOIN replies r ON r.comment_id = c.id", 
      :conditions => ["t.user_id = ? OR c.user_id = ? OR r.user_id = ?", 
        user, user, user], 
      :group => "forums.id"
    }
  }
end

Now...

Forum.user_posted(@user)

Will return an array of forums where a user has posted a topic, reply or comment.

For a list of forums a particular user has posted in:

class User < ActiveRecord::Base
  has_many :topics, :dependent => :destroy
  has_many :comments, :dependent => :destroy
  has_many :replies, :dependent => :destroy    
  named_scope :posted_in_forum, lambda {|forum|
    { :joins => "JOIN replies r ON r.user_id = users.id "+
        "JOIN comments c ON c.user_id = users.id OR c.id = r.comment_id " +
        "JOIN topics t ON t.user_id = users.id OR t.id = c.topic_id " +
        "JOIN forums f ON t.forum_id = forums.id ",
      :conditions => ["f.id = ?", forum], 
      :group => "users.id"
    }
  }
end

Assuming I got that right, this statement:

User.posted_in_forum(@forum)

will return a list of users that have posted in forum either by topic, comment or reply.

P.S. it's probably not a good idea to allow destruction of users in this model. The way you've laid things out, if a user is destroyed, any topics, replies or comments they posted will also be removed. Instead your users should be deactivated.

EmFi
That's great! Thx for the excellent and fast reply.I had to edit your ':group_by' to ':group', but otherwise, it gives me just what I was looking for. I *knew* it had to be thru named_scope.And, yes, I agree with your pt about user deactivation vs destruction. Thx again.
lunaclaire
Followup question: How would I get the list of Users who have posted to a particular Forum?
lunaclaire
I've updated the solution to correct the :group != :group_by mistake, and include a named scope that addresses your followup question.P.S. If you've found an answer helpful, you should vote it up. If it's solved your problem you should accept it. That way others who have a similar problem will find it easier to identify the correct solution.
EmFi
Thx again for the quick response.And... I've accepted the answer, but I guess I dont have the 15 pts needed to vote something up. :-(
lunaclaire
hmm... getting an error on that SQL"ActiveRecord::StatementInvalid (Mysql::Error: You have an error in your SQL syntax;..."but I dont see what the cause is
lunaclaire
The SQL error came from a missing space in one of the join strings.Don't worry about the vote up. I personally don't need the reputation, but it's a good habit to get into.
EmFi
thx again (and agreed on voting - as soon as I can). but, I get a new error:Mysql::Error: Unknown column 'buzzboards.id' in 'on clause'I'm rusty with sql joins, so cant figure it out at the moment.
lunaclaire