5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
# File 'lib/polymorph/methods.rb', line 5
def polymorph(method_name,
through:,
source_types:,
fields: [:id],
through_class: through.to_s.singularize.camelize.constantize,
source_column: method_name.to_s.singularize,
source_type: "#{source_column}_type")
define_method method_name, -> {
query = send(through).select([
source_types.map { |t| "#{t}.*" },
source_types.product(fields).map { |a| "#{a[0]}.#{a[1]} AS #{a[0].to_s.singularize}_#{a[1]}" },
"#{through}.#{source_column}_type",
"'is_polymorph' as polymorph_query"
].flatten.join(', '))
source_types.each do |type|
query = query.joins(%{
LEFT OUTER JOIN #{type}
ON #{type}.id = #{through}.#{source_column}_id
AND '#{type.to_s.singularize.camelize}' = #{through}.#{source_type}
})
end
Polymorph::Relation.new(query, fields: fields, source_types: source_types)
}
through_class.define_singleton_method :instantiate, ->(attrs, column_types) {
super(attrs, column_types).tap do |record|
break unless attrs['polymorph_query'].present?
transfer_fields = fields.map { |field| [field, attrs["#{attrs[source_type].downcase}_#{field}"]] }.to_h
record.assign_attributes(transfer_fields)
end
}
through_class.define_singleton_method :discriminate_class_for_record, ->(attributes) {
return super(attributes) unless attributes['polymorph_query'].present?
attributes["#{source_column}_type"].camelize.constantize
}
end
|