有时我们的数据库查询操作条件多且比较复杂,这时我们可以将query refactor成model形式。
比如我们想通过用户找到他在某些课时下的某些任务的某些时间点完成的作业我们如何做呢?
先创建一个model,user_assignments_query.rb
创建一个class的时候,需要先定义参数。
class UserAssignmentsQuery
def initialize(user)
@user = user
end
end
下面我们就可以开始写方法了(由于比较复杂我们将select和joins单独写成方法)。
def call
user
.assignments.
.select(select)
.joins(join)
.order("due_on DESC")
end
rails有一系列的内建方法,可以让我们不必写原生的sql语句。这里我们使用了,select, joins(联表查询),order(顺序查询)。全部方法见 官方文档 。
接着定义我们想查询的内容。
def join
xxxxx
end
def select
xxxxx
end
此时需要声明变量user在外部是可以调用的。
attr_reader :user
注:attr_accessor,attr_reader,attr_writer 三者都可以用来声明变量供外部使用,区别是第一个是:可读可写,第二个是:只读,第三个是:只可写。
现在可以在外部调用了,比如在assignment的controller,用法如下:
@assignments = DueAssignmentsQuery.new(current_user).call
通过以上的方法我们找到了需要的作业(assignments)。
目前我们都是通过user这个参数来建立联系来找到我们想要的作业,如果有了多节课程,课程这个参数无法通过user找到,我们应该如何在原有的query model里快速引入课程呢?
先定义
class UserAssignmentsQuery
def initialize(user,course)
@user = user
@course = course
end
end
在call的方法中加入where查询语句:
def call
user
.assignments.where(course_id: course.id )
.select(select)
.joins(join)
.order("due_on DESC")
end
记得声明
attr_reader :course
在controller里就可以引用了
@assignments = DueAssignmentsQuery.new(current_user, course).call
注: 在定义joins和select方法时,我们使用了Arel(SQL AST管理器),可以参考这里。
所以需要定义如下:
def assignments
Assignment.arel_table
end