josevalim-inherited_resources 0.1

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.
Files changed (57) hide show
  1. data/CHANGELOG +4 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README +362 -0
  4. data/Rakefile +19 -0
  5. data/init.rb +1 -0
  6. data/lib/inherited_resources.rb +4 -0
  7. data/lib/inherited_resources/base.rb +272 -0
  8. data/lib/inherited_resources/base_helpers.rb +199 -0
  9. data/lib/inherited_resources/belongs_to.rb +227 -0
  10. data/lib/inherited_resources/belongs_to_helpers.rb +89 -0
  11. data/lib/inherited_resources/class_methods.rb +155 -0
  12. data/lib/inherited_resources/polymorphic_helpers.rb +19 -0
  13. data/lib/inherited_resources/respond_to.rb +324 -0
  14. data/lib/inherited_resources/singleton_helpers.rb +53 -0
  15. data/lib/inherited_resources/url_helpers.rb +147 -0
  16. data/test/aliases_test.rb +71 -0
  17. data/test/base_helpers_test.rb +130 -0
  18. data/test/base_test.rb +219 -0
  19. data/test/belongs_to_base_test.rb +268 -0
  20. data/test/belongs_to_test.rb +109 -0
  21. data/test/class_methods_test.rb +73 -0
  22. data/test/fixtures/en.yml +9 -0
  23. data/test/nested_belongs_to_test.rb +138 -0
  24. data/test/polymorphic_base_test.rb +282 -0
  25. data/test/respond_to_test.rb +282 -0
  26. data/test/singleton_base_test.rb +226 -0
  27. data/test/test_helper.rb +37 -0
  28. data/test/url_helpers_test.rb +284 -0
  29. data/test/views/cities/edit.html.erb +1 -0
  30. data/test/views/cities/index.html.erb +1 -0
  31. data/test/views/cities/new.html.erb +1 -0
  32. data/test/views/cities/show.html.erb +1 -0
  33. data/test/views/comments/edit.html.erb +1 -0
  34. data/test/views/comments/index.html.erb +1 -0
  35. data/test/views/comments/new.html.erb +1 -0
  36. data/test/views/comments/show.html.erb +1 -0
  37. data/test/views/employees/edit.html.erb +1 -0
  38. data/test/views/employees/index.html.erb +1 -0
  39. data/test/views/employees/new.html.erb +1 -0
  40. data/test/views/employees/show.html.erb +1 -0
  41. data/test/views/managers/edit.html.erb +1 -0
  42. data/test/views/managers/new.html.erb +1 -0
  43. data/test/views/managers/show.html.erb +1 -0
  44. data/test/views/pets/edit.html.erb +1 -0
  45. data/test/views/professors/edit.html.erb +1 -0
  46. data/test/views/professors/index.html.erb +1 -0
  47. data/test/views/professors/new.html.erb +1 -0
  48. data/test/views/professors/show.html.erb +1 -0
  49. data/test/views/projects/index.html.erb +1 -0
  50. data/test/views/projects/respond_to_with_resource.html.erb +1 -0
  51. data/test/views/students/edit.html.erb +1 -0
  52. data/test/views/students/new.html.erb +1 -0
  53. data/test/views/users/edit.html.erb +1 -0
  54. data/test/views/users/index.html.erb +1 -0
  55. data/test/views/users/new.html.erb +1 -0
  56. data/test/views/users/show.html.erb +1 -0
  57. metadata +108 -0
