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.
@@ -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