Created
July 5, 2012 13:18
-
-
Save GeekOnCoffee/3053598 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From 03c3f527b01951900aa88e2bd3bfd23fc1400f86 Mon Sep 17 00:00:00 2001 | |
From: Ryan Bigg <[email protected]> | |
Date: Thu, 14 Jun 2012 16:58:53 +1000 | |
Subject: [PATCH] Explicitly define scopes as being searchable This stops | |
people using class methods or scopes that shouldn't be used | |
for searching. | |
Props to joernchen from Phenoelit for informing us about this! | |
--- | |
app/models/product.rb | 9 +++++++++ | |
app/models/product_group.rb | 2 +- | |
lib/scopes/product.rb | 34 +++++++++++++++++----------------- | |
3 files changed, 27 insertions(+), 18 deletions(-) | |
diff --git a/app/models/product.rb b/app/models/product.rb | |
index b309008..541ede0 100644 | |
--- a/app/models/product.rb | |
+++ b/app/models/product.rb | |
@@ -60,6 +60,15 @@ class Product < ActiveRecord::Base | |
alias :options :product_option_types | |
+ cattr_accessor :search_scopes do | |
+ [] | |
+ end | |
+ | |
+ def self.add_search_scope(name, &block) | |
+ self.named_scope name.intern, &block | |
+ search_scopes << name.intern | |
+ end | |
+ | |
include ::Scopes::Product | |
# default product scope only lists available and non-deleted products | |
diff --git a/app/models/product_group.rb b/app/models/product_group.rb | |
index 8e89853..2238f5f 100644 | |
--- a/app/models/product_group.rb | |
+++ b/app/models/product_group.rb | |
@@ -90,7 +90,7 @@ class ProductGroup < ActiveRecord::Base | |
end | |
def add_scope(scope_name, arguments=[]) | |
- if scope_name.to_s !~ /eval|send|system|[^a-z0-9_!?]/ | |
+ if Product.search_scopes.include?(scope_name.intern) | |
self.product_scopes << ProductScope.new({ | |
:name => scope_name.to_s, | |
:arguments => [*arguments] | |
diff --git a/lib/scopes/product.rb b/lib/scopes/product.rb | |
index 766d2a9..e7ae9cd 100644 | |
--- a/lib/scopes/product.rb | |
+++ b/lib/scopes/product.rb | |
@@ -40,23 +40,23 @@ module Scopes::Product | |
] | |
# default product scope only lists available and non-deleted products | |
- ::Product.named_scope :active, lambda { |*args| | |
+ ::Product.add_search_scope :active, lambda { |*args| | |
Product.not_deleted.available(args.first).scope(:find) | |
} | |
- ::Product.named_scope :not_deleted, { | |
+ ::Product.add_search_scope :not_deleted, { | |
:conditions => "products.deleted_at is null" | |
} | |
- ::Product.named_scope :available, lambda { |*args| | |
+ ::Product.add_search_scope :available, lambda { |*args| | |
{ :conditions => ["products.available_on <= ?", args.first || Time.zone.now] } | |
} | |
- ::Product.named_scope :keywords, lambda{|query| | |
+ ::Product.add_search_scope :keywords, lambda{|query| | |
return {} if query.blank? | |
Spree::Config.searcher.get_products_conditions_for(query) | |
} | |
- ::Product.named_scope :price_between, lambda {|low,high| | |
+ ::Product.add_search_scope :price_between, lambda {|low,high| | |
{ :joins => :master, :conditions => ["variants.price BETWEEN ? AND ?", low, high] } | |
} | |
@@ -65,7 +65,7 @@ module Scopes::Product | |
# | |
# Product.taxons_id_eq(x) | |
# | |
- Product.named_scope :in_taxon, lambda {|taxon| | |
+ Product.add_search_scope :in_taxon, lambda {|taxon| | |
Product.in_taxons(taxon).scope :find | |
} | |
@@ -74,13 +74,13 @@ module Scopes::Product | |
# | |
# Product.taxons_id_eq([x,y]) | |
# | |
- Product.named_scope :in_taxons, lambda {|*taxons| | |
+ Product.add_search_scope :in_taxons, lambda {|*taxons| | |
taxons = get_taxons(taxons) | |
taxons.first ? prepare_taxon_conditions(taxons) : {} | |
} | |
# for quick access to products in a group, WITHOUT using the association mechanism | |
- Product.named_scope :in_cached_group, lambda {|product_group| | |
+ Product.add_search_scope :in_cached_group, lambda {|product_group| | |
{ :joins => "JOIN product_groups_products ON products.id = product_groups_products.product_id", | |
:conditions => ["product_groups_products.product_group_id = ?", product_group] | |
} | |
@@ -88,7 +88,7 @@ module Scopes::Product | |
# a scope that finds all products having property specified by name, object or id | |
- Product.named_scope :with_property, lambda {|property| | |
+ Product.add_search_scope :with_property, lambda {|property| | |
conditions = case property | |
when String then ["properties.name = ?", property] | |
when Property then ["properties.id = ?", property.id] | |
@@ -102,7 +102,7 @@ module Scopes::Product | |
} | |
# a scope that finds all products having an option_type specified by name, object or id | |
- Product.named_scope :with_option, lambda {|option| | |
+ Product.add_search_scope :with_option, lambda {|option| | |
conditions = case option | |
when String then ["option_types.name = ?", option] | |
when OptionType then ["option_types.id = ?", option.id] | |
@@ -117,7 +117,7 @@ module Scopes::Product | |
# a simple test for product with a certain property-value pairing | |
# note that it can test for properties with NULL values, but not for absent values | |
- Product.named_scope :with_property_value, lambda { |property, value| | |
+ Product.add_search_scope :with_property_value, lambda { |property, value| | |
conditions = case property | |
when String then ["properties.name = ?", property] | |
when Property then ["properties.id = ?", property.id] | |
@@ -132,7 +132,7 @@ module Scopes::Product | |
} | |
# a scope that finds all products having an option value specified by name, object or id | |
- Product.named_scope :with_option_value, lambda {|option, value| | |
+ Product.add_search_scope :with_option_value, lambda {|option, value| | |
option_type_id = case option | |
when String | |
option_type = OptionType.find_by_name(option) || option.to_i | |
@@ -153,7 +153,7 @@ module Scopes::Product | |
} | |
# finds product having option value OR product_property | |
- Product.named_scope :with, lambda{|value| | |
+ Product.add_search_scope :with, lambda{|value| | |
{ | |
:conditions => ["option_values.name = ? OR product_properties.value = ?", value, value], | |
:joins => {:variants => :option_values, :product_properties => []} | |
@@ -178,7 +178,7 @@ module Scopes::Product | |
# there is alternative faster and more elegant solution, it has small drawback though, | |
# it doesn stack with other scopes :/ | |
# | |
- Product.named_scope :descend_by_popularity, lambda{ | |
+ Product.add_search_scope :descend_by_popularity, lambda{ | |
# :joins => "LEFT OUTER JOIN (SELECT line_items.variant_id as vid, COUNT(*) as cnt FROM line_items GROUP BY line_items.variant_id) AS popularity_count ON variants.id = vid", | |
# :order => 'COALESCE(cnt, 0) DESC' | |
{ | |
@@ -201,7 +201,7 @@ SQL | |
} | |
# Produce an array of keywords for use in scopes. Always return array with at least an empty string to avoid SQL errors | |
- def self.prepare_words(words) | |
+ def Product.prepare_words(words) | |
a = words.split(/[,\s]/).map(&:strip) | |
a.any? ? a : [''] | |
end | |
@@ -212,7 +212,7 @@ SQL | |
end | |
end | |
- def self.get_taxons(*ids_or_records_or_names) | |
+ def Product.get_taxons(*ids_or_records_or_names) | |
ids_or_records_or_names.flatten.map { |t| | |
case t | |
when Integer then Taxon.find_by_id(t) | |
@@ -227,7 +227,7 @@ SQL | |
end | |
# specifically avoid having an order for taxon search (conflicts with main order) | |
- def self.prepare_taxon_conditions(taxons) | |
+ def Product.prepare_taxon_conditions(taxons) | |
conditions = taxons.map{|taxon| | |
taxon.self_and_descendants.scope(:find)[:conditions] | |
}.inject([[]]){|result, scope| | |
-- | |
1.7.8.3 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment