Multiple connections using activerecord in rails

I am creating a small Twitter style microblogging service where users can follow other users and get a feed of their posts

I have the following models:

class Follow < ActiveRecord::Base
  belongs_to :follower, :class_name => "User"
  belongs_to :followee, :class_name => "User"
end

class User < ActiveRecord::Base
  has_many :follows,   :foreign_key => 'follower_id',
                       :class_name => 'Follow'
  has_many :followers, :through => :follows
  has_many :followed,  :foreign_key => 'followee_id',
                       :class_name => 'Follow'
  has_many :followees, :through => :followed
  has_many :messages
end

class Message < ActiveRecord::Base
  belongs_to :user
end

      

To get the feed for the current user, I want to execute the following SQL query:

SELECT * FROM follows JOIN users JOIN messages WHERE follows.follower_id = current_user.id AND follows.followee_id = users.id AND users.id = messages.user_id;

      

What is the correct ActiveRecord way to do this?

+1


source to share


2 answers


Not sure what you are looking for, but here is my suggestion:

I am assuming you have other targets for this Follow class, otherwise I cannot see its purpose.

The "correct way" (ie my totally subjective way) of doing this would actually be something like this:

class User < ActiveRecord::Base
  has_and_belongs_to_many :followers, :foreign_key => 'followed_id', 
      :class_name => 'User', :association_foreign_key => 'follower_id', 
      :include => [:messages]
  has_and_belongs_to_many :follows, :foreign_key => 'follower_id', 
      :class_name => 'User', :association_foreign_key => 'followed_id'
  has_many :messages
end

class Message < ActiveRecord::Base
  belongs_to :user
end

      

Then create the following table:

create_table :users_users, :id => false do |t|
  t.integer :followed_id
  t.integer :follower_id
end

      

And you installed:

followed = User.find :first
follower = User.find :last

followed.followers << follower

followed.followers.first.messages
followed.followers.first.followers.first.messages # etc...

      



But from what I do you want to display all posts from all subscribers at the same time.

This can be achieved by adding

 has_and_belongs_to_many :followed_messages, :foreign_key => 'follower_id', 
  :class_name => 'Message', :association_foreign_key => 'followed_id'

      

for the User class, but I don't know how correct that would be. Or could be achieved with extension of the association, but there I really cannot give examples. Business>

Update: By changing: class_name it will associate it with Message.id

, didn't think about it, so it won't be correct this way.

So the only "good" option is to go through the User class like in the first example. The only other options I see are either association extensions (which I cannot give you) or perhaps using a finder statement.

 has_many :followed_messages, :class_name => 'Message',
  :finder_sql => 'select * from messages where user_id in(select followed_id from users_users where follower_id = #{id})'

      

You will probably have to tweak this sql statement to get everything to work, but at least you should get an image :)

+1


source


Keijro's organization will perform better, although if you need a Follow table, then you can execute the requested SQL query like this:



Follow.all(:joins => { :messages, :users }, :conditions => { "follows.follower_id" => current_user.id, "follows.followee_id" => "users.id", "users.id" => "messages.user_id"} )

      

+1


source







All Articles