Reputation: 4013
I am having the following params in my url.
Consider url../price=0-1000_2000-5001
I have converted the above price params as
pri = [["0", "1000"], ["2000", "5001"]] #This is not limited to only two
Now how can I query as following in rails
select * from product where price betweeen 0 and 1000 and price between 2000 and 5001 and so on
I found below query in rails
Product.where(price: pri[0].first..pri[0].last)
But how can I find for multiple ranges.
Edit-1
@posts = Post.where(price: price_range) #This works fine now
[1001..5000, 10000..0]
Here 10000..0 Indicate price greater than 10000
But my query executed as
select * from posts where price between 1001 and 5000 or price between 10000 and 0
But the query should be like this
select * from posts where price between 1001 and 5000 or price > 10000
checkbox1 = value 0-1000
checkbox2 = value 1001-5000
checkbox3 = value 5001-10000
checkbox4 = value 10001-15000
checkbox5 = value 15001-0(This indicates price > 15001 )
Upvotes: 0
Views: 2419
Reputation: 2636
There is a much simpler solution. This is all you need:
price_ranges = [0..1000, 2000..5001]
products = Product.where(price: price_ranges)
Here's console output, with a similar query, showing the SQL that's generated:
>> ranges
=> [-Infinity..1000000, 10000000..19999999]
>> Company.where(total_funding_amount: ranges)
Company Load (0.8ms) SELECT "companies".* FROM "companies" WHERE ((("companies"."total_funding_amount" <= 1000000 OR "companies"."total_funding_amount" BETWEEN 10000000 AND 19999999) OR 1=0))
You can even use a mix of ranges and integers. See the discussion in this Rails issue from 2011 if you're curious.
Upvotes: 0
Reputation: 18037
Here's a solution that uses Range objects instead of a manual representation of ranges. And ARel instead of hardcoded SQL. It's generally good practice to use ARel over SQL strings so that ARel can handle formatting the SQL for whatever database adapter you may be using now and in the future.
price_ranges = [0..1000, 2000..5001]
# Set up the base relation
products = Product.where(price: price_ranges.pop)
# iterate on any remaining prices
products = price_ranges.inject(products) do |rel, price_range|
# Use ARel's `or` method to chain on to the relation
rel.or(Product.arel_table[:price].in(price_range))
end if price_ranges.any?
If you need to, you can first convert your price arrays into ranges like this:
price_ranges = prices.map { |ar| Range.new(Integer(ar.first), Integer(ar.second)) }
Update:
If you want to continue to use ranges but allow for one value to be anything greater than some number you can use Float::INFINITY
to accomplish this:
price_ranges = [1001..5000, 10000..Float::INFINITY]
# For example:
Product.where(price: 10000..Float::INFINITY).to_sql
# => SELECT "products".* FROM "products" WHERE ("products"."id" >= 10000)
Of course, this probably means you'll need to conditionally set the 2nd value to Float::INFINITY
when building up the array of ranges.
Upvotes: 1
Reputation: 460
Instead of using AND between two range use OR this must return some products
Product.where("price between ? and ? or price between ? and ?", pri[0].first, pri[0].last, pri[1].first, pri[1].last)
Edited for dynamic array lenght
arr = [["0", "100"], ["100", "200"]]
query_string = ""
arr.each {|a| query_string << (arr.last == a ? " price between #{a.first} and #{a.last}" : "price between #{a.first} and #{a.last} or") }
Product.where(query_string)
finds the expected records.
Upvotes: 0
Reputation: 11967
Product.where("(price >= ? AND price <= ?) OR (price >= ? AND price <= ?)", pri[0].first, pri[0].last, pri[1].first, pri[1].last)
Something like this should work, i didn't test this code though.
Upvotes: 0