How to print my posts and posts of my friends? - ruby-on-rails

I have 2 models, user and friendship, here's how they looks like:
class User < ActiveRecord::Base
has_many :posts
has_many :friendships, :conditions => { :confirmed => true }
has_many :friend_requests, :class_name => 'Friendship', :conditions => { :confirmed => false }
has_many :friends, :through => :friendships
has_many :friends_friendships, :through => :friends, :source => :friendships
has_many :friends_of_friends, :through => :friends_friendships, :source => :friend
has_many :friends_listings, :through => :friends, :source => :listings
has_many :friends_posts, :through => :friends, :source => :posts
...
end
and
class Friendship < ActiveRecord::Base
belongs_to :user
belongs_to :friend, :class_name => "User"
attr_accessible :friend_id
...
end
and here's how I fetch posts of currently logged in user and posts of his/her friends:
#my_posts = current_user.posts.includes(:user)
#friends_posts = current_user.friends_posts.includes(:user)
This is working well, but how can I load my posts + posts of my friends into one variable and display them as on Facebook? In other words, how can I merge those 2 queries into only one?
Thanks

something like this:
ids = current_user.friends.pluck(:id) << current_user.id
posts = Post.where(user_id: ids)
return
SELECT `posts`.* FROM `posts` WHERE `posts`.`user_id` IN (1, 2, 3, 6)
then in view:
posts.each do |post|
....
end

Related

How not get current_user

i'm breaking my head to get the user of this situation:
a conversation model:
has_many :conversation_participants, :dependent => :destroy
has_many :users,
:through => :conversation_participants
has_many :messages, :dependent => :destroy
has_one :display_message,
:class_name => 'Message',
:order => 'created_at DESC'
def participants(options={})
if options[:not].is_a? User
users - [options[:not]]
else
users
end
end
and conversation_participants:
belongs_to :user
belongs_to :conversation
attr_accessible :user_id
on a conversation helper:
def self_or_other
#conversation.conversation_participants.find_by_user_id(:not => current_user)
end
please, someone could clear me how to get the other user inside conversation_participants model?
I believe like follows:
#conversation.conversation_participants.where.not(user_id: current_user.id).first

Mixing Self Referencial, Many to Many and Polymorphic Relations

