0

i have a page with filters and it doesn't work properly, it works if all filters are set. But if category filter isn't set and the other two are set it wont work(it shows all products). the same as before if category is set and the price is not stock is set again , it shows thing filtered only by category. my model is product.rb

def self.categorized(category=nil)
  return self.where("category_id LIKE ?",category ) if category
  self
end
def self.priced(price=nil)
  return self.where("price < 50") if price=="low"
  return self.where("price < 100 and price > 50") if price=="mid"
  return self.where("price > 100") if price=="high"
  self
end

def self.stocked(stock=nil)
  return self.where("stock > 0") if stock=="available"
  return self.where("stock = 0" ) if stock=="out"
  self
end
def self.catalog(params)
 page = params[:page]
 category = params[:category]
 stock = params[:stock]
 price = params[:price]
 self.stocked(stock).priced(price).categorized(category)
  .paginate(:page =>page).limit(9)
end
LogofaT
  • 289
  • 1
  • 3
  • 17

2 Answers2

3

Your problem is that self isn't exactly what you expect it to be. Since these are class level methods self always refers to the 'plain' class, not something that has already 'aggregated' the where clauses you use. What you want here is to return something that doesn't change the chained query you have so far.

def self.categorized(category=nil)
  return self.where("category_id LIKE ?",category ) if category
  scoped
end

should work

(Updated my answer, not sure if the Product.none did what I thought it would and it is available only for Rails 4.0).

thorsten müller
  • 5,621
  • 1
  • 22
  • 30
2

Use scope for this,

scope :priced, where("price < 50")
scope :stocked, where("stock > 0")

Then call Product.priced.stocked.

Read more about scope and how to pass variables to scope here

Edit:

This will be your complete code for filtering.. Let me know if this is working or not.

  scope :categorized, (lambda do |category|
    where("category_id LIKE ?",category ) if category   
  end)

  scope :priced, (lambda do |price|
     where("price < 50") if price=="low"
     where("price < 100 and price > 50") if price=="mid"
     where("price > 100") if price=="high"
  end)

  scope :stocked, (lambda do |stock|
     where("stock > 0") if stock=="available"
     where("stock = 0" ) if stock=="out"
  end)

def self.catalog(params)
 page = params[:page]
 category = params[:category]
 stock = params[:stock]
 price = params[:price]
 @products = Product.scoped
 @products.stocked(stock) if stock
 @products.priced(price) if price
 @products.categorized(category) if category
 @products.paginate(:page =>page).limit(9)    
end
Thaha kp
  • 3,689
  • 1
  • 26
  • 25
  • Yes, this would work. Though for a better OOP design you should still use a Null Relation in the scope method. That way you don't have to worry about all those `if stock` and similar things at the end, just return Product.none if no attribute applies and you can just chain the scope. As you do it, the outside world needs to have knowledge about how the scope method works. – thorsten müller Feb 10 '14 at 12:00
  • Yes, this would work. Though for a better OOP design you should still use a Null Relation in the scope method. That way you don't have to worry about all those `if stock` and similar things at the end, just return Product.none if no attribute applies and you can just chain the scope. As you do it, the outside world needs to have knowledge about how the scope method works. – thorsten müller Feb 10 '14 at 12:00
  • btw: I think you must do `@products = @products.stocked(stock) if stock` – thorsten müller Feb 10 '14 at 12:00
  • If we add Product.none if stock.nil? inside stock scope, get an empty result if stock == nil. Next line calling priced scope on this result. Where clause inside the priced scope will append to the empty products. Then the result always will be empty. Correct me if I am wrong. – Thaha kp Feb 10 '14 at 12:08
  • Seems I got wrong what exactly ActiveRecord#none does. I think if you use `scoped` as a return value this should have the desired effect, it would not change anything about the already applied scopes, but could still be chained. – thorsten müller Feb 10 '14 at 12:25
  • #Thaha kp. indeed if i would used product null i get an empty list regardless of the other filters. And if i try the code as u wrote it i get an error at the very first line: tried to create Proc object without a block – LogofaT Feb 10 '14 at 16:20
  • Adding () for lambda will solve this problem. See here http://stackoverflow.com/questions/1476678/rails-named-scope-lambda-and-blocks – Thaha kp Feb 11 '14 at 05:27
  • I have tried both ways and both work in this final stage. Altought I dont fully understand scope and lambda so i used #thorsten müller -s version – LogofaT Feb 13 '14 at 15:59