Commit b1560694 by Ivan Lan

Fix name

parent 896f6f72
module Pasted module ActsAsPasting
extend ActiveSupport::Concern module Pasted
extend ActiveSupport::Concern
# 带 prefix 的 pasted_with,独立于不带 prefix 的之外
included do # 带 prefix 的 pasted_with,独立于不带 prefix 的之外
has_many :pastings, as: :pasted included do
# ary => [[klass, id], [klass, id]] has_many :pastings, as: :pasted
# ary => [obj, obj] # ary => [[klass, id], [klass, id]]
scope :pasted_with_any, ->(ary, prefix: '') { # ary => [obj, obj]
ary = parsed_condition_ary(ary) scope :pasted_with_any, ->(ary, prefix: '') {
ids = ary.map do |klass, id| ary = parsed_condition_ary(ary)
joins(:pastings).where(pastings: { ids = ary.map do |klass, id|
pasteable_type: klass.constantize.base_class.name, pasteable_id: id, type: prefix joins(:pastings).where(pastings: {
}).pluck(:id) pasteable_type: klass.constantize.base_class.name, pasteable_id: id, type: prefix
end.reduce(:|) }).pluck(:id)
where(id: ids) end.reduce(:|)
} where(id: ids)
}
scope :pasted_with_all, ->(ary, prefix: '') {
ary = parsed_condition_ary(ary) scope :pasted_with_all, ->(ary, prefix: '') {
ids = ary.map do |klass, id| ary = parsed_condition_ary(ary)
joins(:pastings).where(pastings: { ids = ary.map do |klass, id|
pasteable_type: klass.constantize.base_class.name, pasteable_id: id, type: prefix joins(:pastings).where(pastings: {
}).pluck(:id) pasteable_type: klass.constantize.base_class.name, pasteable_id: id, type: prefix
end.reduce(:&) }).pluck(:id)
where(id: ids) end.reduce(:&)
} where(id: ids)
}
after_create :save_paste_list
after_create :save_paste_list
# 不包含 带 prefix 的 pasted_with
def paste_list # 不包含 带 prefix 的 pasted_with
pastings.where(type: '').reload.map(&:pasteable).uniq def paste_list
end pastings.where(type: '').reload.map(&:pasteable).uniq
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.where(type: '').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(type: '').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 # 不包含 带 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)
add_ary = ary - exist_ary add_ary = ary - exist_ary
remove_ary = exist_ary - ary remove_ary = exist_ary - ary
if new_record? if new_record?
@paste_list = ary @paste_list = ary
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: '', 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: '', type: '',
pasted: self, pasted: self,
pasteable_type: klass, pasteable_type: klass,
pasteable_id: id pasteable_id: id
) )
} }
end
end 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
def save_paste_list def save_paste_list
if @paste_list if @paste_list
self.paste_list = @paste_list self.paste_list = @paste_list
end
end end
end
def correct_class_name? name def correct_class_name? name
ActiveRecord::Base === name.safe_constantize.try(:new) ActiveRecord::Base === name.safe_constantize.try(:new)
end end
def downcase_all_combination str def downcase_all_combination str
downcase_all_combination_ary(str).reverse.map { |x| (String === x ? x : x.flatten.join).classify } downcase_all_combination_ary(str).reverse.map { |x| (String === x ? x : x.flatten.join).classify }
end end
def downcase_all_combination_ary str def downcase_all_combination_ary str
items = String === str ? str.split('_') : str items = String === str ? str.split('_') : str
return items if items.length == 1 return items if items.length == 1
l = downcase_all_combination_ary(items[1..-1]) l = downcase_all_combination_ary(items[1..-1])
result = [] result = []
l.each do |i| l.each do |i|
result.push(items[0, 1] << '/' << i) result.push(items[0, 1] << '/' << i)
result.push(items[0, 1] << '_' << i) result.push(items[0, 1] << '_' << i)
end
result
end end
result
end end
end
module ClassMethods module ClassMethods
def pasted_with *klasses, prefix: nil 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 downcase = "#{prefix}#{downcase}" if prefix
type_value = prefix ? prefix : nil 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
#{klass}.where( #{klass}.where(
id: pastings.where(type: "#{type_value}", pasteable_type: #{klass}.base_class.name).pluck(:pasteable_id) 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
ary = ids.map { |id| ["#{base_class_name}", id] } ary = ids.map { |id| ["#{base_class_name}", id] }
self.paste_#{downcase}_list = ary self.paste_#{downcase}_list = ary
end end
def paste_#{downcase}_list= ary, run_save: true def paste_#{downcase}_list= ary, run_save: true
ary = self.class.parsed_condition_ary(ary).select { |a| ary = self.class.parsed_condition_ary(ary).select { |a|
a.first == "#{base_class_name}" a.first == "#{base_class_name}"
} }
if new_record? if new_record?
@paste_#{downcase}_list = ary @paste_#{downcase}_list = ary
else else
exist_ary = pastings.where( exist_ary = pastings.where(
type: "#{type_value}", pasted: self, pasteable_type: "#{base_class_name}" type: "#{type_value}", pasted: self, pasteable_type: "#{base_class_name}"
).pluck(:pasteable_type, :pasteable_id) ).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}", 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}", type: "#{type_value}",
pasted: self, pasted: self,
pasteable_type: klass, pasteable_type: klass,
pasteable_id: id pasteable_id: id
) )
} }
end
end end
end end
end
private private
def save_paste_#{downcase}_list def save_paste_#{downcase}_list
if @paste_#{downcase}_list if @paste_#{downcase}_list
self.paste_#{downcase}_list = @paste_#{downcase}_list self.paste_#{downcase}_list = @paste_#{downcase}_list
end
end end
end RUBY
RUBY end
end end
end
def parsed_condition_ary ary def parsed_condition_ary ary
ary = ary.compact ary = ary.compact
return [] unless ary && ary.first 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[:pasted_type].constantize.base_class.name, h[:pasted_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 end
end
def acts_as_pasted associations, options={} def acts_as_pasted associations, options={}
has_many associations, through: :pastings, source: :pasteable, **options has_many associations, through: :pastings, source: :pasteable, **options
end
end end
end
module Association module Association
def acts_as_pasted associations, options={} def acts_as_pasted associations, options={}
has_many :pastings, as: :pasteable has_many :pastings, as: :pasteable
has_many associations, through: :pastings, source: :pasted, **options has_many associations, through: :pastings, source: :pasted, **options
end
end end
end end
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