forked from activescaffold/active_scaffold
/
nested_info.rb
146 lines (120 loc) · 3.89 KB
/
nested_info.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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
module ActiveScaffold::DataStructures
class NestedInfo
def self.get(model, params)
if params[:association].nil?
ActiveScaffold::DataStructures::NestedInfoScope.new(model, params)
else
ActiveScaffold::DataStructures::NestedInfoAssociation.new(model, params)
end
rescue ActiveScaffold::ControllerNotFound
nil
end
attr_accessor :association, :child_association, :parent_model, :parent_scaffold, :parent_id, :param_name, :constrained_fields, :scope
def initialize(model, params)
@parent_scaffold = "#{params[:parent_scaffold].to_s.camelize}Controller".constantize
@parent_model = @parent_scaffold.active_scaffold_config.model
end
def to_params
{:parent_scaffold => parent_scaffold.controller_path}
end
def new_instance?
result = @new_instance.nil?
@new_instance = false
result
end
def habtm?
false
end
def has_many?
false
end
def belongs_to?
false
end
def has_one?
false
end
def singular_association?
belongs_to? || has_one?
end
def plural_association?
has_many? || habtm?
end
def readonly_through_association?(columns)
false
end
def through_association?
false
end
def readonly?
false
end
def sorted?(*)
false
end
end
class NestedInfoAssociation < NestedInfo
def initialize(model, params)
super
column = parent_scaffold.active_scaffold_config.columns[params[:association].to_sym]
@param_name = column.model.name.foreign_key.to_sym
@parent_id = params[@param_name]
@association = column.try(:association)
@child_association = association.reverse_association(model) if association
setup_constrained_fields
end
delegate :name, :belongs_to?, :has_one?, :has_many?, :habtm?, :readonly?, :to => :association
# A through association with has_one or has_many as source association
# create cannot be called in nested through associations, and not-nested through associations
# unless create columns include through reflection of reverse association
# e.g. customer -> networks -> firewall, reverse is firewall -> network -> customer,
# firewall can be created if create columns include network
def readonly_through_association?(columns)
return false unless through_association?
return true if association.through_reflection.options[:through]
!association.source_reflection.belongs_to? && (
!child_association || !columns.include?(child_association.through_reflection.name)
)
end
def through_association?
association.through?
end
def sorted?(chain)
default_sorting(chain).present?
end
def default_sorting(chain)
return @default_sorting if defined? @default_sorting
if association.scope.is_a?(Proc) && chain.respond_to?(:values)
@default_sorting = chain.values[:order]
@default_sorting = @default_sorting.map(&:to_sql) if @default_sorting[0].is_a? Arel::Nodes::Node
@default_sorting = @default_sorting.join(', ')
end
end
def to_params
super.merge(:association => @association.name, :assoc_id => parent_id)
end
protected
def setup_constrained_fields
@constrained_fields = []
@constrained_fields << Array(association.foreign_key).map(&:to_sym) unless association.belongs_to?
if child_association && child_association != association
@constrained_fields << child_association.name
end
end
end
class NestedInfoScope < NestedInfo
def initialize(model, params)
super
@scope = params[:named_scope].to_sym
@param_name = parent_model.name.foreign_key.to_sym
@parent_id = params[@param_name]
@constrained_fields = []
end
def to_params
super.merge(:named_scope => @scope)
end
def name
scope
end
end
end