josevalim-inherited_resources 0.6.3 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +9 -0
- data/README +132 -105
- data/lib/inherited_resources/base.rb +15 -189
- data/lib/inherited_resources/base_helpers.rb +75 -39
- data/lib/inherited_resources/belongs_to_helpers.rb +62 -40
- data/lib/inherited_resources/class_methods.rb +268 -272
- data/lib/inherited_resources/dumb_responder.rb +7 -6
- data/lib/inherited_resources/has_scope_helpers.rb +65 -0
- data/lib/inherited_resources/polymorphic_helpers.rb +96 -5
- data/lib/inherited_resources/respond_to.rb +7 -7
- data/lib/inherited_resources/singleton_helpers.rb +48 -6
- data/lib/inherited_resources/url_helpers.rb +37 -36
- data/lib/inherited_resources.rb +4 -2
- data/test/base_helpers_test.rb +3 -92
- data/test/class_methods_test.rb +116 -75
- data/test/customized_belongs_to_test.rb +76 -0
- data/test/defaults_test.rb +2 -1
- data/test/flash_test.rb +83 -0
- data/test/has_scope_test.rb +171 -0
- data/test/test_helper.rb +4 -8
- data/test/url_helpers_test.rb +3 -3
- data/test/views/branches/edit.html.erb +1 -0
- data/test/views/branches/index.html.erb +1 -0
- data/test/views/branches/new.html.erb +1 -0
- data/test/views/branches/show.html.erb +1 -0
- data/test/views/pets/index.html.erb +1 -0
- data/test/views/pets/new.html.erb +1 -0
- data/test/views/pets/show.html.erb +1 -0
- data/test/views/trees/edit.html.erb +1 -0
- data/test/views/trees/index.html.erb +1 -0
- data/test/views/trees/new.html.erb +1 -0
- data/test/views/trees/show.html.erb +1 -0
- metadata +17 -2
@@ -1,8 +1,11 @@
|
|
1
|
-
module InheritedResources
|
2
|
-
|
1
|
+
module InheritedResources
|
2
|
+
# Base helpers for InheritedResource work. Some methods here can be overwriten
|
3
|
+
# and you will need to do that to customize your controllers from time to time.
|
4
|
+
#
|
5
|
+
module BaseHelpers
|
3
6
|
|
4
|
-
# Protected helpers. You might want to overwrite some of them.
|
5
7
|
protected
|
8
|
+
|
6
9
|
# This is how the collection is loaded.
|
7
10
|
#
|
8
11
|
# You might want to overwrite this method if you want to add pagination
|
@@ -69,66 +72,95 @@ module InheritedResources #:nodoc:
|
|
69
72
|
nil
|
70
73
|
end
|
71
74
|
|
72
|
-
|
75
|
+
# Returns if the controller has a parent. When only base helpers are loaded,
|
76
|
+
# it's always false and should not be overwriten.
|
77
|
+
#
|
78
|
+
def parent?
|
79
|
+
false
|
80
|
+
end
|
81
|
+
|
82
|
+
# Overwrite this method to provide other interpolation options when
|
83
|
+
# the flash message is going to be set.
|
84
|
+
#
|
85
|
+
# You cannot overwrite :resource_name and :default options using this
|
86
|
+
# method. Check <tt>set_flash_message!</tt> for more information.
|
87
|
+
#
|
88
|
+
def interpolation_options
|
89
|
+
{ }
|
90
|
+
end
|
91
|
+
|
73
92
|
private
|
74
93
|
|
75
94
|
# Fast accessor to resource_collection_name
|
76
95
|
#
|
77
|
-
def resource_collection_name
|
78
|
-
resources_configuration[:self][:collection_name]
|
96
|
+
def resource_collection_name #:nodoc:
|
97
|
+
self.resources_configuration[:self][:collection_name]
|
79
98
|
end
|
80
99
|
|
81
100
|
# Fast accessor to resource_instance_name
|
82
101
|
#
|
83
|
-
def resource_instance_name
|
84
|
-
resources_configuration[:self][:instance_name]
|
102
|
+
def resource_instance_name #:nodoc:
|
103
|
+
self.resources_configuration[:self][:instance_name]
|
85
104
|
end
|
86
105
|
|
87
|
-
#
|
88
|
-
#
|
106
|
+
# This methods gets your begin_of_association_chain, join it with your
|
107
|
+
# parents chain and returns the scoped association.
|
89
108
|
#
|
90
|
-
def
|
91
|
-
|
92
|
-
|
109
|
+
def end_of_association_chain #:nodoc:
|
110
|
+
chain = symbols_for_association_chain.inject(begin_of_association_chain) do |chain, symbol|
|
111
|
+
evaluate_parent(symbol, resources_configuration[symbol], chain)
|
112
|
+
end
|
93
113
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
114
|
+
if chain
|
115
|
+
if method_for_association_chain
|
116
|
+
apply_scope_to(chain.send(method_for_association_chain), resource_instance_name)
|
117
|
+
else
|
118
|
+
# This only happens when we specify begin_of_association_chain in
|
119
|
+
# a singletion controller without parents. In this case, the chain
|
120
|
+
# is exactly the begin_of_association_chain which is already an
|
121
|
+
# instance and then not scopable.
|
122
|
+
chain
|
123
|
+
end
|
100
124
|
else
|
101
|
-
resource_class
|
125
|
+
apply_scope_to(resource_class, resource_instance_name)
|
102
126
|
end
|
103
127
|
end
|
104
128
|
|
105
129
|
# Returns the appropriated method to build the resource.
|
106
130
|
#
|
107
|
-
def method_for_build
|
131
|
+
def method_for_build #:nodoc:
|
108
132
|
(begin_of_association_chain || parent?) ? :build : :new
|
109
133
|
end
|
110
134
|
|
135
|
+
# Returns the name of the method to be called, before returning the end
|
136
|
+
# of the association chain. This is overwriten by singleton cases
|
137
|
+
# where no method for association chain is called.
|
138
|
+
#
|
139
|
+
def method_for_association_chain #:nodoc:
|
140
|
+
resource_collection_name
|
141
|
+
end
|
142
|
+
|
111
143
|
# Get resource ivar based on the current resource controller.
|
112
144
|
#
|
113
|
-
def get_resource_ivar
|
145
|
+
def get_resource_ivar #:nodoc:
|
114
146
|
instance_variable_get("@#{resource_instance_name}")
|
115
147
|
end
|
116
148
|
|
117
149
|
# Set resource ivar based on the current resource controller.
|
118
150
|
#
|
119
|
-
def set_resource_ivar(resource)
|
151
|
+
def set_resource_ivar(resource) #:nodoc:
|
120
152
|
instance_variable_set("@#{resource_instance_name}", resource)
|
121
153
|
end
|
122
154
|
|
123
155
|
# Get collection ivar based on the current resource controller.
|
124
156
|
#
|
125
|
-
def get_collection_ivar
|
157
|
+
def get_collection_ivar #:nodoc:
|
126
158
|
instance_variable_get("@#{resource_collection_name}")
|
127
159
|
end
|
128
160
|
|
129
161
|
# Set collection ivar based on the current resource controller.
|
130
162
|
#
|
131
|
-
def set_collection_ivar(collection)
|
163
|
+
def set_collection_ivar(collection) #:nodoc:
|
132
164
|
instance_variable_set("@#{resource_collection_name}", collection)
|
133
165
|
end
|
134
166
|
|
@@ -176,11 +208,11 @@ module InheritedResources #:nodoc:
|
|
176
208
|
#
|
177
209
|
# 'Hooray! You just tuned your Aston Martin!'
|
178
210
|
#
|
179
|
-
# If your controller is namespaced, for example
|
211
|
+
# If your controller is namespaced, for example Admin::CarsController,
|
180
212
|
# the messages will be checked in the following order:
|
181
213
|
#
|
182
|
-
# flash.
|
183
|
-
# flash.
|
214
|
+
# flash.admin.cars.create.status
|
215
|
+
# flash.admin.actions.create.status
|
184
216
|
# flash.cars.create.status
|
185
217
|
# flash.actions.create.status
|
186
218
|
#
|
@@ -208,16 +240,6 @@ module InheritedResources #:nodoc:
|
|
208
240
|
flash[status] = message unless message.blank?
|
209
241
|
end
|
210
242
|
|
211
|
-
# Overwrite this method to provide other interpolation options when
|
212
|
-
# the flash message is going to be set.
|
213
|
-
#
|
214
|
-
# You cannot overwrite :resource_name and :default options using this
|
215
|
-
# method. Check <tt>set_flash_message!</tt> for more information.
|
216
|
-
#
|
217
|
-
def interpolation_options
|
218
|
-
{ }
|
219
|
-
end
|
220
|
-
|
221
243
|
# Used to allow to specify success and failure within just one block:
|
222
244
|
#
|
223
245
|
# def create
|
@@ -226,7 +248,7 @@ module InheritedResources #:nodoc:
|
|
226
248
|
# end
|
227
249
|
# end
|
228
250
|
#
|
229
|
-
def respond_to_with_dual_blocks(success, dual_block, options={}, &block)
|
251
|
+
def respond_to_with_dual_blocks(success, dual_block, options={}, &block) #:nodoc:
|
230
252
|
responder = ActionController::MimeResponds::Responder.new(self)
|
231
253
|
|
232
254
|
if dual_block
|
@@ -248,5 +270,19 @@ module InheritedResources #:nodoc:
|
|
248
270
|
respond_to(options.merge!(:responder => responder, :prioritize => :html), &block) unless performed?
|
249
271
|
end
|
250
272
|
|
273
|
+
# Hook to apply scopes. By default returns only the target_object given.
|
274
|
+
# It's extend by HasScopeHelpers.
|
275
|
+
#
|
276
|
+
def apply_scope_to(target_object, target_name) #:nodoc:
|
277
|
+
target_object
|
278
|
+
end
|
279
|
+
|
280
|
+
# Symbols chain in base helpers return nothing. This is later overwriten
|
281
|
+
# by belongs_to and can be complex in polymorphic cases.
|
282
|
+
#
|
283
|
+
def symbols_for_association_chain #:nodoc:
|
284
|
+
[]
|
285
|
+
end
|
286
|
+
|
251
287
|
end
|
252
288
|
end
|
@@ -1,66 +1,88 @@
|
|
1
|
-
module InheritedResources
|
2
|
-
module BelongsToHelpers #:nodoc:
|
1
|
+
module InheritedResources
|
3
2
|
|
4
|
-
|
5
|
-
|
3
|
+
# = belongs_to
|
4
|
+
#
|
5
|
+
# Let's suppose that we have some tasks that belongs to projects. To specify
|
6
|
+
# this assoication in your controllers, just do:
|
7
|
+
#
|
8
|
+
# class TasksController < InheritedResources::Base
|
9
|
+
# belongs_to :project
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# belongs_to accepts several options to be able to configure the association.
|
13
|
+
# For example, if you want urls like /projects/:project_title/tasks, you
|
14
|
+
# can customize how InheritedResources find your projects:
|
15
|
+
#
|
16
|
+
# class TasksController < InheritedResources::Base
|
17
|
+
# belongs_to :project, :finder => :find_by_title!, :param => :project_title
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# It also accepts :route_name, :parent_class and :instance_name as options.
|
21
|
+
# Check the lib/inherited_resources/class_methods.rb for more.
|
22
|
+
#
|
23
|
+
# = nested_belongs_to
|
24
|
+
#
|
25
|
+
# Now, our Tasks get some Comments and you need to nest even deeper. Good
|
26
|
+
# practices says that you should never nest more than two resources, but sometimes
|
27
|
+
# you have to for security reasons. So this is an example of how you can do it:
|
28
|
+
#
|
29
|
+
# class CommentsController < InheritedResources::Base
|
30
|
+
# nested_belongs_to :project, :task
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# If you need to configure any of these belongs to, you can nested them using blocks:
|
34
|
+
#
|
35
|
+
# class CommentsController < InheritedResources::Base
|
36
|
+
# belongs_to :project, :finder => :find_by_title!, :param => :project_title do
|
37
|
+
# belongs_to :task
|
38
|
+
# end
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# Warning: calling several belongs_to is the same as nesting them:
|
42
|
+
#
|
43
|
+
# class CommentsController < InheritedResources::Base
|
44
|
+
# belongs_to :project
|
45
|
+
# belongs_to :task
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# In other words, the code above is the same as calling nested_belongs_to.
|
49
|
+
#
|
50
|
+
module BelongsToHelpers
|
51
|
+
|
52
|
+
protected
|
6
53
|
|
54
|
+
# Parent is always true when belongs_to is called.
|
55
|
+
#
|
7
56
|
def parent?
|
8
57
|
true
|
9
58
|
end
|
10
59
|
|
60
|
+
private
|
61
|
+
|
11
62
|
# Evaluate the parent given. This is used to nest parents in the
|
12
63
|
# association chain.
|
13
64
|
#
|
14
|
-
def evaluate_parent(parent_config, chain = nil)
|
65
|
+
def evaluate_parent(parent_symbol, parent_config, chain = nil) #:nodoc:
|
15
66
|
instantiated_object = instance_variable_get("@#{parent_config[:instance_name]}")
|
16
67
|
return instantiated_object if instantiated_object
|
17
68
|
|
18
|
-
|
69
|
+
parent = if chain
|
19
70
|
chain.send(parent_config[:collection_name])
|
20
71
|
else
|
21
72
|
parent_config[:parent_class]
|
22
73
|
end
|
23
74
|
|
24
|
-
|
25
|
-
|
26
|
-
instance_variable_set("@#{parent_config[:instance_name]}", scoped_parent)
|
27
|
-
end
|
28
|
-
|
29
|
-
# Overwrites the end_of_association_chain method.
|
30
|
-
#
|
31
|
-
# This methods gets your begin_of_association_chain, join it with your
|
32
|
-
# parents chain and returns the scoped association.
|
33
|
-
#
|
34
|
-
def end_of_association_chain
|
35
|
-
chain = symbols_for_chain.inject(begin_of_association_chain) do |chain, symbol|
|
36
|
-
evaluate_parent(resources_configuration[symbol], chain)
|
37
|
-
end
|
38
|
-
|
39
|
-
return resource_class unless chain
|
40
|
-
|
41
|
-
chain = chain.send(method_for_association_chain) if method_for_association_chain
|
42
|
-
return chain
|
43
|
-
end
|
75
|
+
parent = apply_scope_to(parent, parent_symbol)
|
76
|
+
parent = parent.send(parent_config[:finder], params[parent_config[:param]])
|
44
77
|
|
45
|
-
|
46
|
-
# end_of_association_chain. This means that we will have the following
|
47
|
-
# chain:
|
48
|
-
#
|
49
|
-
# Project.find(params[:project_id]).manager
|
50
|
-
#
|
51
|
-
# Instead of:
|
52
|
-
#
|
53
|
-
# Project.find(params[:project_id]).managers
|
54
|
-
#
|
55
|
-
def method_for_association_chain
|
56
|
-
singleton ? nil : resource_collection_name
|
78
|
+
instance_variable_set("@#{parent_config[:instance_name]}", parent)
|
57
79
|
end
|
58
80
|
|
59
81
|
# Maps parents_symbols to build association chain. In this case, it
|
60
82
|
# simply return the parent_symbols, however on polymorphic belongs to,
|
61
|
-
# it has some customization
|
83
|
+
# it has some customization.
|
62
84
|
#
|
63
|
-
def
|
85
|
+
def symbols_for_association_chain #:nodoc:
|
64
86
|
parents_symbols
|
65
87
|
end
|
66
88
|
|