如何通过以下方式获取arel组件:
queries = []
queries << MyModel.some_scope.get_the_arel_component
queries << MyModel.some_scope_with_param("Dave").get_the_arel_component
queries << MyModel.where(:something => 'blah').get_the_arel_component
queries << MyModel.some_scope_with_join_and_merge.get_arel_component
# etc ... (may be any number of queries)
# join each query with OR
combined_query = nil
queries.each do |query|
combined_query ||= query
combined_query = combined_query.or(q)
end
# run the query so it just works
MyModel.where(combined_query)
我遇到了类似问题的可接受答案的一些问题.
可以说我有一个这样的课程:
class Patient
has_one :account
scope :older_than, ->(date) { where(arel_table[:dob].lt(date)) }
scope :with_gender, ->(gender) { where(:gender => gender) }
scope :with_name_like, ->(name) { where("lower(name) LIKE ?", name.downcase) }
scope :in_arrears, -> { joins(:account).merge( Account.in_arrears ) }
end
目标是将任何范围或where子句与OR组合.
One way将是Patient.with_name_like(“Susan”)| Patient.with_name_like( “戴夫”).这似乎分别运行每个单独的查询,而不是组合成单个查询.我已经排除了这个解决方案.
# this fails because `where_values` for the `with_name_like` scope returns a string
sues = Patient.with_name_like("Susan").where_values.reduce(:and)
daves = Patient.with_name_like("Dave").where_values.reduce(:and)
Patient.where(sues.or(daves))
# this works as `where_values` returns an `Arel::Nodes::Equality` object
ages = Patient.older_than(7.years.ago).where_values.reduce(:and)
males = Patients.with_gender('M').where_values.reduce(:and)
Patient.where(ages.or(males))
# this fails as `in_arrears` scope requires a joins
of_age = Patient.older_than(18.years.ago).where_values.reduce(:and)
arrears = Patients.in_arrears.where_values.reduce(:and)
Patient.where(of_age.or(arrears)) # doesn't work as no join on accounts
Patient.join(:account).where(of_age.or(arrears)) # does work as we have our join
总而言之,ORing查询的问题出现在传递字符串或查询需要连接的位置.
我很确定将传递给它的任何东西转换成一个arel对象,只需要访问正确的部分并以正确的方式重新组合它们.我还没有设法解决它.
优选地,答案将仅使用ActiveRecord和AREL而不是第三方库.
最佳答案 由于您可以使用第三方库,
Ransack怎么样?
它具有非常强大的实现,允许各种和/或条件组合,并且也适用于相关模型.
对于像你这样的用例,我希望用户能够从中选择并运行它们或它们的组合,我会使用ransack开箱即用的实现,然后在视图级别,我使用javascript插入隐藏字段,其值将导致结构化params散列搜索在控制器中期待.
使用ransack助手在视图中定义所有范围都很简单.您的代码应如下所示:
调节器
def index
@q = Patient.search(params[:q])
@patients = @q.result(distinct: true)
end
视图
<%= search_form_for @q do |f| %>
<%= f.label :older_than %>
<%= f.date_field :dob_lt %>
<%= f.label :with_gender %>
<%= f.text_field :gender_eq %>
<%= f.label :with_name_like %>
<%= f.text_field :name_cont %>
<%= f.label :in_arrears_exceeding %>
<%= f.text_field :accounts_total_due_gte %>
<%= f.submit %>
<% end %>
此外,如果您想要更多地控制anding和oring,请使用ransack查看complex search form builder示例.