Commit 896f6f72 by Ivan Lan

Add pasting type logic

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