سؤال

I found a few similar questions while searching here, but when I tried to add unless to the solutions I found, things started to break...

Here's what I have that works:

Controller:

    @metrics = Metric.where("current_ratio > ?", @screen.current_ratio_min) unless @screen.current_ratio_min.nil?

Once I add another .where line (of which I need to add many),

    @metrics = Metric.where("current_ratio > ?", @screen.current_ratio_min) unless @screen.current_ratio_min.nil?
    .where("current_ratio < ?", @screen.current_ratio_max) unless @screen.current_ratio_max.nil?

I get an error:

undefined method `where' for false:FalseClass

I'm assuming this is because the first unless is ending my query. How do I apply an unless just to each individual condition? If that is, in fact, the problem :\

Thanks in advance!

هل كانت مفيدة؟

المحلول

@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
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top