spree_core 0.40.4 → 0.50.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|