-
Notifications
You must be signed in to change notification settings - Fork 330
/
association_helpers.rb
109 lines (97 loc) · 4.82 KB
/
association_helpers.rb
1
2
3
4
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
module ActiveScaffold
module Helpers
module AssociationHelpers
# Cache the options for select
def cache_association_options(association, conditions, klass, cache = true)
if active_scaffold_config.cache_association_options && cache
@_associations_cache ||= Hash.new { |h, k| h[k] = {} }
key = [association.name, association.inverse_klass.name, klass.respond_to?(:cache_key) ? klass.cache_key : klass.name].join('/')
@_associations_cache[key][conditions] ||= yield
else
yield
end
end
def association_helper_method(association, method)
model = association.inverse_klass
override_helper_per_model(method, model)
end
# Provides a way to honor the :conditions on an association while searching the association's klass
def association_options_find(association, conditions = nil, klass = nil, record = nil)
if klass.nil? && association.polymorphic?
class_name = record.send(association.foreign_type) if association.belongs_to?
return [] if class_name.blank?
klass = class_name.constantize
cache = !block_given?
else
cache = !block_given? && klass.nil?
klass ||= association.klass
end
conditions ||= send(association_helper_method(association, :options_for_association_conditions), association, record)
klass = send(association_helper_method(association, :association_klass_scoped), association, klass, record)
cache_association_options(association, conditions, klass, cache) do
relation = klass.where(conditions)
column = column_for_association(association, record)
if column&.includes
include_assoc = column.includes.find { |assoc| assoc.is_a?(Hash) && assoc.include?(association.name) }
relation = relation.includes(include_assoc[association.name]) if include_assoc
end
if column&.sort && column.sort&.dig(:sql)
# with threasafe enabled, column.sort[:sql] returns proxied strings and
# regexp capture won't work, which rails uses internally, so to_s is needed
relation = relation.order(Array(column.sort[:sql]).map(&:to_s))
end
relation = yield(relation) if block_given?
relation.to_a
end
end
def column_for_association(association, record)
active_scaffold_config_for(record.class).columns[association.name]
rescue StandardError => e
message = "Error on config for #{record.class.name}:"
Rails.logger.warn "#{message}\n#{e.message}\n#{e.backtrace.join("\n")}"
nil
end
def association_klass_scoped(association, klass, record)
if nested? && nested.through_association? && nested.child_association&.through_reflection == association
# only ActiveRecord associations
if nested.association.through_reflection.collection?
nested_parent_record.send(nested.association.through_reflection.name)
else
klass.where(association.association_primary_key => nested_parent_record.send(nested.association.through_reflection.name)&.id)
end
else
klass
end
end
# Sorts the options for select
def sorted_association_options_find(association, conditions = nil, record = nil)
options = association_options_find(association, conditions, nil, record)
column = column_for_association(association, record)
unless column&.sort && column.sort&.dig(:sql)
method = column.options[:label_method] if column
options = options.sort_by(&(method || :to_label).to_sym)
end
options
end
def association_options_count(association, conditions = nil)
association.klass.where(conditions).count
end
def options_for_association_count(association, record)
conditions = send(association_helper_method(association, :options_for_association_conditions), association, record)
association_options_count(association, conditions)
end
# A useful override for customizing the records present in an association dropdown.
# Should work in both the subform and form_ui=>:select modes.
# Check association.name to specialize the conditions per-column.
def options_for_association_conditions(association, record = nil)
return nil if association.through?
return nil unless association.has_one? || association.has_many?
# Find only orphaned objects
{association.foreign_key => nil}
end
def record_select_params_for_add_existing(association, edit_associated_url_options, record)
{onselect: "ActiveScaffold.record_select_onselect(#{url_for(edit_associated_url_options).to_json}, #{active_scaffold_id.to_json}, id);"}
end
end
end
end