Reputation: 2902
I have models club
and course
where a course belongs to a club and and a club has many courses.
When I load a club, I also want to load it's associated courses, but I only want to load those that meet a conditional test (approved? == true
).
It is straightforward how to do this if I were working directly with the courses:
@courses = Course.find( :all, :conditions => {:approved => true } )
But I would like to do this as part of the statement:
@club = Club.find(params[:id])
because my views are built that way and I would rather not have to change all of them.
Thanks!
Upvotes: 2
Views: 966
Reputation: 2902
The ultimate solution came from a combination of answers, but neither quite got all the way.
Current solution:
I utilize a couple of named scopes in the course
model to achieve the functionality I wanted while keeping my views as universal as possible (being able to dry up code is a must).
So the course
model looks a bit like this:
class Course < ActiveRecord::Base
belongs_to :club
named_scope :have_approval, :conditions => { :approved => true }
named_scope :need_approval, :conditions => { :approved => false }
end
And to gather all approved courses it is as easy as:
@approved_courses = Course.have_approval
Or when working with a club
, getting the approved courses in a club is as easy as:
@club = Club.find(:first)
@approved_courses_in_club = @club.courses.have_approval
Named scope is the man!
Upvotes: 0
Reputation: 64363
You can use default_scope
for this:
class Club < ActiveRecord::Base
has_many :courses, conditions => {:approved => true}
default_scope :include => :courses
end
class Course < ActiveRecord::Base
default_scope :conditions => {:approved => true}
end
Now you can do this:
@club = Club.find(1) # this will eager load approved courses.
Reference:
Article about default_scope
.
Note 1
I changed the courses
assocation in Club
class to select approved courses. In theory, this is not required as the Course
class has a default scope. But, it looks like default scope is not applied for eager loaded queries.
Note 2
I personally would not eager load the Course
objects through default_scope
. Doing it through a default_scope gives you an unobtrusive solution as desired by you.
I would add the include
clause to the find
call to eager load the Course
objects only when it's required.
Note 3
@Ryan Bigg:
Ryan Bates talks about default scopes half way through this his screen cast. He gives an example of using the default scopes to exclude deleted records, i.e.
default_scope :conditions => "delete_at IS NULL"
I consider this use case to be similar. As I perceive the problem, primary operations on the Course model is on approved records and default_scope
with the conditions
option ensures that. To override the default_scope, user can use the with_exclusive_scope
method.
Club.with_exclusive_scope{find(1)}
Upvotes: 1
Reputation: 18043
If you only consider a club's course if it has been approved, you can do
class Club < ActiveRecord::Base
has_many :courses, :conditions => {:approved => true}
end
and in your controller
@club = Club.find(params[:id], :include => :courses)
Now, I don't know if I misunderstood you, but you said "your views are built that way". Do you mean your controllers? Because if you have such logic in your views... DHH kills a kitten every time someone does that.
Upvotes: 2