我有模型club
和course
,其中一个课程属于一个俱乐部,俱乐部有很多课程。
当我加载一个俱乐部时,我也想加载它的相关课程,但我只想加载满足条件测试的那些(approved? == true
)。
如果我直接使用这些课程,那么如何做到这一点很简单:
@courses = Course.find( :all, :conditions => {:approved => true } )
但我想将此作为声明的一部分:
@club = Club.find(params[:id])
因为我的观点是以这种方式构建的,我宁愿不必改变所有观点。
谢谢!
答案 0 :(得分:2)
如果您只考虑俱乐部的课程,如果它已被批准,您可以
class Club < ActiveRecord::Base
has_many :courses, :conditions => {:approved => true}
end
并在您的控制器中
@club = Club.find(params[:id], :include => :courses)
现在,我不知道我是否误解了你,但你说“你的观点是这样构建的”。你的意思是你的控制器?因为如果你的观点中有这样的逻辑...... 每当有人这样做时,DHH会杀死一只小猫。
答案 1 :(得分:1)
您可以使用default_scope
:
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
现在你可以这样做:
@club = Club.find(1) # this will eager load approved courses.
<强>参考:强>
Article关于default_scope
。
注1
我更改了courses
课程中的Club
个关联,以选择已批准的课程。理论上,这不是必需的,因为Course
类具有默认范围。但是,看起来默认范围不适用于急切加载的查询。
注2
我个人不会急切地通过Course
加载default_scope
个对象。通过default_scope执行此操作可为您提供所需的不显眼的解决方案。
我会在include
调用中添加find
子句,以便仅在需要时加载Course
个对象。
注3
@Ryan Bigg:
Ryan Bates在他的screen cast期间谈到了默认范围。他给出了使用默认范围排除已删除记录的示例,即
default_scope :conditions => "delete_at IS NULL"
我认为这个用例类似。当我发现问题时,课程模型的主要操作是在已批准的记录上,default_scope
使用conditions
选项确保这一点。要覆盖default_scope,用户可以使用with_exclusive_scope
方法。
Club.with_exclusive_scope{find(1)}
答案 2 :(得分:0)
最终的解决方案来自于答案的组合,但两者都没有完全解决。
当前解决方案:
我在course
模型中使用了几个命名范围来实现我想要的功能,同时尽可能保持我的视图通用(能够干掉代码是必须的)。
所以course
模型看起来有点像这样:
class Course < ActiveRecord::Base
belongs_to :club
named_scope :have_approval, :conditions => { :approved => true }
named_scope :need_approval, :conditions => { :approved => false }
end
要收集所有经过批准的课程,就像以下一样简单:
@approved_courses = Course.have_approval
或者在使用club
时,在俱乐部获得认可的课程非常简单:
@club = Club.find(:first)
@approved_courses_in_club = @club.courses.have_approval
命名范围是男人!