From aefbda4437f5f1835c60eb4db5f70ebaaa39137a Mon Sep 17 00:00:00 2001 From: aryt Date: Wed, 6 Jul 2022 11:42:33 +0200 Subject: [PATCH 01/13] add yarn build to sandbox.sh --- bin/sandbox.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/sandbox.sh b/bin/sandbox.sh index 31e53fdf14d..67c08885f65 100755 --- a/bin/sandbox.sh +++ b/bin/sandbox.sh @@ -57,9 +57,9 @@ cat <> Gemfile gem 'spree', path: '..' gem 'spree_emails', path: '../emails' gem 'spree_sample', path: '../sample' +$SPREE_GATEWAY_GEM $SPREE_BACKEND_GEM $SPREE_AUTH_DEVISE_GEM -$SPREE_GATEWAY_GEM gem 'spree_i18n', github: 'spree-contrib/spree_i18n', branch: 'main' group :test, :development do From 17660099fbe8e4779e2e1c61f0b6bac5bed6462f Mon Sep 17 00:00:00 2001 From: aryt Date: Fri, 15 Jul 2022 14:42:49 +0200 Subject: [PATCH 02/13] Add mobility gem and basic usage for products --- core/app/models/spree/product.rb | 15 +++ core/config/initializers/mobility.rb | 118 ++++++++++++++++++ core/config/locales/en.yml | 1 + ...translations_for_mobility_table_backend.rb | 19 +++ ...translations_for_mobility_table_backend.rb | 7 ++ ...120222_change_product_name_null_to_true.rb | 5 + core/lib/spree/core.rb | 1 + core/spree_core.gemspec | 1 + sample/lib/spree_sample.rb | 1 + 9 files changed, 168 insertions(+) create mode 100644 core/config/initializers/mobility.rb create mode 100644 core/db/migrate/20220706112554_create_product_name_and_description_translations_for_mobility_table_backend.rb create mode 100644 core/db/migrate/20220715083542_create_spree_product_meta_description_and_meta_keywords_and_meta_title_translations_for_mobility_table_backend.rb create mode 100644 core/db/migrate/20220715120222_change_product_name_null_to_true.rb diff --git a/core/app/models/spree/product.rb b/core/app/models/spree/product.rb index e4983fe0c34..ef67c5819fc 100644 --- a/core/app/models/spree/product.rb +++ b/core/app/models/spree/product.rb @@ -21,6 +21,7 @@ module Spree class Product < Spree::Base extend FriendlyId + extend Mobility include ProductScopes include MultiStoreResource include MemoizedData @@ -41,6 +42,8 @@ class Product < Spree::Base acts_as_paranoid auto_strip_attributes :name + translates :name, :description, :meta_description, :meta_keywords, :meta_title, backend: :table + # we need to have this callback before any dependent: :destroy associations # https://github.com/rails/rails/issues/3458 before_destroy :ensure_not_in_complete_orders @@ -168,6 +171,18 @@ class Product < Spree::Base after_transition to: :draft, do: :after_draft end + def translatable_fields + #TODO I think better solution is to implement get_translatable_fields in mobility gem(?) + %w[name description meta_description meta_keywords meta_title] + end + + def get_field_with_locale(locale, field_name) + I18n.with_locale(locale) do + #Remove fallback: false if you want to see fallbacks at the table + public_send(field_name, fallback: false) + end + end + # Can't use short form block syntax due to https://github.com/Netflix/fast_jsonapi/issues/259 def purchasable? default_variant.purchasable? || variants.any?(&:purchasable?) diff --git a/core/config/initializers/mobility.rb b/core/config/initializers/mobility.rb new file mode 100644 index 00000000000..f9acb2f39ba --- /dev/null +++ b/core/config/initializers/mobility.rb @@ -0,0 +1,118 @@ +Mobility.configure do + # PLUGINS + plugins do + # Backend + # + # Sets the default backend to use in models. This can be overridden in models + # by passing +backend: ...+ to +translates+. + # + # To default to a different backend globally, replace +:key_value+ by another + # backend name. + # + backend :table + fallbacks + locale_accessors + + # ActiveRecord + # + # Defines ActiveRecord as ORM, and enables ActiveRecord-specific plugins. + active_record + + # Accessors + # + # Define reader and writer methods for translated attributes. Remove either + # to disable globally, or pass +reader: false+ or +writer: false+ to + # +translates+ in any translated model. + # + reader + writer + + # Backend Reader + # + # Defines reader to access the backend for any attribute, of the form + # +_backend+. + # + backend_reader + # + # Or pass an interpolation string to define a different pattern: + # backend_reader "%s_translations" + + # Query + # + # Defines a scope on the model class which allows querying on + # translated attributes. The default scope is named +i18n+, pass a different + # name as default to change the global default, or to +translates+ in any + # model to change it for that model alone. + # + query + + # Cache + # + # Comment out to disable caching reads and writes. + # + cache + + # Dirty + # + # Uncomment this line to include and enable globally: + # dirty + # + # Or uncomment this line to include but disable by default, and only enable + # per model by passing +dirty: true+ to +translates+. + # dirty false + + # Fallbacks + # + # Uncomment line below to enable fallbacks, using +I18n.fallbacks+. + # fallbacks + # + # Or uncomment this line to enable fallbacks with a global default. + # fallbacks { :pt => :en } + + # Presence + # + # Converts blank strings to nil on reads and writes. Comment out to + # disable. + # + presence + + # Default + # + # Set a default translation per attributes. When enabled, passing +default: + # 'foo'+ sets a default translation string to show in case no translation is + # present. Can also be passed a proc. + # + # default 'foo' + + # Fallthrough Accessors + # + # Uses method_missing to define locale-specific accessor methods like + # +title_en+, +title_en=+, +title_fr+, +title_fr=+ for each translated + # attribute. If you know what set of locales you want to support, it's + # generally better to use Locale Accessors (or both together) since + # +method_missing+ is very slow. (You can use both fallthrough and locale + # accessor plugins together without conflict.) + # + # fallthrough_accessors + + # Locale Accessors + # + # Uses +def+ to define accessor methods for a set of locales. By default uses + # +I18n.available_locales+, but you can pass the set of locales with + # +translates+ and/or set a global default here. + # + # locale_accessors + # + # Or define specific defaults by uncommenting line below + # locale_accessors [:en, :ja] + + # Attribute Methods + # + # Adds translated attributes to +attributes+ hash, and defines methods + # +translated_attributes+ and +untranslated_attributes+ which return hashes + # with translated and untranslated attributes, respectively. Be aware that + # this plugin can create conflicts with other gems. + # + # attribute_methods + end +end diff --git a/core/config/locales/en.yml b/core/config/locales/en.yml index db521ee52d8..6e73298ae8b 100644 --- a/core/config/locales/en.yml +++ b/core/config/locales/en.yml @@ -1112,6 +1112,7 @@ en: notice_messages: icon_removed: Image has been successfully removed prices_saved: Prices successfully saved + translations_saved: Translations successfully saved product_cloned: Product has been cloned product_deleted: Product has been deleted product_not_cloned: "Product could not be cloned. Reason: %{error}" diff --git a/core/db/migrate/20220706112554_create_product_name_and_description_translations_for_mobility_table_backend.rb b/core/db/migrate/20220706112554_create_product_name_and_description_translations_for_mobility_table_backend.rb new file mode 100644 index 00000000000..e408ede1a1c --- /dev/null +++ b/core/db/migrate/20220706112554_create_product_name_and_description_translations_for_mobility_table_backend.rb @@ -0,0 +1,19 @@ +class CreateProductNameAndDescriptionTranslationsForMobilityTableBackend < ActiveRecord::Migration[7.0] + def change + create_table :spree_product_translations do |t| + + # Translated attribute(s) + t.string :name + t.text :description + + t.string :locale, null: false + t.references :spree_product, null: false, foreign_key: true, index: false + + t.timestamps null: false + end + + add_index :spree_product_translations, :locale, name: :index_spree_product_translations_on_locale + add_index :spree_product_translations, [:spree_product_id, :locale], name: :index_89f757462683439a75913375358673bb7f45ebe0, unique: true + + end +end diff --git a/core/db/migrate/20220715083542_create_spree_product_meta_description_and_meta_keywords_and_meta_title_translations_for_mobility_table_backend.rb b/core/db/migrate/20220715083542_create_spree_product_meta_description_and_meta_keywords_and_meta_title_translations_for_mobility_table_backend.rb new file mode 100644 index 00000000000..b9dd10892b5 --- /dev/null +++ b/core/db/migrate/20220715083542_create_spree_product_meta_description_and_meta_keywords_and_meta_title_translations_for_mobility_table_backend.rb @@ -0,0 +1,7 @@ +class CreateSpreeProductMetaDescriptionAndMetaKeywordsAndMetaTitleTranslationsForMobilityTableBackend < ActiveRecord::Migration[7.0] + def change + add_column :spree_product_translations, :meta_description, :text + add_column :spree_product_translations, :meta_keywords, :string + add_column :spree_product_translations, :meta_title, :string + end +end diff --git a/core/db/migrate/20220715120222_change_product_name_null_to_true.rb b/core/db/migrate/20220715120222_change_product_name_null_to_true.rb new file mode 100644 index 00000000000..726a922cf4c --- /dev/null +++ b/core/db/migrate/20220715120222_change_product_name_null_to_true.rb @@ -0,0 +1,5 @@ +class ChangeProductNameNullToTrue < ActiveRecord::Migration[7.0] + def change + change_column_null :spree_products, :name, true + end +end diff --git a/core/lib/spree/core.rb b/core/lib/spree/core.rb index 5c2e02af035..03947eb26b6 100644 --- a/core/lib/spree/core.rb +++ b/core/lib/spree/core.rb @@ -13,6 +13,7 @@ require 'friendly_id' require 'kaminari' require 'monetize' +require 'mobility' require 'paranoia' require 'ruby-vips' require 'ransack' diff --git a/core/spree_core.gemspec b/core/spree_core.gemspec index c8f197ec06c..c3f5bb6da38 100644 --- a/core/spree_core.gemspec +++ b/core/spree_core.gemspec @@ -54,4 +54,5 @@ Gem::Specification.new do |s| s.add_dependency 'image_processing', '~> 1.2' s.add_dependency 'active_storage_validations', '~> 0.9', '<= 0.9.5' s.add_dependency 'activerecord-typedstore' + s.add_dependency 'mobility', '~> 1.2.9' end diff --git a/sample/lib/spree_sample.rb b/sample/lib/spree_sample.rb index 4421947d90d..ff014991b53 100644 --- a/sample/lib/spree_sample.rb +++ b/sample/lib/spree_sample.rb @@ -5,6 +5,7 @@ module SpreeSample class Engine < Rails::Engine engine_name 'spree_sample' + config.active_record.yaml_column_permitted_classes = [Symbol] # Needs to be here so we can access it inside the tests def self.load_samples Spree::Sample.load_sample('addresses') From 28d8a2c070f511bf2b7fa645aae3189b592a1181 Mon Sep 17 00:00:00 2001 From: aryt Date: Mon, 18 Jul 2022 09:49:11 +0200 Subject: [PATCH 03/13] fix spree_sample::load --- sample/db/samples/orders.rb | 4 ++-- sample/db/samples/promotions.rb | 2 +- sample/db/samples/stock.rb | 4 ++-- sample/db/samples/variants.rb | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sample/db/samples/orders.rb b/sample/db/samples/orders.rb index 534e3738fdd..0c3eb3b6eb3 100644 --- a/sample/db/samples/orders.rb +++ b/sample/db/samples/orders.rb @@ -1,8 +1,8 @@ Spree::Sample.load_sample('addresses') Spree::Sample.load_sample('products') -product_1 = Spree::Product.find_by!(name: 'Denim Shirt') -product_2 = Spree::Product.find_by!(name: 'Checked Shirt') +product_1 = Spree::Product.i18n.find_by!(name: 'Denim Shirt') +product_2 = Spree::Product.i18n.find_by!(name: 'Checked Shirt') orders = [] orders << Spree::Order.where( diff --git a/sample/db/samples/promotions.rb b/sample/db/samples/promotions.rb index ecc0fe4233b..452331c0c9e 100644 --- a/sample/db/samples/promotions.rb +++ b/sample/db/samples/promotions.rb @@ -2,7 +2,7 @@ Spree::Sample.load_sample('option_values') Spree::Sample.load_sample('products') -product = Spree::Product.find_by!(name: 'Denim Shirt') +product = Spree::Product.i18n.find_by!(name: 'Denim Shirt') size = Spree::OptionValue.find_by!(name: 'xs') color = Spree::OptionValue.find_by!(name: 'red') eligible_values = "#{size.id},#{color.id}" diff --git a/sample/db/samples/stock.rb b/sample/db/samples/stock.rb index 4e8c7656440..0669b14e4cb 100644 --- a/sample/db/samples/stock.rb +++ b/sample/db/samples/stock.rb @@ -13,8 +13,8 @@ Spree::StockLocations::StockItems::Create.call(stock_location: location) -product_1 = Spree::Product.find_by!(name: 'Denim Shirt') -product_2 = Spree::Product.find_by!(name: 'Checked Shirt') +product_1 = Spree::Product.i18n.find_by!(name: 'Denim Shirt') +product_2 = Spree::Product.i18n.find_by!(name: 'Checked Shirt') location.stock_item_or_create(product_1.master).update(count_on_hand: 1) location.stock_item_or_create(product_2.master).update(count_on_hand: 1) diff --git a/sample/db/samples/variants.rb b/sample/db/samples/variants.rb index f5788f8cbe5..a1c91fbbc79 100644 --- a/sample/db/samples/variants.rb +++ b/sample/db/samples/variants.rb @@ -14,7 +14,7 @@ VARIANTS.each do |(parent_name, taxon_name, product_name, color_name)| parent = Spree::Taxon.find_by!(name: parent_name) taxon = parent.children.find_by!(name: taxon_name) - product = Spree::Product.find_by!(name: product_name.titleize) + product = Spree::Product.i18n.find_by!(name: product_name.titleize) color = color_option_values.find_by!(name: color_name) size_option_values.each do |size| From 4bee9d14c4b90b14d0cef0a7a940bd4f7adfc85d Mon Sep 17 00:00:00 2001 From: aryt Date: Wed, 20 Jul 2022 11:46:38 +0200 Subject: [PATCH 04/13] Add translations for taxons, fix loading taxons with spree_sample --- core/app/models/spree/taxon.rb | 16 +++++++++++++++- ...translations_for_mobility_table_backend.rb | 19 +++++++++++++++++++ ...18100948_change_taxon_name_null_to_true.rb | 5 +++++ sample/db/samples/product_properties.rb | 7 +++---- sample/db/samples/products.rb | 6 +++--- sample/db/samples/taxons.rb | 10 +++++++--- sample/db/samples/variants.rb | 4 ++-- 7 files changed, 54 insertions(+), 13 deletions(-) create mode 100644 core/db/migrate/20220718100743_create_spree_taxon_name_and_description_translations_for_mobility_table_backend.rb create mode 100644 core/db/migrate/20220718100948_change_taxon_name_null_to_true.rb diff --git a/core/app/models/spree/taxon.rb b/core/app/models/spree/taxon.rb index 677657d584f..b1840c334ae 100644 --- a/core/app/models/spree/taxon.rb +++ b/core/app/models/spree/taxon.rb @@ -3,6 +3,7 @@ module Spree class Taxon < Spree::Base + extend Mobility include Metadata if defined?(Spree::Webhooks) include Spree::Webhooks::HasWebhooks @@ -14,6 +15,8 @@ class Taxon < Spree::Base acts_as_nested_set dependent: :destroy + translates :name, :description, backend: :table + belongs_to :taxonomy, class_name: 'Spree::Taxonomy', inverse_of: :taxons has_many :classifications, -> { order(:position) }, dependent: :delete_all, inverse_of: :taxon has_many :products, through: :classifications @@ -27,7 +30,7 @@ class Taxon < Spree::Base has_many :promotion_rule_taxons, class_name: 'Spree::PromotionRuleTaxon', dependent: :destroy has_many :promotion_rules, through: :promotion_rule_taxons, class_name: 'Spree::PromotionRule' - validates :name, presence: true, uniqueness: { scope: [:parent_id, :taxonomy_id], allow_blank: true, case_sensitive: false } + validates :name, presence: false, uniqueness: { scope: [:parent_id, :taxonomy_id], allow_blank: true, case_sensitive: false } validates :taxonomy, presence: true validates :permalink, uniqueness: { case_sensitive: false, scope: [:parent_id, :taxonomy_id] } validates :hide_from_nav, inclusion: { in: [true, false] } @@ -54,6 +57,17 @@ class Taxon < Spree::Base scope :for_stores, ->(stores) { joins(:taxonomy).where(spree_taxonomies: { store_id: stores.ids }) } + def translatable_fields + %w[name description] + end + + def get_field_with_locale(locale, field_name) + I18n.with_locale(locale) do + #Remove fallback: false if you want to see fallbacks at the table + public_send(field_name, fallback: false) + end + end + # indicate which filters should be used for a taxon # this method should be customized to your own site def applicable_filters diff --git a/core/db/migrate/20220718100743_create_spree_taxon_name_and_description_translations_for_mobility_table_backend.rb b/core/db/migrate/20220718100743_create_spree_taxon_name_and_description_translations_for_mobility_table_backend.rb new file mode 100644 index 00000000000..0d8c1aeb0a8 --- /dev/null +++ b/core/db/migrate/20220718100743_create_spree_taxon_name_and_description_translations_for_mobility_table_backend.rb @@ -0,0 +1,19 @@ +class CreateSpreeTaxonNameAndDescriptionTranslationsForMobilityTableBackend < ActiveRecord::Migration[7.0] + def change + create_table :spree_taxon_translations do |t| + + # Translated attribute(s) + t.string :name + t.text :description + + t.string :locale, null: false + t.references :spree_taxon, null: false, foreign_key: true, index: false + + t.timestamps null: false + end + + add_index :spree_taxon_translations, :locale, name: :index_spree_taxon_translations_on_locale + add_index :spree_taxon_translations, [:spree_taxon_id, :locale], name: :index_spree_taxon_translations_on_spree_taxon_id_and_locale, unique: true + + end +end diff --git a/core/db/migrate/20220718100948_change_taxon_name_null_to_true.rb b/core/db/migrate/20220718100948_change_taxon_name_null_to_true.rb new file mode 100644 index 00000000000..632325bd29b --- /dev/null +++ b/core/db/migrate/20220718100948_change_taxon_name_null_to_true.rb @@ -0,0 +1,5 @@ +class ChangeTaxonNameNullToTrue < ActiveRecord::Migration[7.0] + def change + change_column_null :spree_taxons, :name, true + end +end diff --git a/sample/db/samples/product_properties.rb b/sample/db/samples/product_properties.rb index ac603d68b44..5210ece4154 100644 --- a/sample/db/samples/product_properties.rb +++ b/sample/db/samples/product_properties.rb @@ -43,8 +43,7 @@ 'gender' => 'Men\'s' } ] - -Spree::Taxon.find_by!(name: 'Men').children.find_by!(name: 'T-shirts').products.each do |product| +Spree::Taxon.i18n.find_by!(name: 'Men').children.i18n.find_by!(name: 'T-shirts').products.each do |product| men_tshirts_properties.sample.each do |prop_name, prop_value| product.set_property(prop_name, prop_value, prop_name.gsub('_', ' ').capitalize) end @@ -73,7 +72,7 @@ } ] -Spree::Taxon.find_by!(name: 'Women').children.find_by!(name: 'Tops and T-shirts').products.each do |product| +Spree::Taxon.i18n.find_by!(name: 'Women').children.i18n.find_by!(name: 'Tops and T-shirts').products.each do |product| women_tshirts_properties.sample.each do |prop_name, prop_value| product.set_property(prop_name, prop_value, prop_name.gsub('_', ' ').capitalize) end @@ -86,7 +85,7 @@ fits: %w[Form Lose] } -t_shirts_taxon = Spree::Taxon.where(name: ['T-shirts', 'Tops and T-shirts']) +t_shirts_taxon = Spree::Taxon.i18n.where(name: ['T-shirts', 'Tops and T-shirts']) Spree::Product.all.each do |product| product.set_property(:type, product.taxons.first.name) diff --git a/sample/db/samples/products.rb b/sample/db/samples/products.rb index 7beac2b2fdb..f77cb471de5 100644 --- a/sample/db/samples/products.rb +++ b/sample/db/samples/products.rb @@ -17,8 +17,8 @@ end.uniq PRODUCTS.each do |(parent_name, taxon_name, product_name)| - parent = Spree::Taxon.find_by!(name: parent_name) - taxon = parent.children.find_by!(name: taxon_name) + parent = Spree::Taxon.i18n.find_by!(name: parent_name) + taxon = parent.children.i18n.find_by!(name: taxon_name) Spree::Product.where(name: product_name.titleize).first_or_create! do |product| product.price = rand(10...100) + 0.99 product.description = FFaker::Lorem.paragraph @@ -39,7 +39,7 @@ end end -Spree::Taxon.where(name: ['Bestsellers', 'New', 'Trending', 'Streetstyle', 'Summer Sale', "Summer #{Date.today.year}", '30% Off']).each do |taxon| +Spree::Taxon.i18n.where(name: ['Bestsellers', 'New', 'Trending', 'Streetstyle', 'Summer Sale', "Summer #{Date.today.year}", '30% Off']).each do |taxon| next if taxon.products.any? taxon.products << Spree::Product.all.sample(30) diff --git a/sample/db/samples/taxons.rb b/sample/db/samples/taxons.rb index 40bcf624751..8d3511c14ca 100644 --- a/sample/db/samples/taxons.rb +++ b/sample/db/samples/taxons.rb @@ -13,16 +13,20 @@ TAXON_NAMES = CHILDREN_TAXON_NAMES.map { |(parent_name, taxon_name)| parent_name } categories = Spree::Taxonomy.find_by!(name: I18n.t('spree.taxonomy_categories_name')) -categories_taxon = Spree::Taxon.where(name: I18n.t('spree.taxonomy_categories_name')).first_or_create! +categories_taxon = Spree::Taxon.i18n.where(name: I18n.t('spree.taxonomy_categories_name')).first_or_create! TAXON_NAMES.each do |taxon_name| - taxon = categories_taxon.children.where(name: taxon_name).first_or_create! + if not categories_taxon.children.i18n.where(name: taxon_name).exists? + taxon = categories_taxon.children.where(name: taxon_name).create! + else + taxon = categories_taxon.children.i18n.where(name: taxon_name).first + end taxon.taxonomy = categories taxon.save! end CHILDREN_TAXON_NAMES.each do |(parent_name, taxon_name)| - parent = Spree::Taxon.where(name: parent_name).first + parent = Spree::Taxon.i18n.where(name: parent_name).first taxon = parent.children.where(name: taxon_name).first_or_create! taxon.taxonomy = categories taxon.save! diff --git a/sample/db/samples/variants.rb b/sample/db/samples/variants.rb index a1c91fbbc79..603798ca0d9 100644 --- a/sample/db/samples/variants.rb +++ b/sample/db/samples/variants.rb @@ -12,8 +12,8 @@ size_option_values = Spree::OptionType.find_by!(name: 'size').option_values VARIANTS.each do |(parent_name, taxon_name, product_name, color_name)| - parent = Spree::Taxon.find_by!(name: parent_name) - taxon = parent.children.find_by!(name: taxon_name) + parent = Spree::Taxon.i18n.find_by!(name: parent_name) + taxon = parent.children.i18n.find_by!(name: taxon_name) product = Spree::Product.i18n.find_by!(name: product_name.titleize) color = color_option_values.find_by!(name: color_name) From 66d128fd7e19142034de590a1e1d728639a252b7 Mon Sep 17 00:00:00 2001 From: aryt Date: Wed, 20 Jul 2022 15:43:40 +0200 Subject: [PATCH 05/13] Permit :locale as param --- api/app/helpers/spree/api/v2/collection_options_helpers.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/app/helpers/spree/api/v2/collection_options_helpers.rb b/api/app/helpers/spree/api/v2/collection_options_helpers.rb index 768313af084..a39157739ce 100644 --- a/api/app/helpers/spree/api/v2/collection_options_helpers.rb +++ b/api/app/helpers/spree/api/v2/collection_options_helpers.rb @@ -23,7 +23,7 @@ def collection_meta(collection) # leaving this method in public scope so it's still possible to modify # those params to support non-standard non-JSON API parameters def collection_permitted_params - params.permit(:format, :page, :per_page, :sort, :include, fields: {}, filter: {}) + params.permit(:format, :page, :per_page, :sort, :include, :locale, fields: {}, filter: {}) end private From 0d34d842a5d192638c1530677285ae135da1f2aa Mon Sep 17 00:00:00 2001 From: aryt Date: Fri, 22 Jul 2022 15:05:34 +0200 Subject: [PATCH 06/13] Add mobility ransack and join translations table for taxons --- .../spree/api/v2/platform/taxons_controller.rb | 2 +- .../translatable_resource_controller.rb | 18 ++++++++++++++++++ .../models/concerns/spree/product_scopes.rb | 2 ++ core/app/models/spree/product.rb | 2 +- core/config/initializers/mobility.rb | 2 ++ core/spree_core.gemspec | 1 + 6 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 api/app/controllers/spree/api/v2/platform/translatable_resource_controller.rb diff --git a/api/app/controllers/spree/api/v2/platform/taxons_controller.rb b/api/app/controllers/spree/api/v2/platform/taxons_controller.rb index 9ac17f4b5dd..6f9d39d1da9 100644 --- a/api/app/controllers/spree/api/v2/platform/taxons_controller.rb +++ b/api/app/controllers/spree/api/v2/platform/taxons_controller.rb @@ -2,7 +2,7 @@ module Spree module Api module V2 module Platform - class TaxonsController < ResourceController + class TaxonsController < TranslatableResourceController include ::Spree::Api::V2::Platform::NestedSetRepositionConcern private diff --git a/api/app/controllers/spree/api/v2/platform/translatable_resource_controller.rb b/api/app/controllers/spree/api/v2/platform/translatable_resource_controller.rb new file mode 100644 index 00000000000..c39c864abf6 --- /dev/null +++ b/api/app/controllers/spree/api/v2/platform/translatable_resource_controller.rb @@ -0,0 +1,18 @@ +module Spree + module Api + module V2 + module Platform + class TranslatableResourceController < ResourceController + + def scope + base_scope = super + base_scope = base_scope.joins(:translations) + base_scope + end + end + end + end + end +end + + diff --git a/core/app/models/concerns/spree/product_scopes.rb b/core/app/models/concerns/spree/product_scopes.rb index 4db73faaf84..9a807d00eff 100644 --- a/core/app/models/concerns/spree/product_scopes.rb +++ b/core/app/models/concerns/spree/product_scopes.rb @@ -305,6 +305,8 @@ def self.for_user(user = nil) def self.search_by_name(query) if defined?(SpreeGlobalize) joins(:translations).order(:name).where("LOWER(#{Product::Translation.table_name}.name) LIKE LOWER(:query)", query: "%#{query}%").distinct + elsif defined?(Mobility) + where("LOWER(#{Product::Translation.table_name}.name) LIKE LOWER(:query)", query: "%#{query}%") else where("LOWER(#{Product.table_name}.name) LIKE LOWER(:query)", query: "%#{query}%") end diff --git a/core/app/models/spree/product.rb b/core/app/models/spree/product.rb index ef67c5819fc..6c61ffb9aa9 100644 --- a/core/app/models/spree/product.rb +++ b/core/app/models/spree/product.rb @@ -42,7 +42,7 @@ class Product < Spree::Base acts_as_paranoid auto_strip_attributes :name - translates :name, :description, :meta_description, :meta_keywords, :meta_title, backend: :table + translates :name, :description, :meta_description, :meta_keywords, :meta_title, backend: :table # we need to have this callback before any dependent: :destroy associations # https://github.com/rails/rails/issues/3458 diff --git a/core/config/initializers/mobility.rb b/core/config/initializers/mobility.rb index f9acb2f39ba..3be6d1b6ac4 100644 --- a/core/config/initializers/mobility.rb +++ b/core/config/initializers/mobility.rb @@ -1,6 +1,8 @@ Mobility.configure do # PLUGINS plugins do + # Ransack plugin + ransack # Backend # # Sets the default backend to use in models. This can be overridden in models diff --git a/core/spree_core.gemspec b/core/spree_core.gemspec index c3f5bb6da38..0f14fa9c4f8 100644 --- a/core/spree_core.gemspec +++ b/core/spree_core.gemspec @@ -55,4 +55,5 @@ Gem::Specification.new do |s| s.add_dependency 'active_storage_validations', '~> 0.9', '<= 0.9.5' s.add_dependency 'activerecord-typedstore' s.add_dependency 'mobility', '~> 1.2.9' + s.add_dependency 'mobility-ransack', '~> 1.2.0' end From a29482a0910552de3cc7b393a9affb072cccb58f Mon Sep 17 00:00:00 2001 From: adrianryt Date: Mon, 25 Jul 2022 13:05:48 +0200 Subject: [PATCH 07/13] fix ransack sorting --- core/app/models/concerns/spree/product_scopes.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/app/models/concerns/spree/product_scopes.rb b/core/app/models/concerns/spree/product_scopes.rb index 9a807d00eff..30c59d63b77 100644 --- a/core/app/models/concerns/spree/product_scopes.rb +++ b/core/app/models/concerns/spree/product_scopes.rb @@ -306,7 +306,7 @@ def self.search_by_name(query) if defined?(SpreeGlobalize) joins(:translations).order(:name).where("LOWER(#{Product::Translation.table_name}.name) LIKE LOWER(:query)", query: "%#{query}%").distinct elsif defined?(Mobility) - where("LOWER(#{Product::Translation.table_name}.name) LIKE LOWER(:query)", query: "%#{query}%") + i18n.order(name: :asc).where("LOWER(#{Product::Translation.table_name}.name) LIKE LOWER(:query)", query: "%#{query}%") else where("LOWER(#{Product.table_name}.name) LIKE LOWER(:query)", query: "%#{query}%") end From 400352382aa0db7e67b0bb8bcb5932939d18733f Mon Sep 17 00:00:00 2001 From: adrianryt Date: Tue, 26 Jul 2022 12:39:14 +0200 Subject: [PATCH 08/13] Downgrade mobility-ransack to 1.0.1 --- core/app/models/concerns/spree/product_scopes.rb | 2 +- core/spree_core.gemspec | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/core/app/models/concerns/spree/product_scopes.rb b/core/app/models/concerns/spree/product_scopes.rb index 30c59d63b77..9a807d00eff 100644 --- a/core/app/models/concerns/spree/product_scopes.rb +++ b/core/app/models/concerns/spree/product_scopes.rb @@ -306,7 +306,7 @@ def self.search_by_name(query) if defined?(SpreeGlobalize) joins(:translations).order(:name).where("LOWER(#{Product::Translation.table_name}.name) LIKE LOWER(:query)", query: "%#{query}%").distinct elsif defined?(Mobility) - i18n.order(name: :asc).where("LOWER(#{Product::Translation.table_name}.name) LIKE LOWER(:query)", query: "%#{query}%") + where("LOWER(#{Product::Translation.table_name}.name) LIKE LOWER(:query)", query: "%#{query}%") else where("LOWER(#{Product.table_name}.name) LIKE LOWER(:query)", query: "%#{query}%") end diff --git a/core/spree_core.gemspec b/core/spree_core.gemspec index 0f14fa9c4f8..73c53632fe3 100644 --- a/core/spree_core.gemspec +++ b/core/spree_core.gemspec @@ -55,5 +55,6 @@ Gem::Specification.new do |s| s.add_dependency 'active_storage_validations', '~> 0.9', '<= 0.9.5' s.add_dependency 'activerecord-typedstore' s.add_dependency 'mobility', '~> 1.2.9' - s.add_dependency 'mobility-ransack', '~> 1.2.0' + # Upgrade mobility-ransack version to 1.2.0 after this issue is resolved + s.add_dependency 'mobility-ransack', '~> 1.0.1' end From eb1d96c50e387c969ee0dbb74953810ed2ffa0fd Mon Sep 17 00:00:00 2001 From: adrianryt Date: Tue, 2 Aug 2022 13:21:48 +0200 Subject: [PATCH 09/13] Add friendly_id-mobility gem and translatable slugs --- core/app/models/spree/product.rb | 6 +++--- core/config/initializers/mobility.rb | 2 +- .../20220802070609_add_locale_to_friendly_id_slugs.rb | 11 +++++++++++ ...ct_slug_translations_for_mobility_table_backend.rb | 5 +++++ core/spree_core.gemspec | 1 + 5 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 core/db/migrate/20220802070609_add_locale_to_friendly_id_slugs.rb create mode 100644 core/db/migrate/20220802073225_create_spree_product_slug_translations_for_mobility_table_backend.rb diff --git a/core/app/models/spree/product.rb b/core/app/models/spree/product.rb index 6c61ffb9aa9..6238400bfbd 100644 --- a/core/app/models/spree/product.rb +++ b/core/app/models/spree/product.rb @@ -37,12 +37,12 @@ class Product < Spree::Base default_variant_id tax_category default_variant purchasable? in_stock? backorderable?) - friendly_id :slug_candidates, use: :history + friendly_id :slug_candidates, use: [:history, :mobility] acts_as_paranoid auto_strip_attributes :name - translates :name, :description, :meta_description, :meta_keywords, :meta_title, backend: :table + translates :name, :description, :slug, :meta_description, :meta_keywords, :meta_title, backend: :table # we need to have this callback before any dependent: :destroy associations # https://github.com/rails/rails/issues/3458 @@ -173,7 +173,7 @@ class Product < Spree::Base def translatable_fields #TODO I think better solution is to implement get_translatable_fields in mobility gem(?) - %w[name description meta_description meta_keywords meta_title] + %w[name description slug meta_description meta_keywords meta_title] end def get_field_with_locale(locale, field_name) diff --git a/core/config/initializers/mobility.rb b/core/config/initializers/mobility.rb index 3be6d1b6ac4..2fce51e0965 100644 --- a/core/config/initializers/mobility.rb +++ b/core/config/initializers/mobility.rb @@ -57,7 +57,7 @@ # Dirty # # Uncomment this line to include and enable globally: - # dirty + dirty # # Or uncomment this line to include but disable by default, and only enable # per model by passing +dirty: true+ to +translates+. diff --git a/core/db/migrate/20220802070609_add_locale_to_friendly_id_slugs.rb b/core/db/migrate/20220802070609_add_locale_to_friendly_id_slugs.rb new file mode 100644 index 00000000000..bedde9a8f9e --- /dev/null +++ b/core/db/migrate/20220802070609_add_locale_to_friendly_id_slugs.rb @@ -0,0 +1,11 @@ +class AddLocaleToFriendlyIdSlugs < ActiveRecord::Migration[7.0] + def change + add_column :friendly_id_slugs, :locale, :string, null: :false, after: :scope + + remove_index :friendly_id_slugs, [:slug, :sluggable_type] + add_index :friendly_id_slugs, [:slug, :sluggable_type, :locale], length: { slug: 140, sluggable_type: 50, locale: 2 } + remove_index :friendly_id_slugs, [:slug, :sluggable_type, :scope] + add_index :friendly_id_slugs, [:slug, :sluggable_type, :scope, :locale], length: { slug: 70, sluggable_type: 50, scope: 70, locale: 2 }, unique: true, name: :index_friendly_id_slugs_unique + add_index :friendly_id_slugs, :locale + end +end diff --git a/core/db/migrate/20220802073225_create_spree_product_slug_translations_for_mobility_table_backend.rb b/core/db/migrate/20220802073225_create_spree_product_slug_translations_for_mobility_table_backend.rb new file mode 100644 index 00000000000..abe416d790c --- /dev/null +++ b/core/db/migrate/20220802073225_create_spree_product_slug_translations_for_mobility_table_backend.rb @@ -0,0 +1,5 @@ +class CreateSpreeProductSlugTranslationsForMobilityTableBackend < ActiveRecord::Migration[7.0] + def change + add_column :spree_product_translations, :slug, :string + end +end diff --git a/core/spree_core.gemspec b/core/spree_core.gemspec index 73c53632fe3..57a37a7523b 100644 --- a/core/spree_core.gemspec +++ b/core/spree_core.gemspec @@ -57,4 +57,5 @@ Gem::Specification.new do |s| s.add_dependency 'mobility', '~> 1.2.9' # Upgrade mobility-ransack version to 1.2.0 after this issue is resolved s.add_dependency 'mobility-ransack', '~> 1.0.1' + s.add_dependency 'friendly_id-mobility', '~> 1.0.3' end From 26ce55ff344b816d39b8a9079e11e67502cdc364 Mon Sep 17 00:00:00 2001 From: adrianryt Date: Wed, 3 Aug 2022 09:43:26 +0200 Subject: [PATCH 10/13] Small code changes connected to mobility gem --- .../api/v2/platform/translatable_resource_controller.rb | 5 +---- bin/sandbox.sh | 2 +- core/app/models/spree/product.rb | 9 +++++---- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/api/app/controllers/spree/api/v2/platform/translatable_resource_controller.rb b/api/app/controllers/spree/api/v2/platform/translatable_resource_controller.rb index c39c864abf6..24d75a06e89 100644 --- a/api/app/controllers/spree/api/v2/platform/translatable_resource_controller.rb +++ b/api/app/controllers/spree/api/v2/platform/translatable_resource_controller.rb @@ -3,11 +3,8 @@ module Api module V2 module Platform class TranslatableResourceController < ResourceController - def scope - base_scope = super - base_scope = base_scope.joins(:translations) - base_scope + super.joins(:translations) end end end diff --git a/bin/sandbox.sh b/bin/sandbox.sh index 67c08885f65..31e53fdf14d 100755 --- a/bin/sandbox.sh +++ b/bin/sandbox.sh @@ -57,9 +57,9 @@ cat <> Gemfile gem 'spree', path: '..' gem 'spree_emails', path: '../emails' gem 'spree_sample', path: '../sample' -$SPREE_GATEWAY_GEM $SPREE_BACKEND_GEM $SPREE_AUTH_DEVISE_GEM +$SPREE_GATEWAY_GEM gem 'spree_i18n', github: 'spree-contrib/spree_i18n', branch: 'main' group :test, :development do diff --git a/core/app/models/spree/product.rb b/core/app/models/spree/product.rb index 6238400bfbd..9ea673a3286 100644 --- a/core/app/models/spree/product.rb +++ b/core/app/models/spree/product.rb @@ -37,13 +37,14 @@ class Product < Spree::Base default_variant_id tax_category default_variant purchasable? in_stock? backorderable?) + TRANSLATABLE_FIELDS = %i[name description slug meta_description meta_keywords meta_title] + friendly_id :slug_candidates, use: [:history, :mobility] acts_as_paranoid auto_strip_attributes :name - translates :name, :description, :slug, :meta_description, :meta_keywords, :meta_title, backend: :table - + translates *TRANSLATABLE_FIELDS, backend: :table # we need to have this callback before any dependent: :destroy associations # https://github.com/rails/rails/issues/3458 before_destroy :ensure_not_in_complete_orders @@ -173,11 +174,11 @@ class Product < Spree::Base def translatable_fields #TODO I think better solution is to implement get_translatable_fields in mobility gem(?) - %w[name description slug meta_description meta_keywords meta_title] + TRANSLATABLE_FIELDS end def get_field_with_locale(locale, field_name) - I18n.with_locale(locale) do + Mobility.with_locale(locale) do #Remove fallback: false if you want to see fallbacks at the table public_send(field_name, fallback: false) end From 9250542f185700cf4d65ed9b539ea4c98d0bef8b Mon Sep 17 00:00:00 2001 From: adrianryt Date: Wed, 3 Aug 2022 10:50:17 +0200 Subject: [PATCH 11/13] validates taxon name presence --- core/app/models/spree/taxon.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/app/models/spree/taxon.rb b/core/app/models/spree/taxon.rb index b1840c334ae..a592cdc0668 100644 --- a/core/app/models/spree/taxon.rb +++ b/core/app/models/spree/taxon.rb @@ -30,7 +30,7 @@ class Taxon < Spree::Base has_many :promotion_rule_taxons, class_name: 'Spree::PromotionRuleTaxon', dependent: :destroy has_many :promotion_rules, through: :promotion_rule_taxons, class_name: 'Spree::PromotionRule' - validates :name, presence: false, uniqueness: { scope: [:parent_id, :taxonomy_id], allow_blank: true, case_sensitive: false } + validates :name, presence: true, uniqueness: { scope: [:parent_id, :taxonomy_id], allow_blank: true, case_sensitive: false } validates :taxonomy, presence: true validates :permalink, uniqueness: { case_sensitive: false, scope: [:parent_id, :taxonomy_id] } validates :hide_from_nav, inclusion: { in: [true, false] } From 8af9726bcacc5de29c3a3179f4000f3fefdd18ff Mon Sep 17 00:00:00 2001 From: adrianryt Date: Thu, 4 Aug 2022 12:23:33 +0200 Subject: [PATCH 12/13] Add migration for copying existing data to translatable tables --- ...28_transfer_data_to_translatable_tables.rb | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 core/db/migrate/20220804073928_transfer_data_to_translatable_tables.rb diff --git a/core/db/migrate/20220804073928_transfer_data_to_translatable_tables.rb b/core/db/migrate/20220804073928_transfer_data_to_translatable_tables.rb new file mode 100644 index 00000000000..6deadd8f820 --- /dev/null +++ b/core/db/migrate/20220804073928_transfer_data_to_translatable_tables.rb @@ -0,0 +1,30 @@ +# This migration comes from spree (originally 20220804073928) +class TransferDataToTranslatableTables < ActiveRecord::Migration[7.0] + DEFAULT_LOCALE = 'en' + PRODUCTS_TABLE = 'spree_products' + PRODUCT_TRANSLATIONS_TABLE = 'spree_product_translations' + TAXONS_TABLE = 'spree_taxons' + TAXON_TRANSLATIONS_TABLE = 'spree_taxon_translations' + + def up + # Products + ActiveRecord::Base.connection.execute(" + INSERT INTO #{PRODUCT_TRANSLATIONS_TABLE} (name, description, locale, spree_product_id, created_at, updated_at, meta_description, meta_keywords, meta_title, slug) + SELECT name, description, '#{DEFAULT_LOCALE}' as locale, id, created_at, updated_at, meta_description, meta_keywords, meta_title, slug FROM #{PRODUCTS_TABLE} + ") + #Taxons + ActiveRecord::Base.connection.execute(" + INSERT INTO #{TAXON_TRANSLATIONS_TABLE} (name, description, locale, spree_taxon_id, created_at, updated_at) + SELECT name, description, '#{DEFAULT_LOCALE}' as locale, id, created_at, updated_at FROM #{TAXONS_TABLE} + ") + end + + def down + ActiveRecord::Base.connection.execute(" + TRUNCATE TABLE #{PRODUCT_TRANSLATIONS_TABLE} + ") + ActiveRecord::Base.connection.execute(" + TRUNCATE TABLE #{TAXON_TRANSLATIONS_TABLE} + ") + end +end From 113f7aad8ad8549b669a00191084f7a20927388d Mon Sep 17 00:00:00 2001 From: adrianryt Date: Thu, 4 Aug 2022 14:02:39 +0200 Subject: [PATCH 13/13] Update tables after migrating translatable data --- ...28_transfer_data_to_translatable_tables.rb | 42 +++++++++++++++++-- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/core/db/migrate/20220804073928_transfer_data_to_translatable_tables.rb b/core/db/migrate/20220804073928_transfer_data_to_translatable_tables.rb index 6deadd8f820..9108bf29ff7 100644 --- a/core/db/migrate/20220804073928_transfer_data_to_translatable_tables.rb +++ b/core/db/migrate/20220804073928_transfer_data_to_translatable_tables.rb @@ -1,4 +1,3 @@ -# This migration comes from spree (originally 20220804073928) class TransferDataToTranslatableTables < ActiveRecord::Migration[7.0] DEFAULT_LOCALE = 'en' PRODUCTS_TABLE = 'spree_products' @@ -10,19 +9,56 @@ def up # Products ActiveRecord::Base.connection.execute(" INSERT INTO #{PRODUCT_TRANSLATIONS_TABLE} (name, description, locale, spree_product_id, created_at, updated_at, meta_description, meta_keywords, meta_title, slug) - SELECT name, description, '#{DEFAULT_LOCALE}' as locale, id, created_at, updated_at, meta_description, meta_keywords, meta_title, slug FROM #{PRODUCTS_TABLE} + SELECT name, description, '#{DEFAULT_LOCALE}' as locale, id, created_at, updated_at, meta_description, meta_keywords, meta_title, slug FROM #{PRODUCTS_TABLE} + ") + ActiveRecord::Base.connection.execute(" + UPDATE #{PRODUCTS_TABLE} + SET name=null, description=null, meta_description=null, meta_keywords=null, meta_title=null, slug=null; ") #Taxons ActiveRecord::Base.connection.execute(" INSERT INTO #{TAXON_TRANSLATIONS_TABLE} (name, description, locale, spree_taxon_id, created_at, updated_at) - SELECT name, description, '#{DEFAULT_LOCALE}' as locale, id, created_at, updated_at FROM #{TAXONS_TABLE} + SELECT name, description, '#{DEFAULT_LOCALE}' as locale, id, created_at, updated_at FROM #{TAXONS_TABLE} + ") + ActiveRecord::Base.connection.execute(" + UPDATE #{TAXONS_TABLE} + SET name=null, description=null ") end def down + ActiveRecord::Base.connection.execute(" + UPDATE #{PRODUCTS_TABLE} as products + SET (name, + description, + meta_description, + meta_keywords, + meta_title, + slug) = + (t_products.name, + t_products.description, + t_products.meta_description, + t_products.meta_keywords, + t_products.meta_title, + t_products.slug) + FROM #{PRODUCT_TRANSLATIONS_TABLE} AS t_products + WHERE t_products.spree_product_id = products.id + ") + ActiveRecord::Base.connection.execute(" TRUNCATE TABLE #{PRODUCT_TRANSLATIONS_TABLE} ") + + ActiveRecord::Base.connection.execute(" + UPDATE #{TAXONS_TABLE} as taxons + SET (name, + description) = + (t_taxons.name, + t_taxons.description) + FROM #{TAXON_TRANSLATIONS_TABLE} AS t_taxons + WHERE t_taxons.spree_taxon_id = taxons.id + ") + ActiveRecord::Base.connection.execute(" TRUNCATE TABLE #{TAXON_TRANSLATIONS_TABLE} ")