Rails:有条件地加载关联

时间:2010-08-08 00:59:37

标签: ruby-on-rails ruby activerecord associations

我有模型clubcourse,其中一个课程属于一个俱乐部,俱乐部有很多课程。

当我加载一个俱乐部时,我也想加载它的相关课程,但我只想加载满足条件测试的那些(approved? == true)。

如果我直接使用这些课程,那么如何做到这一点很简单:

@courses = Course.find( :all, :conditions => {:approved => true } )

但我想将此作为声明的一部分:

@club = Club.find(params[:id])

因为我的观点是以这种方式构建的,我宁愿不必改变所有观点。

谢谢!

3 个答案:

答案 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

命名范围是男人!