super_resources 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. data/.DS_Store +0 -0
  2. data/.gitignore +20 -0
  3. data/Gemfile +8 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +215 -0
  6. data/Rakefile +1 -0
  7. data/lib/super_resources/actions.rb +49 -0
  8. data/lib/super_resources/cancan.rb +15 -0
  9. data/lib/super_resources/controller.rb +12 -0
  10. data/lib/super_resources/has_scope.rb +9 -0
  11. data/lib/super_resources/nesting.rb +110 -0
  12. data/lib/super_resources/resources.rb +88 -0
  13. data/lib/super_resources/url_helpers.rb +61 -0
  14. data/lib/super_resources/version.rb +3 -0
  15. data/lib/super_resources.rb +11 -0
  16. data/spec/controllers/actions_nested_spec.rb +115 -0
  17. data/spec/controllers/actions_spec.rb +142 -0
  18. data/spec/controllers/actions_with_blocks_spec.rb +173 -0
  19. data/spec/controllers/paths_spec.rb +114 -0
  20. data/spec/controllers/redirects_spec.rb +39 -0
  21. data/spec/controllers/resources_adapted_spec.rb +192 -0
  22. data/spec/controllers/resources_nested_spec.rb +37 -0
  23. data/spec/controllers/resources_spec.rb +35 -0
  24. data/spec/dummy/.DS_Store +0 -0
  25. data/spec/dummy/README.rdoc +261 -0
  26. data/spec/dummy/Rakefile +7 -0
  27. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  28. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  29. data/spec/dummy/app/controllers/adapted_resources_controller.rb +24 -0
  30. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  31. data/spec/dummy/app/controllers/child_resources_controller.rb +2 -0
  32. data/spec/dummy/app/controllers/grandparent_resources_controller.rb +13 -0
  33. data/spec/dummy/app/controllers/great_grandparent_resources_controller.rb +46 -0
  34. data/spec/dummy/app/controllers/my_adapted_resources_controller.rb +8 -0
  35. data/spec/dummy/app/controllers/parent_resources_controller.rb +2 -0
  36. data/spec/dummy/app/controllers/simple_resources_controller.rb +2 -0
  37. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  38. data/spec/dummy/app/mailers/.gitkeep +0 -0
  39. data/spec/dummy/app/models/.gitkeep +0 -0
  40. data/spec/dummy/app/models/adapted_resource.rb +3 -0
  41. data/spec/dummy/app/models/child_resource.rb +5 -0
  42. data/spec/dummy/app/models/grandparent_resource.rb +6 -0
  43. data/spec/dummy/app/models/great_grandparent_resource.rb +3 -0
  44. data/spec/dummy/app/models/my_adapted_resource.rb +2 -0
  45. data/spec/dummy/app/models/parent_resource.rb +6 -0
  46. data/spec/dummy/app/models/simple_resource.rb +2 -0
  47. data/spec/dummy/app/views/application/edit.html.erb +1 -0
  48. data/spec/dummy/app/views/application/index.html.erb +1 -0
  49. data/spec/dummy/app/views/application/new.html.erb +1 -0
  50. data/spec/dummy/app/views/application/show.html.erb +1 -0
  51. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  52. data/spec/dummy/config/application.rb +64 -0
  53. data/spec/dummy/config/boot.rb +10 -0
  54. data/spec/dummy/config/database.yml +25 -0
  55. data/spec/dummy/config/environment.rb +5 -0
  56. data/spec/dummy/config/environments/development.rb +37 -0
  57. data/spec/dummy/config/environments/production.rb +67 -0
  58. data/spec/dummy/config/environments/test.rb +37 -0
  59. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  60. data/spec/dummy/config/initializers/inflections.rb +15 -0
  61. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  62. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  63. data/spec/dummy/config/initializers/session_store.rb +8 -0
  64. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  65. data/spec/dummy/config/locales/en.yml +5 -0
  66. data/spec/dummy/config/routes.rb +17 -0
  67. data/spec/dummy/config.ru +4 -0
  68. data/spec/dummy/db/migrate/20130117225232_create_resources.rb +27 -0
  69. data/spec/dummy/db/schema.rb +40 -0
  70. data/spec/dummy/lib/assets/.gitkeep +0 -0
  71. data/spec/dummy/log/.gitkeep +0 -0
  72. data/spec/dummy/public/404.html +26 -0
  73. data/spec/dummy/public/422.html +26 -0
  74. data/spec/dummy/public/500.html +25 -0
  75. data/spec/dummy/public/favicon.ico +0 -0
  76. data/spec/spec_helper.rb +39 -0
  77. data/super_resources.gemspec +21 -0
  78. metadata +201 -0
