Merge pull request #5868 from luisramos0/taxonomies

[Bye bye Spree] Bring models taxon and taxonomy from spree_core
This commit is contained in:
Luis Ramos
2020-09-14 20:45:04 +01:00
committed by GitHub
7 changed files with 227 additions and 62 deletions

View File

@@ -0,0 +1,21 @@
# frozen_string_literal: true
module Spree
class Classification < ActiveRecord::Base
self.table_name = 'spree_products_taxons'
belongs_to :product, class_name: "Spree::Product", touch: true
belongs_to :taxon, class_name: "Spree::Taxon", touch: true
before_destroy :dont_destroy_if_primary_taxon
private
def dont_destroy_if_primary_taxon
return unless product.primary_taxon == taxon
errors.add :base, I18n.t(:spree_classification_primary_taxon_error, taxon: taxon.name,
product: product.name)
false
end
end
end

View File

@@ -1,15 +0,0 @@
Spree::Classification.class_eval do
belongs_to :product, class_name: "Spree::Product", touch: true
belongs_to :taxon, class_name: "Spree::Taxon", touch: true
before_destroy :dont_destroy_if_primary_taxon
private
def dont_destroy_if_primary_taxon
if product.primary_taxon == taxon
errors.add :base, I18n.t(:spree_classification_primary_taxon_error, taxon: taxon.name, product: product.name)
false
end
end
end

113
app/models/spree/taxon.rb Normal file
View File

