# Example Application: # Product: name, price, brand, slug, description, delete_flag, image_url # Category: name,slug # Product belongs to Category # Use scopes instead of chained queries scattered all over your application # Get all available apple products with price > 1000 and not older than 1 week # BAD products = Product.where(brand: "apple").where("price > ?", 1000).where(delete_flag: false).where("created_at > ?", 1.week.ago) # GOOD scope :price_bigger_than, -> { |min_price| where("price > ?", min_price) } # Yes you can pass parameter to scope scope :for_brand, -> { |brand| where(brand: brand) } default_scope :un_deleted, where(delete_flag: false) scope :new, -> { |start_date = 1.week.ago| where("created_at > ?", start_date) } # Yes the scope parameter can have a default default_scope :available, where(delete_flag: false) default_scope :unavailable, where(delete_flag: true) products = Product.for_brand("apple").price_bigger_than(1000).available.new # What if we want to override the default scope?! # Get all apple unavailable products products = Product.for_brand("apple") # Wont work, will get only the available products = Product.for_brand("apple").unavailable # Wont work too, will get only the available products = Product.unscoped.for_brand("apple").unavailable # works perfectly (Y) # Now we want to get products updated today # One can make scope :most_updated, where("updated_at > ?", Date.today) # Watch Out!!! # A scope is defined at initialisation, so what you start up your server, console, or in my case the DelayedJob worker, Date.today gets executed once and a scope is created called due that will return all the Books that are due on the day you start the process # This must be me done using Lambda OR without scopes scope :most_updated, -> { where("updated_at > ?", Date.today) } # Note: -> AND lambda are equivalent # You can define scope dynamically # Example for an api with api_keys Status = {:normal => 0, :whitelisted => 1, :blacklisted => 2} Status.each_pair do |k,v| scope "status_#{k}", where(:status => v) # ApiKey.status_whitelisted,... define_singleton_method "status_#{k}?" do |st| # ApiKey.status_whitelisted?(status),... v == st end define_method "status_#{k}?" do # api_key.status_whitelisted?,... self.status == v end end