spree_core 0.40.4 → 0.50.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +6 -1
- data/app/controllers/admin/base_controller.rb +0 -57
- data/app/controllers/admin/configurations_controller.rb +1 -1
- data/app/controllers/admin/general_settings_controller.rb +1 -1
- data/app/controllers/admin/images_controller.rb +18 -8
- data/app/controllers/admin/inventory_settings_controller.rb +1 -1
- data/app/controllers/admin/mail_settings_controller.rb +1 -1
- data/app/controllers/admin/option_types_controller.rb +11 -0
- data/app/controllers/admin/orders_controller.rb +16 -20
- data/app/controllers/admin/overview_controller.rb +1 -1
- data/app/controllers/admin/payment_methods_controller.rb +6 -6
- data/app/controllers/admin/product_groups_controller.rb +10 -11
- data/app/controllers/admin/product_properties_controller.rb +5 -5
- data/app/controllers/admin/product_scopes_controller.rb +12 -4
- data/app/controllers/admin/products_controller.rb +17 -12
- data/app/controllers/admin/properties_controller.rb +7 -7
- data/app/controllers/admin/prototypes_controller.rb +15 -15
- data/app/controllers/admin/reports_controller.rb +12 -11
- data/app/controllers/admin/shipments_controller.rb +0 -5
- data/app/controllers/admin/shipping_categories_controller.rb +6 -6
- data/app/controllers/admin/shipping_methods_controller.rb +1 -2
- data/app/controllers/admin/states_controller.rb +12 -12
- data/app/controllers/admin/tax_categories_controller.rb +2 -2
- data/app/controllers/admin/tax_rates_controller.rb +8 -8
- data/app/controllers/admin/tax_settings_controller.rb +1 -1
- data/app/controllers/admin/taxonomies_controller.rb +3 -3
- data/app/controllers/admin/taxons_controller.rb +1 -8
- data/app/controllers/admin/trackers_controller.rb +1 -1
- data/app/controllers/admin/users_controller.rb +6 -9
- data/app/controllers/admin/variants_controller.rb +13 -2
- data/app/controllers/admin/zones_controller.rb +9 -9
- data/app/controllers/checkout_controller.rb +5 -5
- data/app/controllers/products_controller.rb +1 -1
- data/app/controllers/taxons_controller.rb +3 -1
- data/app/helpers/admin/navigation_helper.rb +36 -19
- data/app/helpers/admin/payments_helper.rb +1 -1
- data/app/helpers/admin/product_groups_helper.rb +1 -1
- data/app/helpers/admin/product_properties_helper.rb +5 -5
- data/app/helpers/admin/products_helper.rb +2 -2
- data/app/helpers/admin/users_helper.rb +5 -2
- data/app/helpers/hook_helper.rb +3 -3
- data/app/helpers/products_helper.rb +0 -19
- data/app/helpers/spree/base_helper.rb +33 -2
- data/app/helpers/taxons_helper.rb +3 -3
- data/app/mailers/order_mailer.rb +2 -2
- data/app/mailers/shipment_mailer.rb +2 -2
- data/app/models/address.rb +42 -9
- data/app/models/adjustment.rb +8 -8
- data/app/models/app_configuration.rb +0 -6
- data/app/models/billing_integration.rb +1 -1
- data/app/models/calculator/sales_tax.rb +3 -3
- data/app/models/configuration.rb +1 -1
- data/app/models/country.rb +4 -5
- data/app/models/creditcard.rb +38 -31
- data/app/models/gateway.rb +14 -14
- data/app/models/gateway/beanstream.rb +4 -4
- data/app/models/gateway/bogus.rb +6 -6
- data/app/models/gateway/braintree.rb +88 -0
- data/app/models/gateway/eway.rb +3 -3
- data/app/models/image.rb +5 -4
- data/app/models/option_type.rb +1 -0
- data/app/models/order.rb +60 -21
- data/app/models/payment.rb +5 -32
- data/app/models/preference.rb +7 -7
- data/app/models/product.rb +22 -7
- data/app/models/product_group.rb +22 -26
- data/app/models/product_property.rb +5 -5
- data/app/models/product_scope.rb +26 -6
- data/app/models/property.rb +1 -1
- data/app/models/state.rb +2 -3
- data/app/models/tax_category.rb +1 -0
- data/app/models/tax_rate.rb +1 -2
- data/app/models/taxon.rb +12 -10
- data/app/models/taxonomy.rb +7 -4
- data/app/models/tracker.rb +1 -1
- data/app/models/user.rb +4 -0
- data/app/models/variant.rb +1 -1
- data/app/models/zone.rb +1 -1
- data/app/models/zone_member.rb +3 -3
- data/app/views/admin/{shared → adjustments}/_adjustments_table.html.erb +7 -4
- data/app/views/admin/adjustments/edit.html.erb +1 -1
- data/app/views/admin/adjustments/index.html.erb +2 -2
- data/app/views/admin/adjustments/new.html.erb +2 -1
- data/app/views/admin/general_settings/edit.html.erb +4 -12
- data/app/views/admin/general_settings/show.html.erb +0 -5
- data/app/views/admin/images/index.html.erb +8 -5
- data/app/views/admin/inventory_settings/show.html.erb +1 -1
- data/app/views/admin/mail_methods/index.html.erb +4 -4
- data/app/views/admin/option_types/_form.html.erb +4 -4
- data/app/views/admin/option_types/_option_value_fields.html.erb +2 -2
- data/app/views/admin/option_types/edit.html.erb +4 -2
- data/app/views/admin/option_types/index.html.erb +5 -5
- data/app/views/admin/orders/_line_item.html.erb +2 -1
- data/app/views/admin/orders/history.html.erb +6 -2
- data/app/views/admin/orders/index.html.erb +22 -19
- data/app/views/admin/orders/show.html.erb +1 -1
- data/app/views/admin/orders/user.html.erb +1 -1
- data/app/views/admin/payment_methods/index.html.erb +7 -5
- data/app/views/admin/payments/_list.html.erb +3 -3
- data/app/views/admin/payments/index.html.erb +1 -1
- data/app/views/admin/payments/show.html.erb +2 -2
- data/app/views/admin/product_groups/edit.html.erb +7 -7
- data/app/views/admin/product_groups/index.html.erb +5 -3
- data/app/views/admin/product_groups/update.js.erb +4 -3
- data/app/views/admin/product_properties/_product_property_fields.html.erb +3 -3
- data/app/views/admin/product_properties/index.html.erb +10 -5
- data/app/views/admin/product_scopes/destroy.js.erb +1 -0
- data/app/views/admin/products/index.html.erb +32 -33
- data/app/views/admin/properties/_form.html.erb +2 -2
- data/app/views/admin/properties/index.html.erb +4 -4
- data/app/views/admin/prototypes/index.html.erb +4 -4
- data/app/views/admin/shared/_address_form.html.erb +1 -1
- data/app/views/admin/shared/_calculator_fields.html.erb +1 -1
- data/app/views/admin/shared/_destroy.js.erb +15 -2
- data/app/views/admin/shared/_order_tabs.html.erb +1 -1
- data/app/views/admin/shared/_report_criteria.html.erb +1 -1
- data/app/views/admin/shipments/_form.html.erb +6 -2
- data/app/views/admin/shipments/edit.html.erb +1 -1
- data/app/views/admin/shipments/index.html.erb +4 -2
- data/app/views/admin/shipping_methods/_form.html.erb +2 -0
- data/app/views/admin/shipping_methods/index.html.erb +3 -2
- data/app/views/admin/states/_state_list.html.erb +11 -5
- data/app/views/admin/tax_categories/index.html.erb +9 -4
- data/app/views/admin/tax_settings/show.html.erb +2 -2
- data/app/views/admin/taxonomies/_list.html.erb +4 -2
- data/app/views/admin/taxonomies/index.html.erb +2 -2
- data/app/views/admin/taxons/_form.html.erb +1 -1
- data/app/views/admin/trackers/index.html.erb +5 -5
- data/app/views/admin/users/_form.html.erb +3 -4
- data/app/views/admin/users/index.html.erb +7 -6
- data/app/views/admin/users/show.html.erb +3 -3
- data/app/views/admin/variants/index.html.erb +21 -6
- data/app/views/admin/zones/_form.html.erb +9 -9
- data/app/views/admin/zones/_member_type.html.erb +5 -5
- data/app/views/admin/zones/index.html.erb +7 -5
- data/app/views/checkout/_address.html.erb +2 -2
- data/app/views/checkout/_payment.html.erb +3 -6
- data/app/views/layouts/admin.html.erb +3 -9
- data/app/views/layouts/spree_application.html.erb +2 -1
- data/app/views/orders/_line_item.html.erb +1 -1
- data/app/views/orders/edit.html.erb +17 -16
- data/app/views/orders/show.html.erb +1 -1
- data/app/views/shared/_admin_head.html.erb +1 -1
- data/app/views/shared/_error_messages.html.erb +2 -2
- data/app/views/shared/_filters.html.erb +4 -4
- data/app/views/shared/_head.html.erb +2 -2
- data/app/views/shared/_nav_bar.html.erb +2 -2
- data/app/views/shared/_products.html.erb +4 -2
- data/app/views/shared/_taxonomies.html.erb +15 -8
- data/app/views/shipment_mailer/shipped_email.text.erb +2 -2
- data/config/cucumber.yml +10 -0
- data/config/initializers/form_builder.rb +1 -5
- data/config/initializers/workarounds_for_ruby19.rb +5 -5
- data/config/locales/en.yml +33 -6
- data/config/routes.rb +18 -13
- data/db/migrate/20090923100315_add_count_on_hand_to_variants_and_products.rb +5 -5
- data/db/migrate/20091213222815_creditcard_last_four_digits.rb +5 -5
- data/db/migrate/20100105132138_shipment_id_for_inventory_units.rb +2 -2
- data/db/migrate/20100209025806_create_payment_methods.rb +3 -3
- data/db/migrate/20100209144531_polymorphic_payments.rb +1 -1
- data/db/migrate/20100214212536_assign_creditcard_txns_to_payment.rb +2 -2
- data/db/migrate/20100224153127_deleted_at_for_payment_methods.rb +1 -1
- data/db/migrate/20100506185838_add_description_to_taxons.rb +1 -1
- data/db/migrate/20100816212146_shipping_method_id_for_orders.rb +1 -1
- data/db/migrate/20101026184808_migrate_checkout_to_orders.rb +2 -2
- data/db/migrate/20101223215658_add_position_to_variants.rb +9 -0
- data/db/migrate/20110110130847_add_next_state_to_state_events.rb +9 -0
- data/db/migrate/20110111122537_add_position_to_option_types.rb +9 -0
- data/db/migrate/20110314192118_remove_trailing_slashes_in_taxon_permalinks.rb +17 -0
- data/lib/custom_fixtures.rb +1 -1
- data/lib/{seo_assist.rb → middleware/seo_assist.rb} +14 -8
- data/lib/product_filters.rb +49 -43
- data/lib/redirect_legacy_product_url.rb +5 -5
- data/lib/scopes.rb +2 -2
- data/lib/scopes/dynamic.rb +9 -16
- data/lib/scopes/product.rb +33 -16
- data/lib/scopes/variant.rb +4 -3
- data/lib/spree/calculated_adjustments.rb +5 -2
- data/lib/spree/config.rb +2 -0
- data/lib/spree/current_order.rb +4 -4
- data/lib/spree/mail_settings.rb +3 -2
- data/lib/spree/search/base.rb +9 -10
- data/lib/spree_base.rb +22 -23
- data/lib/spree_core.rb +10 -69
- data/lib/spree_core/authorize_net_cim_hack.rb +1 -1
- data/lib/spree_core/delegate_belongs_to.rb +18 -24
- data/lib/spree_core/enumerable_constants.rb +38 -38
- data/lib/spree_core/find_by_param.rb +8 -6
- data/lib/spree_core/preferences/preference_definition.rb +7 -7
- data/lib/spree_core/railtie.rb +58 -0
- data/lib/spree_core/ssl_requirement.rb +4 -3
- data/lib/spree_core/testing_support/factories.rb +13 -0
- data/lib/spree_core/testing_support/factories/address_factory.rb +20 -0
- data/lib/spree_core/testing_support/factories/adjustment_factory.rb +6 -0
- data/lib/spree_core/testing_support/factories/calculator_factory.rb +5 -0
- data/lib/spree_core/testing_support/factories/configuraion_factory.rb +4 -0
- data/lib/spree_core/testing_support/factories/country_factory.rb +7 -0
- data/lib/spree_core/testing_support/factories/creditcard_factory.rb +11 -0
- data/lib/spree_core/testing_support/factories/inventory_unit_factory.rb +7 -0
- data/lib/spree_core/testing_support/factories/line_item_factory.rb +8 -0
- data/lib/spree_core/testing_support/factories/mail_method_factory.rb +4 -0
- data/lib/spree_core/testing_support/factories/options_factory.rb +10 -0
- data/lib/spree_core/testing_support/factories/order_factory.rb +18 -0
- data/lib/spree_core/testing_support/factories/payment_factory.rb +26 -0
- data/lib/spree_core/testing_support/factories/payment_method_factory.rb +17 -0
- data/lib/spree_core/testing_support/factories/product_factory.rb +16 -0
- data/lib/spree_core/testing_support/factories/product_group_factory.rb +3 -0
- data/lib/spree_core/testing_support/factories/product_option_type_factory.rb +4 -0
- data/lib/spree_core/testing_support/factories/product_property_factory.rb +4 -0
- data/lib/spree_core/testing_support/factories/product_scope_factory.rb +6 -0
- data/lib/spree_core/testing_support/factories/property_factory.rb +4 -0
- data/lib/spree_core/testing_support/factories/prototype_factory.rb +4 -0
- data/lib/spree_core/testing_support/factories/return_authorization_factory.rb +8 -0
- data/lib/spree_core/testing_support/factories/role_factory.rb +9 -0
- data/lib/spree_core/testing_support/factories/shipment_factory.rb +9 -0
- data/lib/spree_core/testing_support/factories/shipping_category_factory.rb +5 -0
- data/lib/spree_core/testing_support/factories/shipping_method_factory.rb +7 -0
- data/lib/spree_core/testing_support/factories/state_factory.rb +11 -0
- data/lib/spree_core/testing_support/factories/tax_category_factory.rb +8 -0
- data/lib/spree_core/testing_support/factories/tax_rate_factory.rb +5 -0
- data/lib/spree_core/testing_support/factories/taxon_factory.rb +5 -0
- data/lib/spree_core/testing_support/factories/taxonomy_factory.rb +3 -0
- data/lib/spree_core/testing_support/factories/tracker_factory.rb +5 -0
- data/lib/spree_core/testing_support/factories/user_factory.rb +15 -0
- data/lib/spree_core/testing_support/factories/variant_factory.rb +14 -0
- data/lib/spree_core/testing_support/factories/zone_factory.rb +18 -0
- data/lib/spree_core/theme_support/hook.rb +1 -1
- data/lib/spree_core/theme_support/more_patches.rb +20 -20
- data/lib/spree_core/version.rb +5 -0
- data/lib/tasks/common.rb +30 -0
- data/lib/tasks/install.rake +1 -1
- data/lib/tasks/rake_util.rb +19 -0
- data/lib/tasks/taxon.rake +14 -0
- data/public/images/reorder.jpg +0 -0
- data/public/javascripts/admin.js +0 -6
- data/public/javascripts/admin/unobtrusive_handlers.js +28 -0
- data/public/javascripts/checkout.js +3 -3
- data/public/stylesheets/admin/admin-forms.css +1 -6
- data/public/stylesheets/admin/admin.css +0 -28
- data/public/stylesheets/screen.css +0 -280
- metadata +81 -43
- data/app/controllers/countries_controller.rb +0 -11
- data/app/models/spree/alert.rb +0 -13
- data/app/models/state_monitor.rb +0 -25
- data/app/views/admin/shared/_alert.html.erb +0 -6
- data/app/views/countries/index.js.erb +0 -1
- data/app/views/shared/_doc_and_xmlns.html.erb +0 -2
- data/app/views/users/edit.html.erb +0 -9
- data/app/views/users/show.html.erb +0 -46
- data/lib/spree_core/validation_group.rb +0 -143
- data/public/stylesheets/scaffold.css +0 -54
@@ -0,0 +1,17 @@
|
|
1
|
+
class RemoveTrailingSlashesInTaxonPermalinks < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
Taxon.find_each(:conditions => {}) do |t|
|
4
|
+
if t.permalink && t.permalink[-1..-1] == '/'
|
5
|
+
t.update_attribute(:permalink, t.permalink[0...-1])
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.down
|
11
|
+
Taxon.find_each(:conditions => {}) do |t|
|
12
|
+
if t.permalink && t.permalink[-1..-1] != '/'
|
13
|
+
t.update_attribute(:permalink, t.permalink + '/')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/custom_fixtures.rb
CHANGED
@@ -8,23 +8,29 @@ class SeoAssist
|
|
8
8
|
request = Rack::Request.new(env)
|
9
9
|
params = request.params
|
10
10
|
taxon_id = params['taxon']
|
11
|
-
|
11
|
+
|
12
|
+
#redirect requests using taxon id's to their permalinks
|
13
|
+
if !taxon_id.blank? && !taxon_id.is_a?(Hash) && taxon = Taxon.find(taxon_id)
|
12
14
|
params.delete('taxon')
|
13
|
-
|
14
|
-
|
15
|
-
return [301, { 'Location'=> "/t/#{permalink}?#{query}" }, []]
|
15
|
+
|
16
|
+
return build_response(params, "/t/#{taxon.permalink}" )
|
16
17
|
elsif env["PATH_INFO"] =~ /^\/(t|products)(\/\S+)?\/$/
|
17
18
|
#ensures no trailing / for taxon and product urls
|
18
|
-
|
19
|
-
|
20
|
-
new_location += '?' + query unless query.blank?
|
21
|
-
return [301, { 'Location'=> new_location }, []]
|
19
|
+
|
20
|
+
return build_response(params, env["PATH_INFO"][0...-1])
|
22
21
|
end
|
22
|
+
|
23
23
|
@app.call(env)
|
24
24
|
end
|
25
25
|
|
26
26
|
private
|
27
27
|
|
28
|
+
def build_response(params, location)
|
29
|
+
query = build_query(params)
|
30
|
+
location += '?' + query unless query.blank?
|
31
|
+
[301, { 'Location'=> location }, []]
|
32
|
+
end
|
33
|
+
|
28
34
|
def build_query(params)
|
29
35
|
params.map { |k, v|
|
30
36
|
if v.class == Array
|
data/lib/product_filters.rb
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
# set up some basic filters for use with products
|
6
6
|
#
|
7
7
|
# Each filter has two parts
|
8
|
-
# * a parametrized named scope which expects a list of labels
|
8
|
+
# * a parametrized named scope which expects a list of labels
|
9
9
|
# * an object which describes/defines the filter
|
10
10
|
#
|
11
11
|
# The filter description has three components
|
@@ -14,26 +14,28 @@
|
|
14
14
|
# * a mapping of presentation labels to the relevant condition (in the context of the named scope)
|
15
15
|
# * an optional list of labels and values (for use with object selection - see taxons examples below)
|
16
16
|
#
|
17
|
-
# The named scopes here have a suffix '_any', following SearchLogic's convention for a
|
17
|
+
# The named scopes here have a suffix '_any', following SearchLogic's convention for a
|
18
18
|
# scope which returns results which match any of the inputs. This is purely a convention,
|
19
|
-
# but might be a useful reminder.
|
19
|
+
# but might be a useful reminder.
|
20
20
|
#
|
21
|
-
# When creating a form, the name of the checkbox group for a filter F should be
|
22
|
-
# the name of F's scope with [] appended, eg "price_range_any[]", and for
|
21
|
+
# When creating a form, the name of the checkbox group for a filter F should be
|
22
|
+
# the name of F's scope with [] appended, eg "price_range_any[]", and for
|
23
23
|
# each label you should have a checkbox with the label as its value. On submission,
|
24
24
|
# Rails will send the action a hash containing (among other things) an array named
|
25
|
-
# after the scope whose values are the active labels.
|
25
|
+
# after the scope whose values are the active labels.
|
26
26
|
#
|
27
27
|
# SearchLogic will then convert this array to a call to the named scope with the array
|
28
28
|
# contents, and the named scope will build a query with the disjunction of the conditions
|
29
|
-
# relating to the labels, all relative to the scope's context.
|
29
|
+
# relating to the labels, all relative to the scope's context.
|
30
30
|
#
|
31
|
-
# The details of how/when filters are used is a detail for specific models (eg products
|
31
|
+
# The details of how/when filters are used is a detail for specific models (eg products
|
32
32
|
# or taxons), eg see the taxon model/controller.
|
33
33
|
|
34
34
|
# See specific filters below for concrete examples.
|
35
35
|
|
36
|
-
|
36
|
+
# This module is included by Taxon. In development mode that inclusion does not
|
37
|
+
# happen until Taxon class is loaded. Ensure that Taxon class is loaded before
|
38
|
+
# you try something like Product.price_range_any
|
37
39
|
module ProductFilters
|
38
40
|
|
39
41
|
# Example: filtering by price
|
@@ -42,8 +44,11 @@ module ProductFilters
|
|
42
44
|
# we can access the field right away
|
43
45
|
# The filter identifies which scope to use, then sets the conditions for each price range
|
44
46
|
#
|
47
|
+
# If user checks off three different price ranges then the argument passed to
|
48
|
+
# below scope would be something like ["$10 - $15", "$15 - $18", "$18 - $20"]
|
49
|
+
#
|
45
50
|
Product.scope :price_range_any,
|
46
|
-
lambda {
|
51
|
+
lambda {|*opts|
|
47
52
|
conds = opts.map {|o| ProductFilters.price_filter[:conds][o]}.reject {|c| c.nil?}
|
48
53
|
Product.scoped(:joins => :master).conditions_any(conds)
|
49
54
|
}
|
@@ -63,27 +68,27 @@ module ProductFilters
|
|
63
68
|
|
64
69
|
|
65
70
|
# Example: filtering by possible brands
|
66
|
-
#
|
71
|
+
#
|
67
72
|
# First, we define the scope. Two interesting points here: (a) we run our conditions
|
68
|
-
# in the scope where the info for the 'brand' property has been loaded; and (b)
|
69
|
-
# because we may want to filter by other properties too, we give this part of the
|
73
|
+
# in the scope where the info for the 'brand' property has been loaded; and (b)
|
74
|
+
# because we may want to filter by other properties too, we give this part of the
|
70
75
|
# query a unique name (which must be used in the associated conditions too).
|
71
76
|
#
|
72
|
-
# Secondly, the filter. Instead of a static list of values, we pull out all existing
|
77
|
+
# Secondly, the filter. Instead of a static list of values, we pull out all existing
|
73
78
|
# brands from the db, and then build conditions which test for string equality on
|
74
79
|
# the (uniquely named) field "p_brand.value". There's also a test for brand info
|
75
|
-
# being blank: note that this relies on with_property doing a left outer join
|
76
|
-
# rather than an inner join.
|
80
|
+
# being blank: note that this relies on with_property doing a left outer join
|
81
|
+
# rather than an inner join.
|
77
82
|
|
78
83
|
if Property.table_exists? && @@brand_property = Property.find_by_name("brand")
|
79
84
|
Product.scope :brand_any,
|
80
|
-
lambda {
|
81
|
-
conds = opts.map {|o| ProductFilters.brand_filter[:conds][o]}.reject {|c| c.nil?}
|
85
|
+
lambda {|*opts|
|
86
|
+
conds = opts.map {|o| ProductFilters.brand_filter[:conds][o]}.reject {|c| c.nil?}
|
82
87
|
Product.with_property("brand").conditions_any(conds)
|
83
|
-
}
|
88
|
+
}
|
84
89
|
|
85
90
|
def ProductFilters.brand_filter
|
86
|
-
brands = ProductProperty.find_all_by_property_id(@@brand_property).map(&:value).uniq
|
91
|
+
brands = ProductProperty.find_all_by_property_id(@@brand_property).map(&:value).compact.uniq
|
87
92
|
conds = Hash[*brands.map {|b| [b, "product_properties.value = '#{b}'"]}.flatten]
|
88
93
|
{ :name => "Brands",
|
89
94
|
:scope => :brand_any,
|
@@ -95,34 +100,34 @@ module ProductFilters
|
|
95
100
|
|
96
101
|
# Example: a parametrized filter
|
97
102
|
# The filter above may show brands which aren't applicable to the current taxon,
|
98
|
-
# so this one only shows the brands that are relevant to a particular taxon and
|
103
|
+
# so this one only shows the brands that are relevant to a particular taxon and
|
99
104
|
# its descendants.
|
100
105
|
#
|
101
|
-
# We don't have to give a new scope since the conditions here are a subset of the
|
102
|
-
# more general filter, so decoding will still work - as long as the filters on a
|
103
|
-
# page all have unique names (ie, you can't use the two brand filters together
|
106
|
+
# We don't have to give a new scope since the conditions here are a subset of the
|
107
|
+
# more general filter, so decoding will still work - as long as the filters on a
|
108
|
+
# page all have unique names (ie, you can't use the two brand filters together
|
104
109
|
# if they use the same scope). To be safe, the code uses a copy of the scope.
|
105
110
|
#
|
106
|
-
# HOWEVER: what happens if we want a more precise scope? we can't pass
|
107
|
-
# parametrized scope names to SearchLogic, only atomic names, so couldn't ask
|
108
|
-
# for taxon T's customized filter to be used. BUT: we can arrange for the form
|
109
|
-
# to pass back a hash instead of an array, where the key acts as the (taxon)
|
111
|
+
# HOWEVER: what happens if we want a more precise scope? we can't pass
|
112
|
+
# parametrized scope names to SearchLogic, only atomic names, so couldn't ask
|
113
|
+
# for taxon T's customized filter to be used. BUT: we can arrange for the form
|
114
|
+
# to pass back a hash instead of an array, where the key acts as the (taxon)
|
110
115
|
# parameter and value is its label array, and then get a modified named scope
|
111
|
-
# to get its conditions from a particular filter.
|
116
|
+
# to get its conditions from a particular filter.
|
112
117
|
#
|
113
|
-
# The brand-finding code can be simplified if a few more named scopes were added to
|
114
|
-
# the product properties model.
|
118
|
+
# The brand-finding code can be simplified if a few more named scopes were added to
|
119
|
+
# the product properties model.
|
115
120
|
|
116
|
-
if Property.table_exists? && @@brand_property
|
121
|
+
if Property.table_exists? && @@brand_property
|
117
122
|
Product.scope :selective_brand_any, lambda {|opts| Product.brand_any(opts) }
|
118
123
|
|
119
124
|
def ProductFilters.selective_brand_filter(taxon = nil)
|
120
|
-
if taxon.nil?
|
121
|
-
taxon = Taxonomy.first.root
|
122
|
-
end
|
125
|
+
if taxon.nil?
|
126
|
+
taxon = Taxonomy.first.root
|
127
|
+
end
|
123
128
|
all_brands = ProductProperty.find_all_by_property_id(@@brand_property).map(&:value).uniq
|
124
129
|
scope = ProductProperty.scoped(:conditions => ["property_id = ?", @@brand_property]).
|
125
|
-
scoped(:joins => {:product => :taxons},
|
130
|
+
scoped(:joins => {:product => :taxons},
|
126
131
|
:conditions => ["taxons.id in (?)", [taxon] + taxon.descendants])
|
127
132
|
brands = scope.map {|p| p.value}
|
128
133
|
|
@@ -136,17 +141,17 @@ module ProductFilters
|
|
136
141
|
|
137
142
|
|
138
143
|
# Provide filtering on the immediate children of a taxon
|
139
|
-
#
|
144
|
+
#
|
140
145
|
# This doesn't fit the pattern of the examples above, so there's a few changes.
|
141
|
-
# Firstly, it uses an existing scope which was not built for filtering - and so
|
142
|
-
# has no need of a conditions mapping, and secondly, it has a mapping of name
|
143
|
-
# to the argument type expected by the other scope.
|
146
|
+
# Firstly, it uses an existing scope which was not built for filtering - and so
|
147
|
+
# has no need of a conditions mapping, and secondly, it has a mapping of name
|
148
|
+
# to the argument type expected by the other scope.
|
144
149
|
#
|
145
|
-
# This technique is useful for filtering on objects (by passing ids) or with a
|
150
|
+
# This technique is useful for filtering on objects (by passing ids) or with a
|
146
151
|
# scope that can be used directly (eg. testing only ever on a single property).
|
147
|
-
#
|
152
|
+
#
|
148
153
|
# This scope selects products in any of the active taxons or their children.
|
149
|
-
#
|
154
|
+
#
|
150
155
|
def ProductFilters.taxons_below(taxon)
|
151
156
|
return ProductFilters.all_taxons if taxon.nil?
|
152
157
|
{ :name => "Taxons under " + taxon.name,
|
@@ -170,4 +175,5 @@ module ProductFilters
|
|
170
175
|
:conds => nil # not needed
|
171
176
|
}
|
172
177
|
end
|
178
|
+
|
173
179
|
end
|
@@ -2,12 +2,12 @@ class RedirectLegacyProductUrl
|
|
2
2
|
def initialize(app)
|
3
3
|
@app = app
|
4
4
|
end
|
5
|
-
|
6
|
-
def call(env)
|
7
|
-
if env["PATH_INFO"] =~ %r{/t/.+/p/(.+)}
|
8
|
-
return [301, {'Location'=> "/products/#{$1}" }, []]
|
5
|
+
|
6
|
+
def call(env)
|
7
|
+
if env["PATH_INFO"] =~ %r{/t/.+/p/(.+)}
|
8
|
+
return [301, {'Location'=> "/products/#{$1}" }, []]
|
9
9
|
end
|
10
10
|
@app.call(env)
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
end
|
data/lib/scopes.rb
CHANGED
@@ -41,7 +41,7 @@ module Scopes
|
|
41
41
|
scopes.each_pair do |scope_name, targs|
|
42
42
|
hashed_args = {}
|
43
43
|
targs.each{|v| hashed_args[v.to_s] = v.to_s.humanize}
|
44
|
-
|
44
|
+
|
45
45
|
result['scopes'][scope_name.to_s] = {
|
46
46
|
'name' => scope_name.to_s.humanize,
|
47
47
|
'description' => "",
|
@@ -66,4 +66,4 @@ end
|
|
66
66
|
# def to_sql
|
67
67
|
# construct_finder_sql({})
|
68
68
|
# end
|
69
|
-
# end
|
69
|
+
# end
|
data/lib/scopes/dynamic.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# This module is extended by ProductScope
|
1
2
|
module Scopes::Dynamic
|
2
3
|
module_function
|
3
4
|
|
@@ -9,30 +10,22 @@ module Scopes::Dynamic
|
|
9
10
|
|
10
11
|
# Price based scopes
|
11
12
|
all_prices = products.map(&:price).sort
|
13
|
+
|
12
14
|
ranges = [Math.log(products.length).floor, scope_limit].max
|
15
|
+
|
13
16
|
if ranges >= 2
|
14
17
|
l = all_prices.length / ranges
|
15
|
-
scopes << ProductScope.new({
|
16
|
-
|
17
|
-
:arguments => [all_prices[l]]
|
18
|
-
})
|
18
|
+
scopes << ProductScope.new({:name => "master_price_lte", :arguments => [all_prices[l]] })
|
19
|
+
|
19
20
|
(ranges - 2).times do |x|
|
20
|
-
scopes << ProductScope.new({
|
21
|
-
|
22
|
-
:arguments => [
|
23
|
-
all_prices[l*(x+1)+1],
|
24
|
-
all_prices[l*(x+2)]
|
25
|
-
]
|
26
|
-
})
|
21
|
+
scopes << ProductScope.new({:name => "price_between",
|
22
|
+
:arguments => [ all_prices[l*(x+1)+1], all_prices[l*(x+2)] ] })
|
27
23
|
end
|
28
|
-
|
29
|
-
|
30
|
-
:arguments => [all_prices[l*(ranges-1)+1]]
|
31
|
-
})
|
24
|
+
|
25
|
+
scopes << ProductScope.new({:name => "master_price_gte", :arguments => [all_prices[l*(ranges-1)+1]] })
|
32
26
|
end
|
33
27
|
|
34
28
|
scopes
|
35
29
|
end
|
36
30
|
|
37
|
-
|
38
31
|
end
|
data/lib/scopes/product.rb
CHANGED
@@ -40,6 +40,22 @@ module Scopes::Product
|
|
40
40
|
:descend_by_popularity,
|
41
41
|
]
|
42
42
|
|
43
|
+
ORDERING.each do |name|
|
44
|
+
next if %w(asecend_by_master_price descend_by_master_price).include?(name.to_s)
|
45
|
+
r = name.to_s.match(/(.*)_by_(.*)/)
|
46
|
+
|
47
|
+
order_text = "products.#{r[2]} "
|
48
|
+
order_text << ((r[1] == 'ascend') ? "asc" : "desc")
|
49
|
+
|
50
|
+
Product.send(:scope, name.to_s, Product.send(:relation).order(order_text) )
|
51
|
+
end
|
52
|
+
|
53
|
+
::Product.scope :ascend_by_master_price, lambda {
|
54
|
+
Product.joins(:variants_with_only_master).order('variants.price asc') }
|
55
|
+
|
56
|
+
::Product.scope :descend_by_master_price, lambda {
|
57
|
+
Product.joins(:variants_with_only_master).order('variants.price desc') }
|
58
|
+
|
43
59
|
ATTRIBUTE_HELPER_METHODS = {
|
44
60
|
:with_ids => :product_picker_field
|
45
61
|
}
|
@@ -47,9 +63,10 @@ module Scopes::Product
|
|
47
63
|
# Ryan Bates - http://railscasts.com/episodes/112
|
48
64
|
# general merging of conditions, names following the searchlogic pattern
|
49
65
|
::Product.scope :conditions, lambda { |*args| {:conditions => args}}
|
66
|
+
|
50
67
|
# conditions_all is a more descriptively named enhancement of the above
|
51
|
-
::Product.scope :conditions_all, lambda { |*args| {:conditions => [args].flatten}}
|
52
|
-
|
68
|
+
::Product.scope :conditions_all, lambda { |*args| {:conditions => [args].flatten}}
|
69
|
+
|
53
70
|
# forming the disjunction of a list of conditions (as strings)
|
54
71
|
::Product.scope :conditions_any, lambda { |*args|
|
55
72
|
args = [args].flatten
|
@@ -58,21 +75,19 @@ module Scopes::Product
|
|
58
75
|
}
|
59
76
|
|
60
77
|
|
78
|
+
::Product.scope :price_between, lambda { |low, high|
|
79
|
+
{ :joins => :master, :conditions => ["variants.price BETWEEN ? AND ?", low, high] }
|
80
|
+
}
|
61
81
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
# ::Product.scope :available, lambda { |*args|
|
66
|
-
# where("products.available_on <= ?", args.first || Time.zone.now)
|
67
|
-
# }
|
68
|
-
# ::Product.scope :active, lambda { |*args|
|
69
|
-
# Product.not_deleted.available(args.first).scope(:find)
|
70
|
-
# }
|
82
|
+
::Product.scope :master_price_lte, lambda { |price|
|
83
|
+
{ :joins => :master, :conditions => ["variants.price <= ?", price] }
|
84
|
+
}
|
71
85
|
|
72
|
-
::Product.scope :
|
73
|
-
{ :joins => :master, :conditions => ["variants.price
|
86
|
+
::Product.scope :master_price_gte, lambda { |price|
|
87
|
+
{ :joins => :master, :conditions => ["variants.price >= ?", price] }
|
74
88
|
}
|
75
89
|
|
90
|
+
|
76
91
|
# This scope selects products in taxon AND all its descendants
|
77
92
|
# If you need products only within one taxon use
|
78
93
|
#
|
@@ -176,11 +191,11 @@ module Scopes::Product
|
|
176
191
|
Product.scope :in_name, lambda{|words|
|
177
192
|
Product.like_any([:name], prepare_words(words))
|
178
193
|
}
|
179
|
-
|
194
|
+
|
180
195
|
Product.scope :in_name_or_keywords, lambda{|words|
|
181
196
|
Product.like_any([:name, :meta_keywords], prepare_words(words))
|
182
197
|
}
|
183
|
-
|
198
|
+
|
184
199
|
Product.scope :in_name_or_description, lambda{|words|
|
185
200
|
Product.like_any([:name, :description, :meta_description, :meta_keywords], prepare_words(words))
|
186
201
|
}
|
@@ -218,8 +233,10 @@ SQL
|
|
218
233
|
}
|
219
234
|
}
|
220
235
|
|
221
|
-
# Produce an array of keywords for use in scopes.
|
236
|
+
# Produce an array of keywords for use in scopes.
|
237
|
+
# Always return array with at least an empty string to avoid SQL errors
|
222
238
|
def self.prepare_words(words)
|
239
|
+
return [''] if words.blank?
|
223
240
|
a = words.split(/[,\s]/).map(&:strip)
|
224
241
|
a.any? ? a : ['']
|
225
242
|
end
|
data/lib/scopes/variant.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
module Scopes::Variant
|
2
|
-
|
2
|
+
|
3
|
+
#FIXME WARNING tested only under sqlite and postgresql
|
3
4
|
Variant.scope :descend_by_popularity, lambda{
|
4
5
|
order('COALESCE((SELECT COUNT(*) FROM line_items GROUP BY line_items.variant_id HAVING line_items.variant_id = variants.id), 0) DESC')
|
5
6
|
}
|
6
7
|
|
7
|
-
# for selecting variants with an option value
|
8
|
+
# for selecting variants with an option value
|
8
9
|
# no option type given since the value implies an option type
|
9
10
|
# this scope can be chained repeatedly, since the join name is unique
|
10
11
|
Variant.scope :has_option, lambda {|opt|
|
@@ -13,5 +14,5 @@ module Scopes::Variant
|
|
13
14
|
:conditions => ["#{tbl}.option_value_id = (?)", opt]
|
14
15
|
}
|
15
16
|
}
|
16
|
-
|
17
|
+
|
17
18
|
end
|