Commit 896f6f72 by Ivan Lan

Add pasting type logic

parent 6402d2ab
...@@ -4,7 +4,6 @@ class CreateActsAsPastingPastings < ActiveRecord::Migration[5.2] ...@@ -4,7 +4,6 @@ class CreateActsAsPastingPastings < ActiveRecord::Migration[5.2]
t.references :pasteable, polymorphic: true, index: { name: 'acts_as_pasting_pasteable' } t.references :pasteable, polymorphic: true, index: { name: 'acts_as_pasting_pasteable' }
t.references :pasted, polymorphic: true, index: { name: 'acts_as_pasting_pasted' } t.references :pasted, polymorphic: true, index: { name: 'acts_as_pasting_pasted' }
t.string :type, index: true t.string :type, index: true
t.string :pasting_type
t.timestamps t.timestamps
end end
......
module ActsAsPasting module Pasted
module Pasted
extend ActiveSupport::Concern extend ActiveSupport::Concern
# 带 prefix 的 pasted_with,独立于不带 prefix 的之外
included do included do
has_many :pastings, as: :pasted, class_name: 'ActsAsPasting::Pasting' has_many :pastings, as: :pasted
# ary => [[klass, id], [klass, id]] # ary => [[klass, id], [klass, id]]
# ary => [obj, obj] # ary => [obj, obj]
scope :pasted_with_any, ->(ary) { scope :pasted_with_any, ->(ary, prefix: '') {
ary = parsed_condition_ary(ary) ary = parsed_condition_ary(ary)
ary.map { |klass, id| joins(:pastings).where( ids = ary.map do |klass, id|
'acts_as_pasting_pastings.pasteable_type = ? AND acts_as_pasting_pastings.pasteable_id = ?', joins(:pastings).where(pastings: {
klass.constantize.base_class.name, id pasteable_type: klass.constantize.base_class.name, pasteable_id: id, type: prefix
) }).pluck(:id)
}.reduce(:or)&.distinct || self.none end.reduce(:|)
where(id: ids)
} }
scope :pasted_with_all, ->(ary) { scope :pasted_with_all, ->(ary, prefix: '') {
ary = parsed_condition_ary(ary) ary = parsed_condition_ary(ary)
ids = ary.map do |klass, id| ids = ary.map do |klass, id|
joins(:pastings).where(pastings: { pasteable_type: klass.constantize.base_class.name, pasteable_id: id }).pluck(:id) joins(:pastings).where(pastings: {
pasteable_type: klass.constantize.base_class.name, pasteable_id: id, type: prefix
}).pluck(:id)
end.reduce(:&) end.reduce(:&)
where(id: ids) where(id: ids)
} }
after_create :save_paste_list after_create :save_paste_list
# 不包含 带 prefix 的 pasted_with
def paste_list def paste_list
pastings.reload.map(&:pasteable) pastings.where(type: '').reload.map(&:pasteable).uniq
end end
def paste_list_for klass_name # def paste_list_for klass_name
klass_name.constantize.where( # klass_name.constantize.where(
id: pastings.where(pasteable_type: klass_name.constantize.base_class.name).pluck(:pasteable_id) # id: pastings.where(pasteable_type: klass_name.constantize.base_class.name).pluck(:pasteable_id)
) # )
end # end
def paste_list_names def paste_list_names
paste_list.map(&:name) paste_list.map(&:name)
end end
def paste_list_add obj def paste_list_add obj
pastings.create!(pasted: self, pasteable: obj) pastings.where(type: '').create!(pasted: self, pasteable: obj)
end end
def paste_list_remove obj def paste_list_remove obj
pastings.where(pasted: self, pasteable: obj).destroy_all pastings.where(type: '').where(pasted: self, pasteable: obj).destroy_all
end end
# ary => [[klass, id], [klass, id]] # ary => [[klass, id], [klass, id]]
# ary => [obj, obj] # ary => [obj, obj]
# 不包含 带 prefix 的 pasted_with
def paste_list= ary def paste_list= ary
ary = self.class.parsed_condition_ary(ary) ary = self.class.parsed_condition_ary(ary)
exist_ary = pastings.where(pasted: self).pluck(:pasteable_type, :pasteable_id) exist_ary = pastings.where(pasted: self).pluck(:pasteable_type, :pasteable_id)
...@@ -59,12 +64,14 @@ module ActsAsPasting ...@@ -59,12 +64,14 @@ module ActsAsPasting
else else
self.class.transaction do self.class.transaction do
remove_ary.each { |klass, id| pastings.where( remove_ary.each { |klass, id| pastings.where(
type: '',
pasted: self, pasted: self,
pasteable_type: klass, pasteable_type: klass,
pasteable_id: id pasteable_id: id
).destroy_all ).destroy_all
} }
add_ary.each { |klass, id| pastings.create!( add_ary.each { |klass, id| pastings.create!(
type: '',
pasted: self, pasted: self,
pasteable_type: klass, pasteable_type: klass,
pasteable_id: id pasteable_id: id
...@@ -74,16 +81,16 @@ module ActsAsPasting ...@@ -74,16 +81,16 @@ module ActsAsPasting
end end
end end
def method_missing name, *arg, &block # def method_missing name, *arg, &block
klass_downcase = /^paste_(.+)_list$/.match(name)&.[](1) # klass_downcase = /^paste_(.+)_list$/.match(name)&.[](1)
if klass_downcase # if klass_downcase
downcase_all_combination(klass_downcase).each do |str| # downcase_all_combination(klass_downcase).each do |str|
return paste_list_for(str) if correct_class_name?(str) # return paste_list_for(str) if correct_class_name?(str)
end # end
end # end
super(name, *arg, &block) # super(name, *arg, &block)
end # end
private private
...@@ -115,15 +122,20 @@ module ActsAsPasting ...@@ -115,15 +122,20 @@ module ActsAsPasting
end end
module ClassMethods module ClassMethods
def pasted_with *klasses def pasted_with *klasses, prefix: nil
klasses.each do |klass| klasses.each do |klass|
downcase = klass.name.underscore.gsub('/', '_') downcase = klass.name.underscore.gsub('/', '_')
downcase = "#{prefix}#{downcase}" if prefix
type_value = prefix ? prefix : nil
base_class_name = klass.base_class.name base_class_name = klass.base_class.name
class_eval <<-RUBY, __FILE__, __LINE__ + 1 class_eval <<-RUBY, __FILE__, __LINE__ + 1
after_create :save_paste_#{downcase}_list after_create :save_paste_#{downcase}_list
def paste_#{downcase}_list def paste_#{downcase}_list
paste_list_for("#{klass}") #{klass}.where(
id: pastings.where(type: "#{type_value}", pasteable_type: #{klass}.base_class.name).pluck(:pasteable_id)
)
end end
def paste_#{downcase}_ids= ids def paste_#{downcase}_ids= ids
...@@ -138,18 +150,22 @@ module ActsAsPasting ...@@ -138,18 +150,22 @@ module ActsAsPasting
if new_record? if new_record?
@paste_#{downcase}_list = ary @paste_#{downcase}_list = ary
else else
exist_ary = pastings.where(pasted: self, pasteable_type: "#{base_class_name}").pluck(:pasteable_type, :pasteable_id) exist_ary = pastings.where(
type: "#{type_value}", pasted: self, pasteable_type: "#{base_class_name}"
).pluck(:pasteable_type, :pasteable_id)
add_ary = ary - exist_ary add_ary = ary - exist_ary
remove_ary = exist_ary - ary remove_ary = exist_ary - ary
self.class.transaction do self.class.transaction do
remove_ary.each { |klass, id| pastings.where( remove_ary.each { |klass, id| pastings.where(
type: "#{type_value}",
pasted: self, pasted: self,
pasteable_type: klass, pasteable_type: klass,
pasteable_id: id pasteable_id: id
).destroy_all ).destroy_all
} }
add_ary.each { |klass, id| pastings.create!( add_ary.each { |klass, id| pastings.create!(
type: "#{type_value}",
pasted: self, pasted: self,
pasteable_type: klass, pasteable_type: klass,
pasteable_id: id pasteable_id: id
...@@ -171,11 +187,13 @@ module ActsAsPasting ...@@ -171,11 +187,13 @@ module ActsAsPasting
end end
def parsed_condition_ary ary def parsed_condition_ary ary
ary = ary.compact
return [] unless ary && ary.first
case ary.first case ary.first
when ActiveRecord::Base when ActiveRecord::Base
ary.map { |obj| [obj.class.base_class.name, obj.id] } ary.map { |obj| [obj.class.base_class.name, obj.id] }
when Hash when Hash
ary.map { |h| [h[:paste_type].constantize.base_class.name, h[:paste_id]] } ary.map { |h| [h[:pasted_type].constantize.base_class.name, h[:pasted_id]] }
else else
ary.map { |a| [a.first.constantize.base_class.name, a.last] } ary.map { |a| [a.first.constantize.base_class.name, a.last] }
end end
...@@ -192,5 +210,4 @@ module ActsAsPasting ...@@ -192,5 +210,4 @@ module ActsAsPasting
has_many associations, through: :pastings, source: :pasted, **options has_many associations, through: :pastings, source: :pasted, **options
end end
end end
end
end end
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
# #
module ActsAsPasting module ActsAsPasting
class Pasting < ApplicationRecord class Pasting < ApplicationRecord
self.inheritance_column = :_type_disabled
belongs_to :pasteable, polymorphic: true belongs_to :pasteable, polymorphic: true
belongs_to :pasted, polymorphic: true belongs_to :pasted, polymorphic: true
end end
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment