Elegant Advanced Rails Queries
I'm having trouble wrapping my head around more advanced Rails query methods. In this case, I have three tables: Users, Friendships, and Events.
I have set it up as follows in the models for each
User-> :has_many => :friendships, :has_many => :items
Friendship-> :belongs_to => :user
Event-> belongs_to => :user
Friendships are simply two columns: "user_id" and "friend_id" so each new friendship would create two new rows.
Here is the query I'm using to find "the first four events belonging to a friend of the current_user that has a start_date that is later than right now."
find_by_sql(["SELECT DISTINCT e.id
FROM events e
WHERE e.start_date > ?
AND e.user_id IN(
SELECT f.user_id
FROM friendships f
WHERE f.friend_id = ?)
LIMIT 0,4", Time.zone.now,current_user.id])
What is the true and elegant way to do something like this in Rails? I have a fe开发者_JAVA百科eling this is also extremely inefficient...
You should be able to use :join
and :conditions
time_range = (Time.now.midnight - 4.days)..Time.now.midnight
Event.all :joins => :friendships, :conditions =>
{'start_date' => time_range, 'friendships.friend_id' => current_user.id}, :limit => 4
I haven't really done a whole lot of complex querying like this, but I pieced this together from the examples here: http://guides.rubyonrails.org/active_record_querying.html
Edit: You may have to add to Event:
has_many :friends, :through => :friendships
Edit2: Looks like you'll have to actually use a nested join:
Event.all :joins => {:user => :friendships }, :conditions => {'start_date' => time_range, 'friendships.friend_id' => current_user.id }
Here is the model code that I used:
class User < ActiveRecord::Base
has_many :events, :foreign_key => "user_id"
has_many :friendships
has_many :friends, :through => :friendships, :source => :user, :uniq => true
end
class Event < ActiveRecord::Base
belongs_to :user
has_many :friendships, :through => :user
end
class Friendship < ActiveRecord::Base
belongs_to :user
end
And, some example output if that may be helpful at all:
>> Event.all :joins => {:user => :friendships }, :conditions => {'happens_on' => time_range, 'friendships.user_id' => 1 }
Event.all :joins => {:user => :friendships }, :conditions => {'happens_on' => time_range, 'friendships.user_id' => 1 }
=> [#<Event id: 1, happens_on: "2010-08-06 00:42:37", title: "Jims party", description: "Happy Birthday", created_at: "2010-08-03 00:42:37", updated_at: "2010-08-03 00:42:37", user_id: 1>]
>> jim = User.find(1)
jim = User.find(1)
=> #<User id: 1, name: "Jim", bio: "Loves Rails", age: 30, created_at: "2010-08-03 00:30:51", updated_at: "2010-08-03 00:30:51">
>> crystal = User.find(2)
crystal = User.find(2)
=> #<User id: 2, name: "Crystal", bio: "Loves writing", age: 26, created_at: "2010-08-03 00:31:14", updated_at: "2010-08-03 00:31:14">
>> jim.events
jim.events
=> [#<Event id: 1, happens_on: "2010-08-06 00:42:37", title: "Jims party", description: "Happy Birthday", created_at: "2010-08-03 00:42:37", updated_at: "2010-08-03 00:42:37", user_id: 1>]
>> event1 = jim.events[0]
event1 = jim.events[0]
=> #<Event id: 1, happens_on: "2010-08-06 00:42:37", title: "Jims party", description: "Happy Birthday", created_at: "2010-08-03 00:42:37", updated_at: "2010-08-03 00:42:37", user_id: 1>
>> event1.user
event1.user
=> #<User id: 1, name: "Jim", bio: "Loves Rails", age: 30, created_at: "2010-08-03 00:30:51", updated_at: "2010-08-03 00:30:51">
>> event1.friendships
event1.friendships
=> [#<Friendship user_id: 1, friend_id: nil, created_at: "2010-08-03 00:57:31", updated_at: "2010-08-03 00:57:31">]
>>
精彩评论