我有一个要求,用户可以输入一个搜索框,Rails api应该搜索任何客户字段以寻找可能的匹配,所以我开始这样做,并意识到这不是一个很好的解决方案,似乎很重复所有5个领域:
scope :filter, -> (term) { where(
"lower(customers.name) LIKE ? OR
lower(customers.email) LIKE ? OR
lower(customers.business_name) LIKE ? OR
lower(customers.phone) LIKE ? OR
lower(customers.doc_id) LIKE ? OR",
"%#{term.downcase}%", "%{term.downcase}%", "%#{term.downcase}%",
"%#{term.downcase}%", "%#{term.downcase}%"
) }
所以我了解了Arel并尝试了这个:
customers = Customer.arel_table
scope :filter, -> (term) { Customer.where(
customers[:name].matches("%#{term.downcase}%")).
or(customers[:email].matches("%#{term.downcase}%")).
or(customers[:phone].matches("%#{term.downcase}%")).
or(customers[:business_name].matches("%#{term.downcase}%").
or(customers[:doc_id].matches("%#{term.downcase}%"))
) }
但这也是重复的。
有没有办法简单地使用任何一个版本?我想也许是为了Arel我能做到这一点:
scope :filter, -> (term) { Customer.where(
customers[:name, :email, :phone, :business_name, :doc_id].matches("%#{term.downcase}%")
) }
更新
道歉,但我忘了提 - 我试图保持这个简单! - 如果有一个更简单的解决方案,它仍然需要是一个可链接的范围,因为我在其他范围的链中使用此过滤器,如控制器中的这样:
if params[:filter].present?
@cards = current_api_user.account.cards.new_card(:false).search(params.slice(:filter))
else ...
其中'search'是一个关注点,它只是将过滤器参数键/值对发送到模型中的作用域。例如,这里是卡模型范围(您可以看到它的过滤器范围然后调用filter_customer范围,然后调用Customer.filter,这是问题所在的范围)。这可能看起来很复杂,但这意味着我对所有相关模型的所有范围都具有完全可组合性:
scope :new_card, -> value { where(is_new: value) }
scope :filter_template, -> (term) { Card.where(template_id: Template.filter(term)) }
scope :filter_customer, -> (term) { Card.where(customer_id: Customer.filter(term)) }
scope :filter, -> (term) { Card.filter_customer(term).or(Card.filter_template(term)) }
答案 0 :(得分:1)
选项1:
使用多个 ORs
构建条件字符串fields = ["name", "email", "phone", "business_name", "doc_id"]
filter = fields.map { |field| "lower(#{field}) LIKE '#{term.downcase}'" }.join(' OR ')
@customers = Customer.where(filter)
选项2:
使用简单条件连接搜索
fields = ["name", "email", "phone", "business_name", "doc_id"]
@customers = []
fields.each do |field|
filter = "lower(#{field}) LIKE '#{term.downcase}'"
@customers.concat(Customer.where(filter))
end
<强>范围:强>
只需稍加更改即可将第一种方法用作范围
班级客户
scope :filter_customer, -> (term) { Customer.where(Customer.build_filter(term)) }
def self.build_filter term
fields = ["name", "email", "phone", "business_name", "doc_id"]
filter = fields.map { |field| "lower(#{field}) LIKE '#{term.downcase}'" }.join(' OR ')
end
备注:您的第一篇帖子基于客户,我根据此模型制作了所有代码。更新后,答案需要在卡片中使用一些更改,但它应该是微不足道的。