Active Record joins over 3 tables - ruby-on-rails

I am trying to find all terms and courses that apply to a contact.
Here are my models
class Register < ActiveRecord::Base
belongs_to :session
belongs_to :contact
end
class Session < ActiveRecord::Base
belongs_to :term
belongs_to :course
has_many :registers
has_many :contacts, :through => :registers
end
Here is the find a wrote
#data = Register.all :joins => {:session =>[:term, :course]} , :conditions => ["contact_id = ?", params[:id]]
When I run the query all I get is the session records not the terms or courses
Thanks
Alex

Try using :include instead of :joins. Something like:
#data = Register.all :include => {:session =>[:term, :course]} , :conditions => ["contact_id = ?", params[:id]]

Related

map method in many_to_many relationship

I have the following 3 models in my application:
class Submission < ActiveRecord::Base
has_many :linkedsubmissions
end
class Linkedsubmission < ActiveRecord::Base
belongs_to :submission
has_many :lnksubtypes
end
class Lnksubtype < ActiveRecord::Base
belongs_to :linkedsubmission
end
In the code below '#submission.linkedsubmissions.lnksubtypes' is incorrect.
#history = Audit.find(:all, :conditions => ["auditable_id IN (?)",#submission.linkedsubmissions.lnksubtypes.map{|b| b.LSU_ID} ])
I need to find all audits with 'auditable_id' in #submission.linkedsubmissions.lnksubtypes
You need to add the following has_many relationship to your Submission model.
class Submission < ActiveRecord::Base
has_many :linkedsubmissions
has_many :lnksubtypes, :through => :linkedsubmissions
end
Now, you'll be able to reformat your query like this
#history = Audit.find(:all, :conditions => ["auditable_id IN (?)", #submission.lnksubtypes.map(&:LSU_ID) ])
Audit.find(:all, :conditions => ["auditable_id IN (?)",#submission.linkedsubmissions.map{|b| b.lnksubtypes.map{&:LSU_OID) }.flatten ])
But there should be a better way to get those LSU_OID with sql only.
#history = Audit.where(:auditable_id => #submission.lnksubtypes.map(&:LSU_ID))
slightly shorter

return objects with no associated data

class Game < Event
has_many :statistics, :dependent => :destroy
...
end
class Statistic < ActiveRecord::Base
belongs_to :game
end
I want to make a named scope that only returns games that have no statistics.
Thanks
Try
named_scope :no_statistics, :include => :statistics, :conditions => ['statistics.id IS NULL']

Retrieving unique associated models from an array of another model

What is the recommended approach for finding multiple, unique associated models for a subset of another model? As an example, for a subset of users, determine unique artist models they have favorited.
One approach is to grab the users from the database, then iterate them all quering for favorites and building a unique array, but this seems rather inefficient and slow.
class User < ActiveRecord::Base
has_many :favorites
end
class Artist < ActiveRecord::Base
has_many :favorites
end
class Favorite < ActiveRecord::Base
belongs_to :user
belongs_to :artist
end
#users = User.find_by_age(26)
# then determine unique favorited artists for this subset of users.
The has_many association has a option called uniq for this requirement:
class User < ActiveRecord::Base
has_many :favorites
has_many :artists, :through => :favorites, :uniq => true
end
class Artist < ActiveRecord::Base
has_many :favorites
has_many :users, :through => :favorites, :uniq => true
end
class Favorite < ActiveRecord::Base
belongs_to :user
belongs_to :artist
end
Usage:
# if you are expecting an array of users, then use find_all instead of find_
#users = User.find_all_by_age(26, :include => :artists)
#users.each do |user|
user.artists # unique artists
end
Edit 1
I have updated the answer based on user's comment.
Solution 1- :group
Artist.all(:joins => :users, :group => :id,
:conditions => ["users.age = ?", 26])
Solution 2- SELECT DISTINCT
Artist.all(:joins => :users, :select => "DISTINCT artists.*",
:conditions => ["users.age = ?", 26]))

API for named scopes

I am having great difficulty reading the API for named scopes. Each "bid" has a user_id and an auction_id. I need a scope to return the auctions the user has bid on.
Auction
class Auction < ActiveRecord::Base
has_many :bids
named_scope :current, lambda {
{:conditions => ["scheduled_start < ?", 0.minutes.ago],
:order => 'scheduled_start asc'}
}
named_scope :scheduled, lambda {
{:conditions => ["scheduled_start > ?", 0.minutes.ago],
:order => 'scheduled_start asc'}
}
end
Bid
class Bid < ActiveRecord::Base
belongs_to :user
belongs_to :auction
validates_numericality_of :point, :on => :create
#
# how do I write a named scope to check if a user has bid on an auction?
end
you might wanna try a has many through association instead of a named scope.
class User < ActiveRecord::Base
has_many :bids
has_many :auctions, :through => :bids
end
Or do it the other way round
class Auction < ActiveRecord::Base
has_many :bids
has_many :users, :through => :bids
end
That way, you can simply write: #auction.users.include?(user)
That is not very clear to read, so lets improve it:
class Auction < ActiveRecord::Base
has_many :bids
has_many :bidders, :through => :bids, :source => :user
end
And now: #auction.bidders.include?(user)
Lastly, you can pass more than one param to a lamda, so (not the best example)
named_scope :for_apple_and_banana, lambda{|apple_id, banana_id| {:conditions => ["apple_id = ? AND banana_id = ?", apple_id, banana_id ]}}

Eager loading a named_scope from an association in Rails

Is there any way to eager load a named_scope from an association?
I have my Article model:
class Article < ActiveRecord::Base
has_many :comments
end
and my Comment model:
class Comment < ActiveRecord::Base
belongs_to :article
named_scope :approved, :conditions => { :approved => true }
named_scope :unapproved, :conditions => { :approved => false }
end
I could eager load all comments for an article with:
#article = Article.find(params[:id], :include => :comments)
How can I do the same, but only for approved comments?
It is not built-in to rails at this time, but Ryan Daigle created a plugin called utility_scopes that adds a with() scope so you can do:
Article.approved.with(:comments)
Blog Post: http://ryandaigle.com/articles/2008/8/20/named-scope-it-s-not-just-for-conditions-ya-know
Github Repo: http://github.com/yfactorial/utility_scopes
[Updated per comment]
My bad. I didn't read well enough. I don't think there's anything that will let you call on an association named_scope like that. The closest thing I can think of would be creating a named_scope on Article:
class Article < ActiveRecord::Base
named_scope :with_approved_comments, {:include => :comments, :conditions => ['comments.approved = ?', true]}
end
Hope this helps.
The other answer didn't work for me since I have to load many associations and associations of those associations on some models. I found I had two options, change the association to have conditions and thus make an association for each scope I wanted or turn them into methods on the class that had the has_many association. I needed to do something along the lines of:
#newspaper = Newspaper.find params[:id], :include => {
:articles => {
:author => true,
:source => true
}
}
So in my example I changed:
class Newspaper < ActiveRecord::Base
has_many :articles
end
class Article
belongs_to :newspaper
belongs_to :author
has_one :source
named_scope :private, :conditions => { :private => true }
named_scope :public, :conditions => { :private => false }
end
to:
class Newspaper < ActiveRecord::Base
has_many :articles
def articles_public
articles.reject &:private
end
def articles_private
articles.select &:private
end
end
class Article
belongs_to :newspaper
belongs_to :author
has_one :source
end
I found this way to be preferable since I can now eager load articles when finding a newspaper and just change all article.private to article_private. Had I created two associations like:
has_many :articles_private, :class_name => 'Article', :conditions {:private => true}
has_many :articles_public, :class_name => 'Article', :conditions {:private => false}
I would have to eager load them both in cases where I needed all associated articles.

Resources