我正在努力找出有效链接我的协会的正确方法。我基本上有以下层次结构:
学校>课程>讲座>附件
用户可以拥有其中的许多内容,这表明他们不拥有这些内容,而是表示他们已注册或有权访问这些内容。然后我们使用cancan进行授权。
我的挑战是,用户可以在学校注册,然后分别注册每门课程,或者他们可以注册“学校范围”的套餐,让他们可以访问所有课程。在添加后者之前,我们的用户模型包括以下内容:
belongs_to :school
has_many :active_sales, -> { where active: true }, class_name: "Sale"
has_many :courses, through: :active_sales, source: :sale
has_many :lectures, through: :courses
has_many :attachments, through: :lectures
在尝试添加全校范围内的销售(销售是多态的“可登记”课程和学校)时,我无法弄清楚如何正确地将关联链接在一起。基本上,它就像链条叉子然后重新加入。如果我可以做像
那样的事情会很好has_many :courses, through: :active_sales, source: :sale, -> {where (id: active_sale.enrollable_id && active_sale.enrollable_type: 'Course') || (school_id: active_sale.enrollable_id && active_sale.enrollable_type: 'School') }
...但我很确定where方法没有关联,也不清楚是否需要将条件串联起来。我试过搞乱关联扩展,但也遇到了麻烦。
有最好的方法吗?
答案 0 :(得分:1)
Vanilla AtiveRecord在复杂查询的情况下很难使用,除非您自己编写SQL语句。执行OR语句的唯一方法是将整个SQL语句编写为字符串,并将其用作where子句。
但您也可以使用Arel来塑造您的查询。
在您的情况下,我认为如果您为active_sales_courses或类方法创建了一个范围,而不是尝试将所有内容放在has_many
语句中,它将使您的代码更清晰。
def self.active_sales_courses
courses = Arel::Table.new(:courses)
active_sales = Arel::Table.new(:active_sales)
query = courses.joins(active_sales).on(courses[:id].eq(active_sales[:enrollable_id])).
where((courses[:id].eq(active_sales[:enrollable_id]).
and(active_sales[:enrollable_type].eq('Course'))).
or(courses[:school_id].eq(active_sales[:enrollable_id]).
and(active_sales[:enrollable_type].eq('School'))))
query.to_sql
end
我无法保证此代码有效,因为我无法对其进行测试,但它是作为指示提供的。