Multiple query conditions in Rails - if they exist.

别说谁变了你拦得住时间么 提交于 2019-12-05 10:50:33
@metrics = Metric.all
@metrics = @metrics.where('current_ratio > ?', @screen.current_ration_min) if @screen.current_ratio_min.present?
@metrics = @metrics.where('other_value > ?', @screen.other_value) if @screen.other_value.present?

This is the best way I can think of without programmatically building a where clause string which can be risky for SQL injection.

Keep adding as many conditions as you want. Notable, use if something.present? instead of your unless something.nil?

Also, the Metric.all might not be ideal, but whatever you need to get all records to start with.

If you want clean code, use scope

In metric.rb

  scope :current_ratio_min, lambda {|current_ratio_min|
    current_ratio_min.present? ? where('current_ratio > ?', current_ration_min) : where()}
  scope :current_ratio_max, lambda {|current_ratio_max|
    current_ratio_max.present? ? where('current_ratio > ?', current_ratio_max) : where()}

Your query :

@metrics = Metric.current_ratio_min(@screen.current_ratio_min).current_ratio_max(@screen.current_ratio_max)`

Write the following method in your Array class

 class Array
  def add_condition!(condition, conjunction = 'AND')
   if String === condition
     add_condition!([condition])
   elsif Hash === condition
     add_condition!([condition.keys.map { |attr| "#{attr}=?" }.join(' AND ')] + condition.values)
   elsif Array === condition
     unless condition.empty?
       self[0] = "(#{self[0]}) #{conjunction} (#{condition.shift})" unless empty?
       self.push(*condition)
     end
   else
    raise "don't know how to handle this condition type"
   end
  self
 end
end

You can build your conditions for ActiveRecord where or find with conditions as follows

 conditions = []
 conditions.add_condition!(["current_ratio > ?", @screen.current_ratio_min]) unless @screen.current_ratio_min.nil?  
 conditions.add_condition!(["current_ratio < ?", @screen.current_ratio_max]) unless @screen.current_ratio_max.nil?
 @metrics = Metric.where(conditions)

This will be helpful in building multiple conditions with AND/OR combinations

What about something like this?

if !@screen.current_ratio_min.nil? && !@screen.current_ratio_max.nil?
  @metrics = Metric.where("current_ratio > ?", @screen.current_ratio_min).where("current_ratio < ?", @screen.current_ratio_max)
elsif @screen.current_ratio_min.nil? && !@screen.current_ratio_max.nil?
  @metrics = Metric.where("current_ratio < ?", @screen.current_ratio_max)
elsif !@screen.current_ratio_min.nil? && @screen.current_ratio_max.nil?
  @metrics = Metric.where("current_ratio > ?", @screen.current_ratio_min)
else
  @metrics = Metric.all
end

Try with the following code

if @screen.current_ratio_min and @screen.current_ratio_max
  @metrics = Metric.where("current_ratio > ? and current_ratio < ?", @screen.current_ratio_min, @screen.current_ratio_max)
else
 unless @screen.current_ratio_min.blank?
   @metrics = Metric.where("current_ratio > ?", @screen.current_ratio_min)
 else
   unless @screen.current_ratio_max.blank?
     @metrics = Metric.where("current_ratio < ?", @screen.current_ratio_max)
   else
     @metrics = Metric.all
   end
 end 
end
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!