有几件事情我会根据您自己的回答中的代码更改/推荐:
- 移动搜索查询到示波器上的每个模型类
- 身高AREL通过原始SQL编写查询(here's a quick guide)
- 加强轨查询模型
的变化我时使用某种or
时建议将使您能够做这样的事情:
search = search_params
tasks = Tasks.all
tasks = tasks.or.user_handle_matches(handle) if (handle = search[:user].presence)
tasks = tasks.or.client_name_matches(name) if (name = search[:client].presence)
tasks = tasks.or.project_name_matches(name) if (name = search[:project].presence)
tasks = tasks.or.activity_name_matches(name) if (name = search[:activity].presence)
@tasks = tasks.uniq
首先,将您的每个查询转换为模型上的范围。这使您以后重用你的范围:
class User
scope :handle_matches, ->(handle) {
where(arel_table[:handle].matches("%#{handle}%"))
}
end
class Client
scope :name_matches, ->(name) {
where(arel_table[:name].matches("%#{name}%"))
}
end
class Project
scope :name_matches, ->(name) {
where(arel_table[:name].matches("%#{name}%"))
}
end
class Activity
scope :name_matches, ->(name) {
where(arel_table[:name].matches("%#{name}%"))
}
end
然后,您可以使用您Task
模型中,这些范围,以便更好的搜索能力。对于每一个上Task
作用域的我们正在做一个连接(内部连接)上的关系,并使用范围限制所加入的结果:
class Task
belongs_to :assignment
has_one :user, :through => :assignment
has_one :activity, :through => :assignment
has_one :project, :through => :activity
scope :user_handle_matches, ->(handle) {
joins(:user).merge(User.handle_matches(handle))
}
scope :client_name_matches, ->(name) {
joins(:client).merge(Client.name_matches(name))
}
scope :activity_name_matches, ->(name) {
joins(:activity).merge(Activity.name_matches(name))
}
scope :project_name_matches, ->(name) {
joins(:project).merge(Project.name_matches(name))
}
end
的最后一个问题解决的是or
荷兰国际集团的结果。 Rails 4及以下版本并没有真正允许这种开箱即用,但有宝石和代码允许这个功能。
我经常在this GitHub gist的代码中包含代码,以允许or
作用域。该代码允许您执行诸如Person.where(name: 'John').or.where(name: 'Jane')
之类的操作。
此SO question中讨论了许多其他选项。
如果你不想包含随机代码和宝石,另一个选择是将一个ID数组传递给where子句。这会生成一个类似于SELECT * FROM tasks WHERE id IN (1, 4, 5, ...)
的查询:
tasks = []
tasks << Tasks.user_handle_matches(handle) if (handle = search[:user].presence)
tasks << tasks.or.client_name_matches(name) if (name = search[:client].presence)
tasks << tasks.or.project_name_matches(name) if (name = search[:project].presence)
tasks << tasks.or.activity_name_matches(name) if (name = search[:activity].presence)
# get the matching id's for each query defined above
# this is the catch, each call to `pluck` is another hit of the db
task_ids = tasks.collect {|query| query.pluck(:id) }
tasks_ids.uniq!
@tasks = Tasks.where(id: tasks_ids)
嘿,我不明白你是否指'继承'或'协会'由'<'操作符..请。我认为重写会很好 – illusionist
编辑,我的意思是关联(认为它们被称为rails中的关系),例如: 项目具有外键client_id 项目模型具有belongs_to关联 客户端模型具有has_many关联 –