I'm working on some app, I have User, Post and Report models so users can report other users, or posts. So I did this:
class Report < ActiveRecord::Base
belongs_to :user
belongs_to :reportable, :polymorphic => true
...
class User < ActiveRecord::Base
has_many :reports, :dependent => :destroy
has_many :reported_users, :through => :reports, :source => :reportable, :source_type => 'User'
has_many :reported_posts, :through => :reports, :source => :reportable, :source_type => 'Post'
has_many :reports, :as => :reportable, :dependent => :destroy
...
class Post < ActiveRecord::Base
has_many :reports, :as => :reportable, :dependent => :destroy
...
And my user spec looks like:
it 'reports another user' do
#reporter = FactoryGirl.create(:user)
#reported = FactoryGirl.create(:user)
Report.create!(:user => #reporter, :reportable => #reported)
Report.count.should == 1
#reporter.reported_users.size.should == 1
end
And I get an error saying:
User reports another user
Failure/Error: #reporter.reported_users.size.should == 1
expected: 1
got: 0 (using ==)
Can't figure out whats wrong, can I use has_many :reports and has_many :reports, :as => :reportable together in a model? Also, how can I get the reporters for a user? Let's say I want to have #user.reporters to get all other users who have reported a particular user.
Changing the second has_many :reports to has_many :inverse_reports solved the problem:
class User < ActiveRecord::Base
has_many :reports, :dependent => :destroy
has_many :reported_users, :through => :reports, :source => :reportable, :source_type => 'User'
has_many :reported_posts, :through => :reports, :source => :reportable, :source_type => 'Post'
has_many :inverse_reports, :class_name => 'Report', :as => :reportable, :dependent => :destroy
Now I guess I can also get the reporters for each user like:
has_many :reporters, :through => :inverse_reports, :source => :user

named_scope and HABTM association

I have a models User
class User < ActiveRecord::Base
has_many :ratings
has_many :rated_films, :through => :ratings, :source => :film
end
and Films
class Film < ActiveRecord::Base
has_many :users, :through => :ratings
end
I am looking to find all Films that have not been rated by the specified user, smth like
class Film < ActiveRecord::Base
has_many :users, :through => :ratings
named_scope :not_rated_by_user, lambda { |user|
{:joins => :users, :conditions => ['? NOT IN users', user]}
}
end
Film.not_rated_by_user(User.first)
I am not that familiar with SQL so am not quite sure if this could be achieved in a named scope.
Many thanks
Yuriy
I suppose you have a ratings table, which is your join table. Right? So you need something like:
class User < ActiveRecord::Base
has_many :ratings
has_many :rated_films, :through => :ratings, :source => :film
end
class Film < ActiveRecord::Base
has_many :ratings
has_many :users, :through => :ratings
named_scope :not_rated_by_user, lambda { |user_id| {
:include => :ratings,
:conditions => ['? NOT IN (ratings.user_id)', user_id]
}}
end
class Rating < ActiveRecord::Base
belongs_to :film
belongs_to :user
end
And you can use
Film.not_rated_by_user(User.first.id)
Please let me know if it helped. I haven't tested!

Nested Has Many Through Plugin and Named Scopes

I have a User Model(:name, :password, :email), and Event model(:name, :etc) and Interest model (:name) [>all singular<]
Then I created two join tables -> UsersInterests and EventsInterests; each not containing a primary key and only comprised of the user_id/interest_id and event_id/interest_id respectively. [>plural<]
My Models Use the Nested Has Many Through Plugin
user.rb => has_many :users_interests
has_many :interests, :through => :users_interests
has_many :events_interests, :through => :interests
has_many :events, :through => :events_interests
event.rb => has_many :events_interests
has_many :interests, :through => :events_interests
has_many :users_interests, :through => :interests
has_many :users, :through => :users_interests
interest.rb => has_and_belongs_to_many :users
has_and_belongs_to_many :events
events_interests.rb => belongs_to :interests
belongs_to :events
users_interests.rb => belongs_to :users
belongs_to :interests
Whew..ok So I wanted to created a named_scope of that find all the events that share interest with a particular user. Here is some code someone helped me with.
named_scope :shares_interest_with_users, lambda {|user|
{ :joins => :users_interests,
:conditions => {:users_interests => {:user_id => user}}
}}
When i run from the controller =>
#user = User.find(1)
#events = Event.shares_interest_with_user(#user)
I get the error :
uninitialized constant Event::EventsInterest
Can anyone see what i messed up?
You must have named something wrong along the way. At a glance I'd say you have a file or class named incorrectly. Remember model names MUST always be singular, both in file and class names or else Rails won't make the connection. Another source of your problem is that arguments to belongs_to must also be singular. Even if you had got things right, the HABTM relationship in interests with users would have thrown an error when you ran the named scope.
I was able to solve your error with the following models.
user.rb
class User < ActiveRecord::Base
has_many :users_interests
has_many :interests, :through => :users_interests
has_many :events_interests, :through => :interests
has_many :events, :through => :events_interests
end
users_interest.rb
class UsersInterest < ActiveRecord::Base
belongs_to :user
belongs_to :interest
end
interest.rb
class Interest < ActiveRecord::Base
has_many :users,:through => :users_interests
has_many :users_interests
has_many :events_interests
has_many :events, :through => :events_interests
end
**events_interest.rb
class EventsInterest <ActiveRecord::Base
belongs_to :interest
belongs_to :event
end
event.rb
class Event <ActiveRecord::Base
has_many :events_interests
has_many :interests, :through => :events_interests
has_many :users_interests, :through => :interests
has_many :users, :through => :users_interests
named_scope :shares_interest_with_users, lambda {|user|
{ :joins => :users_interests,
:conditions => {:users_interests => {:user_id => user}}
}
}
end

has_many through self referential association

I want to (as an example) create a has_many association to all posts by friends of a person, something like has_many :remote_posts to give me something like person > friends > person > posts.
..here is how I would go about it
script/generate model post title:string person_id:integer
script/generate model friendship person_id:integer friend_id:integer
script/generate model person name:string
class Person < ActiveRecord::Base
has_many :posts
has_many :friendships, :foreign_key => 'friend_id'
has_many :people, :through => :friendships
has_many :remote_posts, :class_name => 'Post', :through => :people, :source => :posts
end
class Friendship < ActiveRecord::Base
belongs_to :person
#also has a 'friend_id' to see who the friendship is aimed at
end
class Post < ActiveRecord::Base
belongs_to :person
end
# generate some people and friends
{'frank' => ['bob','phil'], 'bob' => ['phil']}.each {|k,v|
v.each {|f|
Friendship.create(
:person_id => Person.find_or_create_by_name(f).id,
:friend_id => Person.find_or_create_by_name(k).id
)
}
}
# generate some posts
Person.all.each {|p|
p.posts.create({:title => "Post by #{p.name}"})
}
Now,
Person.first.friendships # ..works
Person.first.people # (friends) ..works
Person.first.posts # ..works
Person.first.remote_posts #....
...and I get this error..
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: people.person_id: SELECT "posts".* FROM "posts" INNER JOIN "people" ON "posts".person_id = "people".id WHERE (("people".person_id = 1))
Aside from the foreign key error - seems like the friendships association isn't coming into play at all. I was thinking that this might be because of the :source => :posts, since the posts association would come into it twice.
I could write some finder sql (and that is what I have working at the moment), though I'd sooner do it this way.
Any ideas of how to get this to work?
How about this:
In the FriendShip class, add:
has_many :posts, :through => :person
and in the Person class, change the remote_posts to:
has_many :remote_posts, :class_name => 'Post',
:through => :friendships, :source => :person
How about a nested has_many :through relationship. This seems to work for me:
class Friendship < ActiveRecord::Base
belongs_to :person
belongs_to :friend, :class_name => 'Person'
has_many :posts, :through => :friend, :source => :posts
end
class Person < ActiveRecord::Base
has_many :posts
has_many :friendships, :foreign_key => 'friend_id'
has_many :people, :through => :friendships
has_many :remote_posts, :through => :friendships, :source => :posts
end
Note: this requires this nested_has_many_through plugin. (Note: direct linking to github repos seems to be broken... but that repo is there despite the error message.)

Resources