【问题标题】:Arel AND clause and Empty conditionArel AND 子句和空条件
【发布时间】:2015-06-20 07:00:34
【问题描述】:

考虑以下代码片段:

def sql
  billing_requests
  .project(billing_requests[Arel.star])
  .where(
    filter_by_day
      .and(filter_by_merchant)
      .and(filter_by_operator_name)
  )
  .to_sql
end

def filter_by_day
  billing_requests[:created_at].gteq(@start_date).and(
    billing_requests[:created_at].lteq(@end_date)
  )
end

def filter_by_operator_name
  unless @operator_name.blank?
    return billing_requests[:operator_name].eq(@operator_name)
  end
end

def filter_by_merchant
  unless @merchant_id.blank?
    return billing_requests[:merchant_id].eq(@merchant_id)
  end
end

private

def billing_requests
  @table ||= Arel::Table.new(:billing_requests)
end

在方法filter_by_merchant中,当商户ID为空时,Arel必须返回什么值才能忽略AND子句的影响? 另外,有没有更好的方法来处理这种情况?

【问题讨论】:

  • 据我所知,没有任何参数可以传递给 and 使其什么也不做。
  • 你试过“return billing_requests.all”吗?

标签: ruby-on-rails ruby activerecord arel


【解决方案1】:

你应该返回 true。当您运行 .and(true) 时,它最终会在 sql 中转换为“AND 1”。

def filter_by_merchant
  return true if @merchant_id.blank?

  billing_requests[:merchant_id].eq(@merchant_id)
end

【讨论】:

  • 就我而言,我必须返回Arel.sql('TRUE'),否则会引发unsupported: TrueClass 错误。
【解决方案2】:

似乎不可能给and 提供任何导致它什么都不做的参数。但是,您可以有条件地致电and

def sql
  billing_requests
  .project(billing_requests[Arel.star])
  .where(filter_by_day_and_merchant_and_operator_name)
  .to_sql
end

def filter_by_day
  billing_requests[:created_at].gteq(@start_date).and(
    billing_requests[:created_at].lteq(@end_date)
  )
end

def filter_by_merchant
  billing_requests[:merchant_id].eq(@merchant_id)
end

def filter_by_operator_name
  billing_requests[:operator_name].eq(@operator_name)
end

def filter_by_day_and_merchant
  if @merchant_id.blank?
    filter_by_day
  else
    filter_by_day.and(filter_by_merchant)
  end
end

def filter_by_day_and_merchant_and_operator_name
  if @operator_name.blank?
    filter_by_day_and_merchant
  else
    filter_by_day_and_merchant.and(filter_by_operator_name)
  end
end  

private

def billing_requests
  @table ||= Arel::Table.new(:billing_requests)
end

它非常笨重,但它可以完成工作。

【讨论】:

  • @wally_altman,我按照你提到的进行了尝试。但以下是我得到的。 gist.github.com/midhunkrishna/985523a2041305eb817b
  • 嘿,你是对的,它不起作用!我已经更新了我的解决方案。
  • @wally_altman,这不能回答问题。此外,如果我还必须通过另一个参数进行过滤,比如“operator_name”,该怎么办?我已经更新了问题。
  • 更新了我的答案。如果您有更多参数可供过滤,您可以扩展此解决方案。
  • @wally_altman,这不是一个可维护的解决方案。如果我有相当复杂的查询,我可以“扩展”它以使其非常难以阅读。
【解决方案3】:
def sql
  billing_requests
  .project(billing_requests[Arel.star])
  .where(conditions)
  .to_sql
end

def conditions
  ret = filter_by_day
  ret = ret.and(filter_by_merchant) unless @merchant_id.blank?
  ret = ret.and(filter_by_operator_name) unless @operator_name.blank?
  ret
end

def filter_by_day
  billing_requests[:created_at].gteq(@start_date).and(
    billing_requests[:created_at].lteq(@end_date)
  )
end

def filter_by_operator_name
  billing_requests[:operator_name].eq(@operator_name)
end

def filter_by_merchant
   billing_requests[:merchant_id].eq(@merchant_id)
end

private

def billing_requests
  @table ||= Arel::Table.new(:billing_requests)
end

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-01-06
    • 2011-09-07
    • 2013-12-23
    • 2021-10-28
    • 1970-01-01
    • 1970-01-01
    • 2017-06-11
    • 1970-01-01
    相关资源
    最近更新 更多