@@ -0,0 +1,113 @@
# frozen_string_literal: true
module Spree
class Taxon < ActiveRecord::Base
acts_as_nested_set dependent: :destroy
belongs_to :taxonomy, class_name: 'Spree::Taxonomy', touch: true
has_many :classifications, dependent: :destroy
has_many :products, through: :classifications
before_create :set_permalink
validates :name, presence: true
has_attached_file :icon,
styles: { mini: '32x32>', normal: '128x128>' },
default_style: :mini,
url: '/spree/taxons/:id/:style/:basename.:extension',
path: ':rails_root/public/spree/taxons/:id/:style/:basename.:extension',
default_url: '/assets/default_taxon.png'
include Spree::Core::S3Support
supports_s3 :icon
# Indicate which filters should be used for this taxon
def applicable_filters
[]
end
# Return meta_title if set otherwise generates from root name and/or taxon name
def seo_title
if meta_title
meta_title
else
root? ? name : "#{root.name} - #{name}"
end
end
# Creates permalink based on Stringex's .to_url method
def set_permalink
if parent.present?
self.permalink = [parent.permalink, permalink_end].join('/')
elsif permalink.blank?
self.permalink = name.to_url
end
end
# For #2759
def to_param
permalink
end
def active_products
scope = products.active
scope
end
def pretty_name
ancestor_chain = ancestors.inject("") do |name, ancestor|
name += "#{ancestor.name} -> "
end
ancestor_chain + name.to_s
end
# Find all the taxons of supplied products for each enterprise, indexed by enterprise.
# Format: {enterprise_id => [taxon_id, ...]}
def self.supplied_taxons
taxons = {}
Spree::Taxon.
joins(products: :supplier).
select('spree_taxons.*, enterprises.id AS enterprise_id').
each do |t|
taxons[t.enterprise_id.to_i] ||= Set.new
taxons[t.enterprise_id.to_i] << t.id
end
taxons
end
# Find all the taxons of distributed products for each enterprise, indexed by enterprise.
# May return :all taxons (distributed in open and closed order cycles),
# or :current taxons (distributed in an open order cycle).
#
# Format: {enterprise_id => [taxon_id, ...]}
def self.distributed_taxons(which_taxons = :all)
ents_and_vars = ExchangeVariant.joins(exchange: :order_cycle).merge(Exchange.outgoing)
.select("DISTINCT variant_id, receiver_id AS enterprise_id")
ents_and_vars = ents_and_vars.merge(OrderCycle.active) if which_taxons == :current
taxons = Spree::Taxon
.select("DISTINCT spree_taxons.id, ents_and_vars.enterprise_id")
.joins(products: :variants_including_master)
.joins("
INNER JOIN (#{ents_and_vars.to_sql}) AS ents_and_vars
ON spree_variants.id = ents_and_vars.variant_id")
taxons.each_with_object({}) do |t, ts|
ts[t.enterprise_id.to_i] ||= Set.new
ts[t.enterprise_id.to_i] << t.id
end
end
private
def permalink_end
return name.to_url if permalink.blank?
permalink.split('/').last
end
end
end

View File

@@ -1,47 +0,0 @@
Spree::Taxon.class_eval do
has_many :classifications, dependent: :destroy
# Indicate which filters should be used for this taxon
def applicable_filters
fs = []
# fs << Spree::ProductFilters.distributor_filter if Spree::ProductFilters.respond_to? :distributor_filter
fs
end
# Find all the taxons of supplied products for each enterprise, indexed by enterprise.
# Format: {enterprise_id => [taxon_id, ...]}
def self.supplied_taxons
taxons = {}
Spree::Taxon.
joins(products: :supplier).
select('spree_taxons.*, enterprises.id AS enterprise_id').
each do |t|
taxons[t.enterprise_id.to_i] ||= Set.new
taxons[t.enterprise_id.to_i] << t.id
end
taxons
end
# Find all the taxons of distributed products for each enterprise, indexed by enterprise.
# May return :all taxons (distributed in open and closed order cycles),
# or :current taxons (distributed in an open order cycle).
#
# Format: {enterprise_id => [taxon_id, ...]}
def self.distributed_taxons(which_taxons = :all)
ents_and_vars = ExchangeVariant.joins(exchange: :order_cycle).merge(Exchange.outgoing)
.select("DISTINCT variant_id, receiver_id AS enterprise_id")
ents_and_vars = ents_and_vars.merge(OrderCycle.active) if which_taxons == :current
taxons = Spree::Taxon
.select("DISTINCT spree_taxons.id, ents_and_vars.enterprise_id").joins(products: :variants_including_master)
.joins("INNER JOIN (#{ents_and_vars.to_sql}) AS ents_and_vars ON spree_variants.id = ents_and_vars.variant_id")
taxons.each_with_object({}) do |t, ts|
ts[t.enterprise_id.to_i] ||= Set.new
ts[t.enterprise_id.to_i] << t.id
end
end
end

View File

@@ -0,0 +1,24 @@
# frozen_string_literal: true
module Spree
class Taxonomy < ActiveRecord::Base
validates :name, presence: true
has_many :taxons
has_one :root, -> { where parent_id: nil }, class_name: "Spree::Taxon", dependent: :destroy
after_save :set_name
default_scope -> { order("#{table_name}.position") }
private
def set_name
if root
root.update_column(:name, name)
else
self.root = Taxon.create!(taxonomy_id: id, name: name)
end
end
end
end

View File

@@ -1,7 +1,11 @@
# frozen_string_literal: true
require 'spec_helper'
module Spree
describe Taxon do
let(:taxon) { Spree::Taxon.new(name: "Ruby on Rails") }
let(:e) { create(:supplier_enterprise) }
let!(:t1) { create(:taxon) }
let!(:t2) { create(:taxon) }
@@ -46,5 +50,51 @@ module Spree
end.to change { taxon2.reload.updated_at }
end
end
context "set_permalink" do
it "should set permalink correctly when no parent present" do
taxon.set_permalink
expect(taxon.permalink).to eq "ruby-on-rails"
end
it "should support Chinese characters" do
taxon.name = "你好"
taxon.set_permalink
expect(taxon.permalink).to eq 'ni-hao'
end
context "with parent taxon" do
before do
allow(taxon).to receive_messages parent_id: 123
allow(taxon).to receive_messages parent: build(:taxon, permalink: "brands")
end
it "should set permalink correctly when taxon has parent" do
taxon.set_permalink
expect(taxon.permalink).to eq "brands/ruby-on-rails"
end
it "should set permalink correctly with existing permalink present" do
taxon.permalink = "b/rubyonrails"
taxon.set_permalink
expect(taxon.permalink).to eq "brands/rubyonrails"
end
it "should support Chinese characters" do
taxon.name = ""
taxon.set_permalink
expect(taxon.permalink).to eq "brands/wo"
end
end
end
# Regression test for Spree #2620
context "creating a child node using first_or_create" do
let(:taxonomy) { create(:taxonomy) }
it "does not error out" do
expect { taxonomy.root.children.where(name: "Some name").first_or_create }.not_to raise_error
end
end
end
end

View File

@@ -0,0 +1,19 @@
# frozen_string_literal: true
require 'spec_helper'
describe Spree::Taxonomy do
context "#destroy" do
before do
@taxonomy = create(:taxonomy)
@root_taxon = @taxonomy.root
@child_taxon = create(:taxon, taxonomy_id: @taxonomy.id, parent: @root_taxon)
end
it "should destroy all associated taxons" do
@taxonomy.destroy
expect{ Spree::Taxon.find(@root_taxon.id) }.to raise_error(ActiveRecord::RecordNotFound)
expect{ Spree::Taxon.find(@child_taxon.id) }.to raise_error(ActiveRecord::RecordNotFound)
end
end
end