josevalim-inherited_resources 0.6.3 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,11 @@
1
- module InheritedResources #:nodoc:
2
- module BaseHelpers #:nodoc:
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
- # Private helpers, you probably don't have to worry with them.
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
- # Returns if the object has a parent. This means, if it has an object
88
- # set at begin_of_association_chain is not nil.
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 parent?
91
- false
92
- end
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
- # This methods gets your begin_of_association_chain and returns the
95
- # scoped association.
96
- #
97
- def end_of_association_chain
98
- if begin_of_association_chain || parent?
99
- begin_of_association_chain.send(resource_collection_name)
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 Rare::CarsController,
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.rare.cars.create.status
183
- # flash.rare.actions.create.status
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 #:nodoc:
2
- module BelongsToHelpers #:nodoc:
1
+ module InheritedResources
3
2
 
4
- # Private helpers, you probably don't have to worry with them.
5
- private
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
- scoped_parent = if chain
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
- scoped_parent = scoped_parent.send(parent_config[:finder], params[parent_config[:param]])
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
- # If current controller is singleton, returns instance name to
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 to deal with properly.
83
+ # it has some customization.
62
84
  #
63
- def symbols_for_chain
85
+ def symbols_for_association_chain #:nodoc:
64
86
  parents_symbols
65
87
  end
66
88