data/.DS_Store ADDED
Binary file
data/.gitignore ADDED
@@ -0,0 +1,20 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+
19
+ spec/dummy/log/*.log
20
+ spec/dummy/db/*.sqlite3
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'rails', '~> 3.1'
6
+
7
+ gem 'sqlite3'
8
+ gem 'rspec-rails'
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012, 2013 Habanero Software Pty Limited
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,215 @@
1
+ # SuperResources
2
+
3
+ SuperResources DRYs up your controller code by abstracting your controller's strandard RESTful actions and by providing
4
+ standard helpers to access the controller's target resource(s) in a consistent way across all controllers. More than that,
5
+ SuperResources exploits the application's routes to provide simplified path helpers for nested resources.
6
+
7
+ With SuperResources, in the great majority of common REST situations, you can use the same resource helpers and path helpers,
8
+ regardless of the the specific type of resource or how it is nested, even if the resource is nested under many other resources.
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ gem 'super_resources'
15
+
16
+ And then execute:
17
+
18
+ bundle install
19
+
20
+ Or install it yourself as:
21
+
22
+ gem install super_resources
23
+
24
+ ## Usage
25
+
26
+ To gain all the standard RESTful actions, just `include SuperResources::Controller` in your controller:
27
+
28
+ class OrganizationUnitsController < ApplicationController
29
+ include SuperResources::Controller
30
+ end
31
+
32
+ ### Resource Helper Methods
33
+
34
+ SuperResources provides helper methods that you can use directly in the controller, views or helper methods:
35
+
36
+ resource
37
+ collection
38
+
39
+ For member actions, `resource` answers a single object that the RESTFUL is operating on.
40
+ For collection actions (i.e `index1), `collection` answer a scoped collection of objects.
41
+
42
+ SuperResources does away with specifically named instance variables, such as those created by standard scaffolds. For example, in the example above, SuperResources does not give you `@organization_unit` or `@organization_units` for free. You won't need them in the common cases. Using `resource` and `collection` in every controller makes for easier coding and maintenance.
43
+
44
+ ### Path Helper Methods
45
+
46
+ SuperResources provides a set of vastly simplified path helpers.
47
+
48
+ collection_path #=> path to the resource's index action
49
+ resource_path(object = resource)
50
+ new_resource_path
51
+ edit_resource_path(object = resource)
52
+
53
+ Note that the helper methods that require an input argument, assumes the current resource by default, so you don't have to pass it in.
54
+
55
+ #### These Helper Methods Work Even When the Resource is Nested
56
+
57
+ Because SuperResources uses the metadata created by your routes declarations to work out whether the resource has been nested and if so, automatically uses the nesting objects to build complete paths. This relieves you of passing in an array to the path helper.
58
+
59
+ With this feature alone, SuperResources cleans up your code and makes it more reusable. For example, the same code can be used when you
60
+ have a resource that is nested inside multiple other objects. SuperResources dynamically works out the nesting that applies in each case.
61
+
62
+ ## Nested Resource
63
+
64
+ Let's face it: deailing with nested resources has always been a pain. All that fiddling about, getting the path names and inputs right. Chane the nesting and you have to go through and chaneg all your path calls too. Then, if you have a resource that can be nested within multiple other resources, such as when you have an associative object and you want to navigate to it from any of it associations, the permutations become very complex.
65
+
66
+ It should be much easier, especially when you take routes into account. If I have an action that is matched to this route:
67
+
68
+ /notes/:note_id/pages/:id
69
+
70
+ then shouldn't I have paths available that can work out the nesting context, so that I don't hard code it?
71
+
72
+ SuperResources does this. For example, including SuperResources in `PagesController` will allow me to simply call,
73
+ for example, `edit_resource_path` and the code has been actioned through the above route, the nesting with a Note identified by `:note_id` will be assumed. Even better, if the same code is actioned by another route with different nesting, SuperResources will get that right too.
74
+
75
+ If you need, such as when you want to link 'outside the nest' as it were, you still have `note_page_path(note, page)` available to you.
76
+
77
+ ### Parent Helper Method
78
+
79
+ Sometimes you want to use the object that is nesting your resource, such as when you want to customize a redirect. SuperResources provides
80
+ `parent` to answer that object. For example given, the following route:
81
+
82
+ /notes/:note_id/pages/:id
83
+
84
+
85
+ calling `parent` will answer a Note object with an id of `:note_id`.
86
+
87
+ For deeper nests, the immediately nested object is always answered by `parent`. For example, given this route:
88
+
89
+ /authors/:author_id/notes/:note_id/pages/:id
90
+
91
+ calling `parent` will still answer a Note object with an id of `:note_id`.
92
+
93
+ ### Accessing Route Objects
94
+
95
+ Any nested route implies a component hierarchy of objects. SuperResources allows you to access these objects bye a convenient name.
96
+
97
+ For example, given this route:
98
+
99
+ /authors/:author_id/notes/:note_id/pages/:id
100
+
101
+ you can make these calls:
102
+
103
+ author #=> Author with an id of :author_id
104
+ note #=> Note with an id of :note_id
105
+ page #=> Page with an id of :id
106
+
107
+ An example of a place where you will want these, is in a layout template that presents information about the nesting objects. For example, you may want to show a page inside an author layout template. The author layout template will present information about the author. In this case, the layout will be used in the context of `PagesController`, so you can't refer to `resource` in the layout, since it will answer the page, not the author. You need some way to arbitrarily refer to the author. Being able to call `author` provides this.
108
+
109
+ ## Adapting and Customising
110
+
111
+ ### Resource Class
112
+
113
+ SuperResources derives the class of the target resource from the controller name. For example, `OrganizationUnitsController` operates, by default, on resources of the class `OrganizationUnit`. If you want to change this, redefine hotspot method `resource_class`, for example:
114
+
115
+ class TeamsController < ApplicationController
116
+ include SuperResources::Controller
117
+
118
+ protected
119
+
120
+ def resource_class
121
+ OrganizationUnit
122
+ end
123
+ end
124
+
125
+ ### Resource Helper Methods
126
+
127
+ Yes, you can adapt these to suit your needs.
128
+
129
+ Both `resource` and `collection` accept a block, which SuperResources uses to stitch into its internal implementation, so tht any subsequent calls to these helpers uses your implementation.
130
+ The block for `resource` shall answer a single instance of the resource class and the block for `collection` shall answer an array of instances of the resource class.
131
+
132
+ For example, if you wanted 'TeamsController#collection' to return only those teams that the current user has joined, you would write an implementation of `collection` that calls its super, passing a block the evalautes to the right collection:
133
+
134
+ def collection
135
+ super { resource_class.joined_by(current_user) }
136
+ end
137
+
138
+ If that looks strange, bear in mind it's been designed so that you don't need to know how SuperResources internally uses your preferred implementation.
139
+
140
+ ### Finder Method
141
+
142
+ Before being able to use the result of `resource`, SuperResources may need to find it. The canonical way to do this is to do:
143
+
144
+ resource_class.find(:params[:id])
145
+
146
+ While SuperResource uses the `find` method as the default, you can choose another finder method by redefining `finder_method`. For example:
147
+
148
+ class PagesController < ApplicationController
149
+
150
+ protected
151
+
152
+ def finder_method
153
+ :find_by_position
154
+ end
155
+ end
156
+
157
+ ### Builder Method
158
+
159
+ SuperResources extracts the construction of a new resource into the `build_resource` method. If you need to create a new resource, say in a special action, use 'build_resource' so that SuperResource can also keep track of it (for example, make sure that `resource' answers the built object).
160
+
161
+ If you need to do specialized work for the build, pass the a block to `build_resource` that evaluates to an object with the state you need. For example:
162
+
163
+ build_resource do
164
+ resource_class.new do |p|
165
+ # initialize the state here
166
+ end
167
+ end
168
+
169
+ More commonly, you would redefine the whole method so that it always behaves the same way for its enclosing controller:
170
+
171
+ def build_resource
172
+ super do
173
+ resource_class.new do |p|
174
+ # initialize the state here
175
+ end
176
+ end
177
+ end
178
+
179
+ ### Redefining Actions
180
+
181
+ Yes, you can. All actions defined by SuperResources use responders and accept parameters to pass to `respond_with`, so customizing these parameters is a common adaptation.
182
+
183
+ For example, suppose that after creating a comment, you want to redirect to an index of comments that apply to the same parent. Adapt teh action like this:
184
+
185
+ def create
186
+ super :location => polymorphic_url([ parent, :comments ])
187
+ end
188
+
189
+ Anything you can pass to `respond_with`, you can pass to he super call, including a block.
190
+
191
+ You could, of course, completely redefine an action:
192
+
193
+ def new
194
+ # knock yourself out
195
+ end
196
+
197
+ ### Defining Actions
198
+
199
+ Just do it. Declare them in your controller and match them in routes. All the SuperResources helpers are still available to you.
200
+
201
+ ## Acknowledgments
202
+
203
+ SuperResources would never have happened without InheritedResources [https://github.com/josevalim/inherited_resources] existing first.
204
+ We preferred the idea of abstracting and extracting RESTful actions out of all our controllers and we're not so keen on scaffolds generating
205
+ un-DRY code. We used InheritedResources in a production deployed application [meetlinkshare.com], gained some experience and decided we wanted an even DRYer tool.
206
+
207
+ The basic mechanics of SuperResources was hacked out during Rails Camp 12 in Tasmania, Australia and was subsequently applied to MeetLinkShare.
208
+
209
+ ## Contributing
210
+
211
+ 1. Fork it
212
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
213
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
214
+ 4. Push to the branch (`git push origin my-new-feature`)
215
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,49 @@
1
+ module SuperResources
2
+ module Actions
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ respond_to :html
7
+ end
8
+
9
+ def index(options = {}, &block)
10
+ respond_with(*(with_chain(collection) << options), &block)
11
+ end
12
+
13
+ def show(options = {}, &block)
14
+ respond_with(*(with_chain(resource) << options), &block)
15
+ end
16
+
17
+ def new(options = {}, &block)
18
+ respond_with(*(with_chain(build_resource) << options), &block)
19
+ end
20
+
21
+ def edit(options = {}, &block)
22
+ respond_with(*(with_chain(resource) << options), &block)
23
+ end
24
+
25
+ def create(options = {}, &block)
26
+ if create_resource(resource_params)
27
+ options[:location] ||= resource_url
28
+ end
29
+
30
+ respond_with(*(with_chain(resource) << options), &block)
31
+ end
32
+
33
+ def update(options = {}, &block)
34
+ if update_resource(resource_params)
35
+ options[:location] ||= resource_url
36
+ end
37
+
38
+ respond_with(*(with_chain(resource) << options), &block)
39
+ end
40
+
41
+ def destroy(options = {}, &block)
42
+ if destroy_resource
43
+ options[:location] ||= collection_url
44
+ end
45
+
46
+ respond_with(*(with_chain(resource) << options), &block)
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,15 @@
1
+ module SuperController
2
+ module Cancan
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ before_filter :authorize_resource
7
+ end
8
+
9
+ protected
10
+
11
+ def authorize_resource
12
+ #authorize! action_name.to_sym, resource
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,12 @@
1
+ module SuperResources
2
+ module Controller
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ include Actions
7
+ include Nesting
8
+ include HasScope
9
+ include URLHelpers
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,9 @@
1
+ module SuperResources
2
+ module HasScope
3
+ protected
4
+
5
+ def end_of_association_chain
6
+ respond_to?(:apply_scopes) ? apply_scopes(super) : super
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,110 @@
1
+ module SuperResources
2
+ module Nesting
3
+ extend ActiveSupport::Concern
4
+ include Resources
5
+
6
+ included do
7
+ helper_method :association_chain, :with_chain, :method_missing, :respond_to?
8
+ end
9
+
10
+ def respond_to?(m, *args)
11
+ m.in?(symbols_for_association_chain) ? true : super
12
+ end
13
+
14
+ protected
15
+
16
+ def method_missing(m, *args, &block)
17
+ case
18
+ when m == resource_params_name
19
+ resource
20
+ when i = symbols_for_association_chain.index(m)
21
+ association_chain[i]
22
+ else
23
+ super
24
+ end
25
+ end
26
+
27
+ def collection(&block)
28
+ if block_given?
29
+ @collection = yield
30
+ else
31
+ @collection ||= end_of_association_chain
32
+ end
33
+ end
34
+
35
+ def resource(&block)
36
+ if block_given?
37
+ @resource = yield
38
+ else
39
+ @resource ||= end_of_association_chain.send(finder_method, params[:id])
40
+ end
41
+ end
42
+
43
+ def build_resource(&block)
44
+ if block_given?
45
+ @resource = yield
46
+ else
47
+ @resource ||= end_of_association_chain.build(resource_params)
48
+ end
49
+ end
50
+
51
+ def nested?
52
+ association_chain.any?
53
+ end
54
+
55
+ def parent
56
+ association_chain.last
57
+ end
58
+
59
+ def end_of_association_chain
60
+ nested? ? parent.send(resource_collection_name) : resource_class.scoped
61
+ end
62
+
63
+ def association_chain
64
+ @association_chain ||=
65
+ symbols_for_association_chain.inject([]) do |chain, symbol|
66
+ chain << chain_link(symbol, chain.last)
67
+ end
68
+ end
69
+
70
+ def chain_link(symbol, previous_link)
71
+ link = if previous_link
72
+ previous_link.send(symbol.to_s.pluralize.to_sym)
73
+ else
74
+ symbol.to_s.classify.safe_constantize
75
+ end
76
+
77
+ link.find(params[:"#{symbol}_id"])
78
+ end
79
+
80
+ def symbols_for_association_chain
81
+ @symbols_for_association_chain ||=
82
+ route.parts \
83
+ .select { |p| p.to_s =~ %r(_id$) } \
84
+ .map { |p| p.to_s.gsub(/_id$/, '').to_sym }
85
+ @symbols_for_association_chain
86
+ end
87
+
88
+ def with_chain(object)
89
+ association_chain + [ object ]
90
+ end
91
+
92
+ def route
93
+ @route ||= begin
94
+ routes.formatter.send(:match_route, nil, path_parameters) do |route|
95
+ # TODO: don't assume the first route is good, validate!
96
+ # TODO: don't use break
97
+ break route
98
+ end
99
+ end
100
+ end
101
+
102
+ def routes
103
+ request.env['action_dispatch.routes']
104
+ end
105
+
106
+ def path_parameters
107
+ request.env['action_dispatch.request.path_parameters'].symbolize_keys
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,88 @@
1
+ module SuperResources
2
+ module Resources
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ helper_method :collection, :collection=, :resource, :resource=, :resource_class, :parent, :nested?
7
+ end
8
+
9
+ protected
10
+
11
+ def resource_class
12
+ controller_name.classify.singularize.safe_constantize
13
+ end
14
+
15
+ def resource_instance_name
16
+ controller_name.singularize.to_sym
17
+ end
18
+
19
+ def resource_params_name
20
+ resource_instance_name
21
+ end
22
+
23
+ def resource_collection_name
24
+ controller_name.to_sym
25
+ end
26
+
27
+ def collection(&block)
28
+ if block_given?
29
+ @collection = yield
30
+ else
31
+ @collection ||= resource_class.scoped
32
+ end
33
+ end
34
+
35
+ def collection=(c)
36
+ @collection = c
37
+ end
38
+
39
+ def resource(&block)
40
+ if block_given?
41
+ @resource = yield
42
+ else
43
+ @resource ||= resource_class.send(finder_method, params[:id])
44
+ end
45
+ end
46
+
47
+ def resource=(r)
48
+ @resource = r
49
+ end
50
+
51
+ def finder_method
52
+ :find
53
+ end
54
+
55
+ def nested?
56
+ false
57
+ end
58
+
59
+ def parent
60
+ nil
61
+ end
62
+
63
+ def build_resource(&block)
64
+ if block_given?
65
+ @resource = yield
66
+ else
67
+ @resource ||= resource_class.new(resource_params)
68
+ end
69
+ end
70
+
71
+ def create_resource(attributes)
72
+ build_resource.attributes = attributes
73
+ resource.save
74
+ end
75
+
76
+ def update_resource(attributes)
77
+ resource.update_attributes(attributes)
78
+ end
79
+
80
+ def resource_params
81
+ params[resource_params_name] || {}
82
+ end
83
+
84
+ def destroy_resource
85
+ resource.destroy
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,61 @@
1
+ module SuperResources
2
+ module URLHelpers
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ helper_method :collection_path, :resource_path, :new_resource_path,
7
+ :edit_resource_path
8
+ end
9
+
10
+ protected
11
+
12
+ def full_association_chain_symbols
13
+ symbols_for_association_chain + [resource_instance_name]
14
+ end
15
+
16
+ def collection_route
17
+ chain = symbols_for_association_chain + [resource_collection_name]
18
+ :"#{chain.join('_')}_url"
19
+ end
20
+
21
+ def resource_route
22
+ :"#{full_association_chain_symbols.join('_')}_url"
23
+ end
24
+
25
+ def new_resource_route
26
+ :"new_#{resource_route}"
27
+ end
28
+
29
+ def edit_resource_route
30
+ :"edit_#{resource_route}"
31
+ end
32
+
33
+ def collection_url
34
+ send(collection_route, *association_chain)
35
+ end
36
+
37
+ alias_method :collection_path, :collection_url
38
+
39
+ def resource_url(object = resource)
40
+ if object.persisted?
41
+ send(resource_route, *(association_chain + [object]))
42
+ else
43
+ collection_url # probably a new action
44
+ end
45
+ end
46
+
47
+ alias_method :resource_path, :resource_url
48
+
49
+ def new_resource_url
50
+ send(new_resource_route, *association_chain)
51
+ end
52
+
53
+ alias_method :new_resource_path, :new_resource_url
54
+
55
+ def edit_resource_url(object = resource)
56
+ send(edit_resource_route, *(association_chain + [object]))
57
+ end
58
+
59
+ alias_method :edit_resource_path, :edit_resource_url
60
+ end
61
+ end
@@ -0,0 +1,3 @@
1
+ module SuperResources
2
+ VERSION = "1.0.0.rc1"
3
+ end
@@ -0,0 +1,11 @@
1
+ module SuperResources
2
+ autoload :Actions, "super_resources/actions"
3
+ autoload :Controller, "super_resources/controller"
4
+ autoload :Nesting, "super_resources/nesting"
5
+ autoload :Resources, "super_resources/resources"
6
+ autoload :URLHelpers, "super_resources/url_helpers"
7
+ autoload :Version, "super_resources/version"
8
+
9
+ autoload :HasScope, "super_resources/has_scope"
10
+ autoload :Cancan, "super_resources/cancan"
11
+ end