data/CHANGELOG ADDED
@@ -0,0 +1,4 @@
1
+ Version 0.1
2
+
3
+ * Initial release. Support to I18n, singleton controllers, polymorphic
4
+ controllers, belongs_to, nested_belongs_to and url helpers.
data/MIT-LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2006 Coda Hale
2
+ Copyright (c) 2008 José Valim (jose.valim at gmail dot com)
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,362 @@
1
+ Inherited Resources
2
+ License: MIT
3
+ Version: 0.1
4
+
5
+ You can also read this README in pretty html at the GitHub project Wiki page:
6
+
7
+ http://github.com/josevalim/inherited_resources/wikis/home
8
+
9
+ Description
10
+ -----------
11
+
12
+ Inherited Resources speeds up development by making your controllers inherit
13
+ all restful actions so you just have to focus on what is important. It makes
14
+ your controllers more powerful and cleaner at the same time.
15
+
16
+ keywords: resources, controller, singleton, belongs_to, polymorphic and I18n
17
+
18
+ Installation
19
+ ------------
20
+
21
+ Install Inherited Resources is very easy. It is stored in GitHub, so just run
22
+ the following:
23
+
24
+ gem sources -a http://gems.github.com
25
+ sudo gem install josevalim-inherited_resources
26
+
27
+ If you want it as plugin, just do:
28
+
29
+ script/plugin install git://github.com/josevalim/inherited_resources.git
30
+
31
+ Basic Usage
32
+ -----------
33
+
34
+ To use Inherited Resources you just have to inherit (duh) it:
35
+
36
+ class ProjectsController < ResourceController::Base
37
+ end
38
+
39
+ And all actions are defined and working, check it! Your projects collection
40
+ (in the index action) is still available in the instance variable @projects
41
+ and your project resource (all other actions) is available as @ project.
42
+
43
+ The next step is to define which mime types this controller provides:
44
+
45
+ class ProjectsController < InheritedResources::Base
46
+ respond_to :html, :xml, :json
47
+ end
48
+
49
+ You can also specify them based per action:
50
+
51
+ class ProjectsController < InheritedResources::Base
52
+ respond_to :html, :xml, :json
53
+ respond_to :js, :only => :create
54
+ respond_to :iphone, :except => [ :edit, :update ]
55
+ end
56
+
57
+ Let's take a request on create with :rjs as example of how it works. After the
58
+ action is processed, it will check if the view "projects/create.js.rjs" exist.
59
+ If it does exist, it will render it, otherwise it will check if the resource
60
+ @project respond to :to_js. If it is true, it will render the result of :to_js,
61
+ otherwise it will render a 404.
62
+
63
+ Another option is to specify which actions the controller will inherit from
64
+ the InheritedResources::Base:
65
+
66
+ class ProjectsController < InheritedResources::Base
67
+ actions :index, :show, :new, :create
68
+ end
69
+
70
+ Or:
71
+
72
+ class ProjectsController < InheritedResources::Base
73
+ actions :all, :except => [ :edit, :update, :destroy ]
74
+ end
75
+
76
+ Overwriting defaults
77
+ --------------------
78
+
79
+ Now that you learned the default behavior and basic configuration, let's see
80
+ how to extend it.
81
+
82
+ Assuming that you have a PeopleController, but the resource is actually called
83
+ User, you could overwrite the resource name, collection name and instance name
84
+ just doing:
85
+
86
+ class PeopleController < InheritedResources::Base
87
+ defaults :resource_class => User, :collection_name => 'users', :instance_name => 'user'
88
+ end
89
+
90
+ Further extensions is done by overwriting two methods. Let's suppose you want
91
+ to add pagination to your projects collection:
92
+
93
+ class ProjectsController < InheritedResources::Base
94
+ protected
95
+ def collection
96
+ @projects ||= end_of_association_chain.paginate(params[:page]).all
97
+ end
98
+ end
99
+
100
+ In this case you could just have done:
101
+
102
+ class ProjectsController < InheritedResources::Base
103
+ protected
104
+ def collection
105
+ @projects ||= Project.paginate(params[:page]).all
106
+ end
107
+ end
108
+
109
+ But you should get used if end_of_association_chain. When you have nested
110
+ resources it's very handy and it will deal with all nesting stuff. It was first
111
+ introduced in resource_controller by Jamis Golick and we will talk more about it
112
+ soon.
113
+
114
+ On the other hand, if you just added pretty urls for in your ProjectsController
115
+ (/projects/my-project-name), you can overwrite how projects are being found by:
116
+
117
+ class ProjectsController < InheritedResources::Base
118
+ protected
119
+ def resource
120
+ @project ||= end_of_association_chain.find_by_title!(params[:title])
121
+ end
122
+ end
123
+
124
+ And now since you is acquainted to end_of_association_chain let's meet its
125
+ twin brother: begin_of_association_chain.
126
+
127
+ It's mostly used when you want to create resources based on the @current_user.
128
+ In such cases, you don't have your @current_user in the url, but in the session.
129
+
130
+ So if you have to do: @current_user.projects.find or @current_user.projects.build
131
+ you can deal with both just doing:
132
+
133
+ class ProjectsController < InheritedResources::Base
134
+ protected
135
+ def begin_of_association_chain
136
+ @current_user
137
+ end
138
+ end
139
+
140
+ Overwriting actions
141
+ -------------------
142
+
143
+ Let's suppose that after destroying a project you want to redirect to your
144
+ root url instead of redirecting to projects url. You just have to do:
145
+
146
+ class ProjectsController < InheritedResources::Base
147
+ def destroy
148
+ super do |format|
149
+ format.html { redirect_to root_url }
150
+ end
151
+ end
152
+ end
153
+
154
+ You are opening your action and giving the parent action a new behavior. No
155
+ tricks, no DSL, just Ruby.
156
+
157
+ On the other hand, I have to agree that calling super is the right thing but
158
+ is not very readable. That's why all methods have aliases. So this is
159
+ equivalent:
160
+
161
+ class ProjectsController < InheritedResources::Base
162
+ def destroy
163
+ destroy! do |format|
164
+ format.html { redirect_to projects_url }
165
+ end
166
+ end
167
+ end
168
+
169
+ Now let's suppose that before create a project you have to do something special
170
+ but you don't want to create a before filter for it:
171
+
172
+ class ProjectsController < InheritedResources::Base
173
+ def create
174
+ @project = Project.new(params[:project])
175
+ @project.something_special!
176
+ create!
177
+ end end
178
+
179
+ Yeap, that simple! The nice part is since you already set the instance variable
180
+ @project, it will not do it again and overwrite your @project with something
181
+ special. :)
182
+
183
+ Flash messages and I18n
184
+ -----------------------
185
+
186
+ Flash messages are powered by I18n api. It checks for messages in the following
187
+ order:
188
+
189
+ flash.controller_name.action_name.status
190
+ flash.actions.action_name.status
191
+
192
+ If none is available, a default message in english set. Let's have a break from
193
+ projects and talk about CarsController. So in a create action, it will check for
194
+ flash messages in the following order:
195
+
196
+ flash.cars.create.status
197
+ flash.actions.create.status
198
+
199
+ The status can be :notice (when the object can be created, updated
200
+ or destroyed with success) or :error (when the objecy cannot be created
201
+ or updated).
202
+
203
+ Those messages are interpolated by using the resource class human name, which
204
+ is also localized and it means you can set:
205
+
206
+ flash:
207
+ actions:
208
+ create:
209
+ notice: "Hooray! {{resource}} was successfully created!"
210
+
211
+ It will replace {{resource}} for Car properly.
212
+
213
+ But sometimes, flash messages are not that simple. Going back
214
+ to cars example, you might want to say the brand of the car when it's
215
+ updated. Well, that's easy also:
216
+
217
+ flash:
218
+ cars:
219
+ update:
220
+ notice: "Hooray! You just tuned your {{car_brand}}!"
221
+
222
+ Since :car_name is not available for interpolation by default, you have
223
+ to overwrite interpolation_options.
224
+
225
+ def interpolation_options
226
+ { :car_brand => @car.brand }
227
+ end
228
+
229
+ Then you will finally have:
230
+
231
+ 'Hooray! You just tuned your Aston Martin!'
232
+
233
+ Belongs to
234
+ ----------
235
+
236
+ Finally, our Projects are going to get some Tasks. Then you create a
237
+ TasksController and do:
238
+
239
+ class TasksController < InheritedResources::Base
240
+ belongs_to :project
241
+ end
242
+
243
+ belongs_to accepts several options to be able to configure the association.
244
+ Remember that our projects have pretty urls? So if you thought that url like
245
+ /projects/:project_title/tasks would be a problem, I can assure you it won't:
246
+
247
+ class TasksController < InheritedResources::Base
248
+ belongs_to :project, :finder => :find_by_title!, :param => :project_title
249
+ end
250
+
251
+ Check belongs_to file for more customization. :)
252
+
253
+ Nested belongs to
254
+ -----------------
255
+
256
+ Now, our Tasks get some Comments and you need to nest even deeper. Good
257
+ practices says that you should never nest more than two resources, but sometimes
258
+ you have to for security reasons. So this is an example of how you can do it:
259
+
260
+ class CommentsController < InheritedResources::Base
261
+ nested_belongs_to :project
262
+ nested_belongs_to :task
263
+ end
264
+
265
+ nested_belongs_to is actually just an alias to belongs_to. This is an
266
+ alternative declaration:
267
+
268
+ class CommentsController < InheritedResources::Base
269
+ belongs_to :project do
270
+ belongs_to :task
271
+ end
272
+ end
273
+
274
+ Polymorphic belongs to
275
+ ----------------------
276
+
277
+ Now let's go even further. Our Projects is getting some Files and Messages
278
+ besides Tasks, and they are all commentable:
279
+
280
+ class CommentsController < InheritedResources::Base
281
+ belongs_to :task, :file, :message, :polymorphic => true
282
+ end
283
+
284
+ You can even use it with nested resources:
285
+
286
+ class CommentsController < InheritedResources::Base
287
+ belongs_to :project do
288
+ belongs_to :task, :file, :message, :polymorphic => true
289
+ end
290
+ end
291
+
292
+ When using polymorphic associations, you get some free helpers:
293
+
294
+ parent? #=> true
295
+ parent_type #=> :task
296
+ parent_class #=> Task
297
+ parent_instance #=> @task
298
+
299
+ Polymorphic controller is another great idea by James Golick and he also uses
300
+ that on resource_controller.
301
+
302
+ Singletons
303
+ ----------
304
+
305
+ Now we are going to add manager to projects. We say that Manager is a singleton
306
+ resource because a Project has just one manager. You should declare it as
307
+ has_one (or resource) in your routes.
308
+
309
+ To declare an association as singleton, you just have to give the :singleton
310
+ option.
311
+
312
+ class ManagersController < InheritedResources::Base
313
+ belongs_to :project, :singleton => true
314
+ end
315
+
316
+ It will deal with everything again and hide the action :index from you.
317
+
318
+ URL Helpers
319
+ -----------
320
+
321
+ When you use InheritedResources it creates some URL helpers for you.
322
+ And they handle everything for you.
323
+
324
+ # /posts/1/comments
325
+ resource_url # => /posts/1/comments/#{@comment.to_param}
326
+ resource_url(comment) # => /posts/1/comments/#{comment.to_param}
327
+ new_resource_url # => /posts/1/comments/new
328
+ edit_resource_url # => /posts/1/comments/#{@comment.to_param}/edit
329
+ collection_url # => /posts/1/comments
330
+
331
+ # /projects/1/tasks
332
+ resource_url # => /products/1/tasks/#{@task.to_param}
333
+ resource_url(task) # => /products/1/tasks/#{task.to_param}
334
+ new_resource_url # => /products/1/tasks/new
335
+ edit_resource_url # => /products/1/tasks/#{@task.to_param}/edit
336
+ collection_url # => /products/1/tasks
337
+
338
+ # /users
339
+ resource_url # => /users/#{@user.to_param}
340
+ resource_url(user) # => /users/#{user.to_param}
341
+ new_resource_url # => /users/new
342
+ edit_resource_url # => /users/#{@user.to_param}/edit
343
+ collection_url # => /users
344
+
345
+ The nice thing is that those urls are not guessed during runtime. They are
346
+ all created when your application is loaded (except for polymorphic
347
+ associations, that relies on Rails polymorphic_url).
348
+
349
+ What's next
350
+ -----------
351
+
352
+ I'm working on generators and some nice things to speed up and make easier
353
+ your controllers tests with mocking and stubs. :)
354
+
355
+ Bugs and Feedback
356
+ -----------------
357
+
358
+ If you discover any bugs, please send an e-mail to jose.valim@gmail.com
359
+ If you just want to give some positive feedback or drop a line, that's fine too!
360
+
361
+ Copyright (c) 2009 José Valim
362
+ http://josevalim.blogspot.com/
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Run tests for InheritedResources.'
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.pattern = 'test/**/*_test.rb'
8
+ t.verbose = true
9
+ end
10
+
11
+ desc 'Generate documentation for InheritedResources.'
12
+ Rake::RDocTask.new(:rdoc) do |rdoc|
13
+ rdoc.rdoc_dir = 'rdoc'
14
+ rdoc.title = 'InheritedResources'
15
+ rdoc.options << '--line-numbers' << '--inline-source'
16
+ rdoc.rdoc_files.include('README')
17
+ rdoc.rdoc_files.include('MIT-LICENSE')
18
+ rdoc.rdoc_files.include('lib/**/*.rb')
19
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require File.join(File.dirname(__FILE__), 'lib', 'inherited_resources')
@@ -0,0 +1,4 @@
1
+ dir = File.dirname(__FILE__)
2
+ require File.join(dir, 'inherited_resources', 'respond_to')
3
+
4
+ module InheritedResources; end
@@ -0,0 +1,272 @@
1
+ # = Inheriting
2
+ #
3
+ # To use InheritedResources you have to inherit from InheritedResources::Base
4
+ # class. This class have all Rails REST actions defined (index, show, new, edit
5
+ # update, create and destroy). The following definition is the same as a Rails
6
+ # scaffolded controller:
7
+ #
8
+ # class ProjectController < InheritedResources::Base
9
+ # end
10
+ #
11
+ # All actions are defined, check it!
12
+ #
13
+ # The next step is to define which mime types this controller provides:
14
+ #
15
+ # class ProjectController < InheritedResources::Base
16
+ # respond_to :html, :xml, :json
17
+ # end
18
+ #
19
+ # You just said that this controller will respond to :html, :xml and :json. You
20
+ # can also specify it based on actions:
21
+ #
22
+ # class ProjectController < InheritedResources::Base
23
+ # respond_to :html, :xml, :json
24
+ # respond_to :js, :only => :create
25
+ # respond_to :csv, :except => [ :destroy ]
26
+ # end
27
+ #
28
+ # How it works is simple. Let's suppose you have a json request on the action
29
+ # show. It will first try to render "projects/show.json.something". If it can't
30
+ # be found, it will call :to_json in the resource, which in this case is
31
+ # @project.
32
+ #
33
+ # If the resource @project doesn't respond to :to_json, we will render a 404
34
+ # Not Found.
35
+ #
36
+ # If you don't want to inherit all actions from InheritedResources::Base, call
37
+ # actions method with the actions you want to inherit:
38
+ #
39
+ # class ProjectController < InheritedResources::Base
40
+ # actions :index, :show, :new, :create, :edit, :update
41
+ # end
42
+ #
43
+ # Or:
44
+ #
45
+ # class ProjectController < InheritedResources::Base
46
+ # actions :all, :except => :destroy
47
+ # end
48
+ #
49
+ # = Extending the default behaviour
50
+ #
51
+ # Let's suppose that after destroying a project you want to redirect to your
52
+ # root url instead of redirecting to projects url. You just have to do:
53
+ #
54
+ # class ProjectController < InheritedResources::Base
55
+ # def destroy
56
+ # super do |format|
57
+ # format.html { redirect_to projects_url }
58
+ # end
59
+ # end
60
+ # end
61
+ #
62
+ # super? Yes, we agree that calling super is the right thing but it does not
63
+ # look nice. That's why all methods have aliases. So this is equivalent:
64
+ #
65
+ # class ProjectController < InheritedResources::Base
66
+ # def destroy
67
+ # destroy! do |format|
68
+ # format.html { redirect_to projects_url }
69
+ # end
70
+ # end
71
+ # end
72
+ #
73
+ # Since this is actually Ruby (and not a new DSL), if you want to do something
74
+ # before creating the project that is to small to deserve a before_filter, you
75
+ # could simply do:
76
+ #
77
+ # class ProjectController < InheritedResources::Base
78
+ # def create
79
+ # # do something different!
80
+ # create!
81
+ # end
82
+ # end
83
+ #
84
+ # And as instance variables are shared you can do more nice things.
85
+ # Let's suppose you want to create a project based on the current user:
86
+ #
87
+ # class ProjectController < InheritedResources::Base
88
+ # def create
89
+ # @project = @current_user.projects.build(params[:project])
90
+ # create!
91
+ # end
92
+ # end
93
+ #
94
+ # When you call create! the instance variable @project is already defined,
95
+ # so the method won't instanciate it again.
96
+ #
97
+ # The great thing is that we are not using blocks or nothing in special. We are
98
+ # just inheriting and calling the parent (super). You can extend even more
99
+ # without using blocks, please check helpers.rb for more info.
100
+ #
101
+ # = Flash and I18n
102
+ #
103
+ # Flash messages are changed through I18n API. If you have a ProjectsController,
104
+ # when a resource is updated with success, it will search for messages in the
105
+ # following order:
106
+ #
107
+ # 'flash.projects.update.notice'
108
+ # 'flash.actions.update.notice'
109
+ #
110
+ # If none of them are not available, it will show the default message:
111
+ #
112
+ # Project was successfully updated.
113
+ #
114
+ # The message will be set into flash[:notice].
115
+ # Messages can be interpolated, so you can do the following in your I18n files:
116
+ #
117
+ # flash:
118
+ # actions:
119
+ # update:
120
+ # notice: "Hooray! {{resource}} was updated with success!"
121
+ #
122
+ # It will replace {{resource}} by Project.human_name, which is also localized
123
+ # (check http://rails-i18n.org/wiki/pages/i18n-rails-guide for more info).
124
+ #
125
+ # But sometimes, flash messages are not that simple. You might want to say the
126
+ # the name of the project when it's updated. Well, that's easy also:
127
+ #
128
+ # flash:
129
+ # projects:
130
+ # update:
131
+ # notice: "Dear manager, {{project_name}} was successfully updated!"
132
+ #
133
+ # Since :project_name is not available for interpolation by default, you
134
+ # have to overwrite interpolation_options method on your controller.
135
+ #
136
+ # def interpolation_options
137
+ # { :project_name => @project.quoted_name }
138
+ # end
139
+ #
140
+ # Then you will finally have:
141
+ #
142
+ # 'Dear manager, "Make Rails Scale" was successfully updated!'
143
+ #
144
+ # Success messages appear on :create, :update and :destroy actions. Failure
145
+ # messages appear only on :create and :update.
146
+ #
147
+ # = Changing assumptions
148
+ #
149
+ # When you inherit from InheritedResources::Base, we make some assumptions on
150
+ # what is your resource_class, instance_name and collection_name.
151
+ #
152
+ # You can change those values by calling the class method defaults:
153
+ #
154
+ # class PeopleController < InheritedResources::Base
155
+ # defaults :resource_class => User, :instance_name => 'user', :collection_name => 'users'
156
+ # end
157
+ #
158
+ # Further customizations can be done replacing some methods. Check
159
+ # base_helpers.rb file for more information.
160
+ #
161
+ module InheritedResources
162
+ RESOURCES_ACTIONS = [ :index, :show, :new, :edit, :create, :update, :destroy ]
163
+
164
+ class Base < ::ApplicationController
165
+ include InheritedResources::BaseHelpers
166
+ extend InheritedResources::BelongsTo
167
+ extend InheritedResources::ClassMethods
168
+
169
+ helper_method :collection_url, :collection_path, :resource_url, :resource_path,
170
+ :new_resource_url, :new_resource_path, :edit_resource_url, :edit_resource_path
171
+
172
+ def self.inherited(base)
173
+ base.class_eval do
174
+ # Make all resources actions public
175
+ public *RESOURCES_ACTIONS
176
+ end
177
+
178
+ # Call super to register class in ApplicationController
179
+ super
180
+
181
+ # Creates and sets class accessors default values
182
+ initialize_resources_class_accessors!(base)
183
+ end
184
+
185
+ protected
186
+
187
+ # GET /resources
188
+ def index(&block)
189
+ respond_to(:with => collection, &block)
190
+ end
191
+ alias :index! :index
192
+
193
+ # GET /resources/1
194
+ def show(&block)
195
+ respond_to(:with => resource, &block)
196
+ end
197
+ alias :show! :show
198
+
199
+ # GET /resources/new
200
+ def new(&block)
201
+ respond_to(:with => build_resource, &block)
202
+ end
203
+ alias :new! :new
204
+
205
+ # GET /resources/1/edit
206
+ def edit(&block)
207
+ respond_to(:with => resource, &block)
208
+ end
209
+ alias :edit! :edit
210
+
211
+ # POST /resources
212
+ def create(&block)
213
+ object = build_resource(params[resource_instance_name])
214
+
215
+ if object.save
216
+ set_flash_message!(:notice, '{{resource}} was successfully created.')
217
+
218
+ respond_to(:with => object, :status => :created, :location => resource_url) do |format|
219
+ yield(format) if block_given?
220
+ format.html { redirect_to(resource_url) }
221
+ end
222
+ else
223
+ set_flash_message!(:error)
224
+
225
+ respond_to(:with => object.errors, :status => :unprocessable_entity) do |format|
226
+ yield(format) if block_given?
227
+ format.html { render :action => "new" }
228
+ end
229
+ end
230
+ end
231
+ alias :create! :create
232
+
233
+ # PUT /resources/1
234
+ def update(&block)
235
+ object = resource
236
+
237
+ if object.update_attributes(params[resource_instance_name])
238
+ set_flash_message!(:notice, '{{resource}} was successfully updated.')
239
+
240
+ respond_to do |format|
241
+ yield(format) if block_given?
242
+ format.html { redirect_to(resource_url) }
243
+ format.all { head :ok }
244
+ end
245
+ else
246
+ set_flash_message!(:error)
247
+
248
+ respond_to(:with => object.errors, :status => :unprocessable_entity) do |format|
249
+ yield(format) if block_given?
250
+ format.html { render :action => "edit" }
251
+ end
252
+ end
253
+ end
254
+ alias :update! :update
255
+
256
+ # DELETE /resources/1
257
+ def destroy(&block)
258
+ resource.destroy
259
+
260
+ set_flash_message!(:notice, '{{resource}} was successfully destroyed.')
261
+
262
+ respond_to do |format|
263
+ yield(format) if block_given?
264
+ format.html { redirect_to(collection_url) }
265
+ format.all { head :ok }
266
+ end
267
+ end
268
+ alias :destroy! :destroy
269
+
270
+ end
271
+ end
272
+