matid-resource_controller 0.6.5

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 (227) hide show
  1. data/LICENSE +23 -0
  2. data/README.rdoc +330 -0
  3. data/VERSION.yml +4 -0
  4. data/generators/scaffold_resource/USAGE +29 -0
  5. data/generators/scaffold_resource/scaffold_resource_generator.rb +179 -0
  6. data/generators/scaffold_resource/templates/controller.rb +2 -0
  7. data/generators/scaffold_resource/templates/fixtures.yml +10 -0
  8. data/generators/scaffold_resource/templates/functional_test.rb +57 -0
  9. data/generators/scaffold_resource/templates/helper.rb +2 -0
  10. data/generators/scaffold_resource/templates/migration.rb +15 -0
  11. data/generators/scaffold_resource/templates/model.rb +2 -0
  12. data/generators/scaffold_resource/templates/old_migration.rb +13 -0
  13. data/generators/scaffold_resource/templates/rspec/functional_spec.rb +255 -0
  14. data/generators/scaffold_resource/templates/rspec/helper_spec.rb +11 -0
  15. data/generators/scaffold_resource/templates/rspec/routing_spec.rb +61 -0
  16. data/generators/scaffold_resource/templates/rspec/unit_spec.rb +11 -0
  17. data/generators/scaffold_resource/templates/rspec/views/edit_spec.rb +28 -0
  18. data/generators/scaffold_resource/templates/rspec/views/index_spec.rb +26 -0
  19. data/generators/scaffold_resource/templates/rspec/views/new_spec.rb +30 -0
  20. data/generators/scaffold_resource/templates/rspec/views/show_spec.rb +25 -0
  21. data/generators/scaffold_resource/templates/shoulda_functional_test.rb +19 -0
  22. data/generators/scaffold_resource/templates/unit_test.rb +7 -0
  23. data/generators/scaffold_resource/templates/view__form.erb +6 -0
  24. data/generators/scaffold_resource/templates/view__form.haml +5 -0
  25. data/generators/scaffold_resource/templates/view_edit.erb +16 -0
  26. data/generators/scaffold_resource/templates/view_edit.haml +11 -0
  27. data/generators/scaffold_resource/templates/view_index.erb +22 -0
  28. data/generators/scaffold_resource/templates/view_index.haml +19 -0
  29. data/generators/scaffold_resource/templates/view_new.erb +12 -0
  30. data/generators/scaffold_resource/templates/view_new.haml +9 -0
  31. data/generators/scaffold_resource/templates/view_show.erb +9 -0
  32. data/generators/scaffold_resource/templates/view_show.haml +9 -0
  33. data/lib/resource_controller.rb +23 -0
  34. data/lib/resource_controller/accessors.rb +77 -0
  35. data/lib/resource_controller/base.rb +15 -0
  36. data/lib/resource_controller/controller.rb +38 -0
  37. data/lib/resource_controller/helpers.rb +27 -0
  38. data/lib/resource_controller/helpers/current_objects.rb +73 -0
  39. data/lib/resource_controller/helpers/nested.rb +67 -0
  40. data/lib/resource_controller/helpers/singleton_customizations.rb +64 -0
  41. data/lib/resource_controller/helpers/urls.rb +132 -0
  42. data/lib/resource_controller/singleton.rb +15 -0
  43. data/lib/urligence.rb +50 -0
  44. data/rails/init.rb +6 -0
  45. data/test/Rakefile +10 -0
  46. data/test/app/controllers/accounts_controller.rb +6 -0
  47. data/test/app/controllers/application_controller.rb +5 -0
  48. data/test/app/controllers/cms/options_controller.rb +3 -0
  49. data/test/app/controllers/cms/personnel_controller.rb +2 -0
  50. data/test/app/controllers/cms/photos_controller.rb +6 -0
  51. data/test/app/controllers/cms/products_controller.rb +3 -0
  52. data/test/app/controllers/comments_controller.rb +3 -0
  53. data/test/app/controllers/images_controller.rb +4 -0
  54. data/test/app/controllers/options_controller.rb +8 -0
  55. data/test/app/controllers/people_controller.rb +9 -0
  56. data/test/app/controllers/photos_controller.rb +12 -0
  57. data/test/app/controllers/posts_controller.rb +10 -0
  58. data/test/app/controllers/projects_controller.rb +3 -0
  59. data/test/app/controllers/somethings_controller.rb +3 -0
  60. data/test/app/controllers/tags_controller.rb +13 -0
  61. data/test/app/controllers/users_controller.rb +12 -0
  62. data/test/app/helpers/accounts_helper.rb +2 -0
  63. data/test/app/helpers/application_helper.rb +3 -0
  64. data/test/app/helpers/cms/products_helper.rb +2 -0
  65. data/test/app/helpers/comments_helper.rb +2 -0
  66. data/test/app/helpers/images_helper.rb +2 -0
  67. data/test/app/helpers/options_helper.rb +2 -0
  68. data/test/app/helpers/people_helper.rb +2 -0
  69. data/test/app/helpers/photos_helper.rb +2 -0
  70. data/test/app/helpers/posts_helper.rb +2 -0
  71. data/test/app/helpers/projects_helper.rb +2 -0
  72. data/test/app/helpers/somethings_helper.rb +2 -0
  73. data/test/app/helpers/tags_helper.rb +2 -0
  74. data/test/app/helpers/users_helper.rb +2 -0
  75. data/test/app/models/account.rb +4 -0
  76. data/test/app/models/comment.rb +3 -0
  77. data/test/app/models/image.rb +3 -0
  78. data/test/app/models/option.rb +3 -0
  79. data/test/app/models/personnel.rb +3 -0
  80. data/test/app/models/photo.rb +5 -0
  81. data/test/app/models/post.rb +3 -0
  82. data/test/app/models/product.rb +3 -0
  83. data/test/app/models/project.rb +2 -0
  84. data/test/app/models/something.rb +2 -0
  85. data/test/app/models/tag.rb +3 -0
  86. data/test/app/models/user.rb +3 -0
  87. data/test/app/views/accounts/_form.html.erb +4 -0
  88. data/test/app/views/accounts/edit.html.erb +14 -0
  89. data/test/app/views/accounts/new.html.erb +12 -0
  90. data/test/app/views/accounts/show.html.erb +5 -0
  91. data/test/app/views/cms/options/edit.rhtml +17 -0
  92. data/test/app/views/cms/options/index.rhtml +20 -0
  93. data/test/app/views/cms/options/new.rhtml +16 -0
  94. data/test/app/views/cms/options/show.rhtml +8 -0
  95. data/test/app/views/cms/photos/edit.rhtml +17 -0
  96. data/test/app/views/cms/photos/index.rhtml +20 -0
  97. data/test/app/views/cms/photos/new.rhtml +16 -0
  98. data/test/app/views/cms/photos/show.rhtml +8 -0
  99. data/test/app/views/cms/products/edit.rhtml +17 -0
  100. data/test/app/views/cms/products/index.rhtml +20 -0
  101. data/test/app/views/cms/products/new.rhtml +16 -0
  102. data/test/app/views/cms/products/show.rhtml +8 -0
  103. data/test/app/views/comments/edit.rhtml +27 -0
  104. data/test/app/views/comments/index.rhtml +24 -0
  105. data/test/app/views/comments/new.rhtml +26 -0
  106. data/test/app/views/comments/show.rhtml +18 -0
  107. data/test/app/views/images/_form.html.erb +4 -0
  108. data/test/app/views/images/edit.html.erb +14 -0
  109. data/test/app/views/images/new.html.erb +12 -0
  110. data/test/app/views/layouts/application.rhtml +17 -0
  111. data/test/app/views/layouts/comments.rhtml +17 -0
  112. data/test/app/views/layouts/options.rhtml +17 -0
  113. data/test/app/views/layouts/people.rhtml +17 -0
  114. data/test/app/views/layouts/photos.rhtml +17 -0
  115. data/test/app/views/layouts/projects.rhtml +17 -0
  116. data/test/app/views/layouts/somethings.rhtml +17 -0
  117. data/test/app/views/layouts/tags.rhtml +17 -0
  118. data/test/app/views/options/_form.html.erb +8 -0
  119. data/test/app/views/options/edit.html.erb +16 -0
  120. data/test/app/views/options/index.html.erb +21 -0
  121. data/test/app/views/options/new.html.erb +12 -0
  122. data/test/app/views/options/show.html.erb +10 -0
  123. data/test/app/views/people/edit.rhtml +17 -0
  124. data/test/app/views/people/index.rhtml +20 -0
  125. data/test/app/views/people/new.rhtml +16 -0
  126. data/test/app/views/people/show.rhtml +8 -0
  127. data/test/app/views/photos/edit.rhtml +17 -0
  128. data/test/app/views/photos/index.rhtml +20 -0
  129. data/test/app/views/photos/new.rhtml +16 -0
  130. data/test/app/views/photos/show.rhtml +8 -0
  131. data/test/app/views/posts/edit.rhtml +22 -0
  132. data/test/app/views/posts/index.rhtml +22 -0
  133. data/test/app/views/posts/new.rhtml +21 -0
  134. data/test/app/views/posts/show.rhtml +13 -0
  135. data/test/app/views/projects/edit.rhtml +17 -0
  136. data/test/app/views/projects/index.rhtml +20 -0
  137. data/test/app/views/projects/new.rhtml +16 -0
  138. data/test/app/views/projects/show.rhtml +8 -0
  139. data/test/app/views/somethings/edit.rhtml +17 -0
  140. data/test/app/views/somethings/index.rhtml +20 -0
  141. data/test/app/views/somethings/new.rhtml +16 -0
  142. data/test/app/views/somethings/show.rhtml +8 -0
  143. data/test/app/views/tags/edit.rhtml +17 -0
  144. data/test/app/views/tags/index.rhtml +20 -0
  145. data/test/app/views/tags/index.rjs +0 -0
  146. data/test/app/views/tags/new.rhtml +16 -0
  147. data/test/app/views/tags/show.rhtml +8 -0
  148. data/test/app/views/users/edit.rhtml +17 -0
  149. data/test/app/views/users/index.rhtml +20 -0
  150. data/test/app/views/users/new.rhtml +16 -0
  151. data/test/app/views/users/show.rhtml +8 -0
  152. data/test/config/boot.rb +110 -0
  153. data/test/config/database.yml +9 -0
  154. data/test/config/environment.rb +49 -0
  155. data/test/config/environments/development.rb +17 -0
  156. data/test/config/environments/test.rb +19 -0
  157. data/test/config/initializers/inflections.rb +14 -0
  158. data/test/config/routes.rb +61 -0
  159. data/test/db/migrate/001_create_posts.rb +12 -0
  160. data/test/db/migrate/002_create_products.rb +11 -0
  161. data/test/db/migrate/003_create_comments.rb +13 -0
  162. data/test/db/migrate/004_create_options.rb +13 -0
  163. data/test/db/migrate/005_create_photos.rb +11 -0
  164. data/test/db/migrate/006_create_tags.rb +17 -0
  165. data/test/db/migrate/007_create_somethings.rb +11 -0
  166. data/test/db/migrate/008_create_accounts.rb +11 -0
  167. data/test/db/migrate/009_add_account_id_to_photos.rb +9 -0
  168. data/test/db/migrate/010_create_projects.rb +11 -0
  169. data/test/db/migrate/011_create_images.rb +12 -0
  170. data/test/db/migrate/012_create_users.rb +11 -0
  171. data/test/db/migrate/013_create_personnel.rb +11 -0
  172. data/test/db/migrate/014_add_personnel_id_to_photos.rb +9 -0
  173. data/test/db/schema.rb +78 -0
  174. data/test/script/console +3 -0
  175. data/test/script/destroy +3 -0
  176. data/test/script/generate +3 -0
  177. data/test/script/server +3 -0
  178. data/test/test/fixtures/accounts.yml +7 -0
  179. data/test/test/fixtures/comments.yml +11 -0
  180. data/test/test/fixtures/images.yml +6 -0
  181. data/test/test/fixtures/options.yml +9 -0
  182. data/test/test/fixtures/personnel.yml +5 -0
  183. data/test/test/fixtures/photos.yml +9 -0
  184. data/test/test/fixtures/photos_tags.yml +3 -0
  185. data/test/test/fixtures/posts.yml +9 -0
  186. data/test/test/fixtures/products.yml +7 -0
  187. data/test/test/fixtures/projects.yml +7 -0
  188. data/test/test/fixtures/somethings.yml +7 -0
  189. data/test/test/fixtures/tags.yml +7 -0
  190. data/test/test/fixtures/users.yml +5 -0
  191. data/test/test/functional/cms/options_controller_test.rb +23 -0
  192. data/test/test/functional/cms/photos_controller_test.rb +43 -0
  193. data/test/test/functional/cms/products_controller_test.rb +23 -0
  194. data/test/test/functional/comments_controller_test.rb +19 -0
  195. data/test/test/functional/images_controller_test.rb +30 -0
  196. data/test/test/functional/people_controller_test.rb +27 -0
  197. data/test/test/functional/photos_controller_test.rb +123 -0
  198. data/test/test/functional/posts_controller_test.rb +27 -0
  199. data/test/test/functional/projects_controller_test.rb +21 -0
  200. data/test/test/functional/somethings_controller_test.rb +21 -0
  201. data/test/test/functional/tags_controller_test.rb +57 -0
  202. data/test/test/functional/users_controller_test.rb +17 -0
  203. data/test/test/test_helper.rb +13 -0
  204. data/test/test/unit/accessors_test.rb +110 -0
  205. data/test/test/unit/account_test.rb +7 -0
  206. data/test/test/unit/action_options_test.rb +109 -0
  207. data/test/test/unit/base_test.rb +11 -0
  208. data/test/test/unit/comment_test.rb +10 -0
  209. data/test/test/unit/failable_action_options_test.rb +77 -0
  210. data/test/test/unit/helpers/current_objects_test.rb +133 -0
  211. data/test/test/unit/helpers/internal_test.rb +106 -0
  212. data/test/test/unit/helpers/nested_test.rb +86 -0
  213. data/test/test/unit/helpers/singleton_current_objects_test.rb +68 -0
  214. data/test/test/unit/helpers/singleton_nested_test.rb +77 -0
  215. data/test/test/unit/helpers/singleton_urls_test.rb +67 -0
  216. data/test/test/unit/helpers/urls_test.rb +75 -0
  217. data/test/test/unit/helpers_test.rb +25 -0
  218. data/test/test/unit/image_test.rb +7 -0
  219. data/test/test/unit/option_test.rb +10 -0
  220. data/test/test/unit/photo_test.rb +10 -0
  221. data/test/test/unit/post_test.rb +10 -0
  222. data/test/test/unit/project_test.rb +10 -0
  223. data/test/test/unit/response_collector_test.rb +49 -0
  224. data/test/test/unit/something_test.rb +10 -0
  225. data/test/test/unit/tag_test.rb +10 -0
  226. data/test/test/unit/urligence_test.rb +203 -0
  227. metadata +379 -0
@@ -0,0 +1,27 @@
1
+ module ResourceController
2
+ # == ResourceController::Helpers
3
+ #
4
+ # Included in Base.
5
+ #
6
+ # These helpers are used internally to manage objects, generate urls, and manage parent resource associations.
7
+ #
8
+ # If you want to customize certain controller behaviour, like member-object, and collection fetching, overriding these methods is all it takes.
9
+ #
10
+ # See the docs below, and the README for examples
11
+ #
12
+ # *Please Note: many of these helpers build on top of each other, and require that behaviour to be maintained, in order for other functionality to work properly.*
13
+ #
14
+ # e.g. All fetching must be done on top of the method end_of_association_chain, or else parent resources (including polymorphic ones) won't function correctly.
15
+ #
16
+ # class PostsController < ResourceController::Base
17
+ # private
18
+ # def object
19
+ # @object ||= end_of_association_chain.find_by_permalink(param)
20
+ # end
21
+ # end
22
+ module Helpers
23
+ include ResourceController::Helpers::Urls
24
+ include ResourceController::Helpers::Nested
25
+ include ResourceController::Helpers::CurrentObjects
26
+ end
27
+ end
@@ -0,0 +1,73 @@
1
+ module ResourceController
2
+ module Helpers
3
+ module CurrentObjects
4
+ protected
5
+ # Used internally to return the model for your resource.
6
+ #
7
+ def model
8
+ model_name.to_s.camelize.constantize
9
+ end
10
+
11
+
12
+ # Used to fetch the collection for the index method
13
+ #
14
+ # In order to customize the way the collection is fetched, to add something like pagination, for example, override this method.
15
+ #
16
+ def collection
17
+ end_of_association_chain.find(:all)
18
+ end
19
+
20
+ # Returns the current param.
21
+ #
22
+ # Defaults to params[:id].
23
+ #
24
+ # Override this method if you'd like to use an alternate param name.
25
+ #
26
+ def param
27
+ params[:id]
28
+ end
29
+
30
+ # Used to fetch the current member object in all of the singular methods that operate on an existing member.
31
+ #
32
+ # Override this method if you'd like to fetch your objects in some alternate way, like using a permalink.
33
+ #
34
+ # class PostsController < ResourceController::Base
35
+ # private
36
+ # def object
37
+ # @object ||= end_of_association_chain.find_by_permalink(param)
38
+ # end
39
+ # end
40
+ #
41
+ def object
42
+ @object ||= end_of_association_chain.find(param) unless param.nil?
43
+ @object
44
+ end
45
+
46
+ # Used internally to load the member object in to an instance variable @#{model_name} (i.e. @post)
47
+ #
48
+ def load_object
49
+ instance_variable_set "@#{parent_type}", parent_object if parent?
50
+ instance_variable_set "@#{object_name}", object
51
+ end
52
+
53
+ # Used internally to load the collection in to an instance variable @#{model_name.pluralize} (i.e. @posts)
54
+ #
55
+ def load_collection
56
+ instance_variable_set "@#{parent_type}", parent_object if parent?
57
+ instance_variable_set "@#{object_name.to_s.pluralize}", collection
58
+ end
59
+
60
+ # Returns the form params. Defaults to params[model_name] (i.e. params["post"])
61
+ #
62
+ def object_params
63
+ params["#{object_name}"]
64
+ end
65
+
66
+ # Builds the object, but doesn't save it, during the new, and create action.
67
+ #
68
+ def build_object
69
+ @object ||= end_of_association_chain.send parent? ? :build : :new, object_params
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,67 @@
1
+ # Nested and Polymorphic Resource Helpers
2
+ #
3
+ module ResourceController
4
+ module Helpers
5
+ module Nested
6
+ protected
7
+ # Returns the relevant association proxy of the parent. (i.e. /posts/1/comments # => @post.comments)
8
+ #
9
+ def parent_association
10
+ @parent_association ||= parent_object.send(model_name.to_s.pluralize.to_sym)
11
+ end
12
+
13
+ # Returns the type of the current parent
14
+ #
15
+ def parent_type
16
+ @parent_type ||= parent_type_from_params || parent_type_from_request
17
+ end
18
+
19
+ # Returns the type of the current parent extracted from params
20
+ #
21
+ def parent_type_from_params
22
+ [*belongs_to].find { |parent| !params["#{parent}_id".to_sym].nil? }
23
+ end
24
+
25
+ # Returns the type of the current parent extracted form a request path
26
+ #
27
+ def parent_type_from_request
28
+ [*belongs_to].find { |parent| request.path.split('/').include? parent.to_s }
29
+ end
30
+
31
+ # Returns true/false based on whether or not a parent is present.
32
+ #
33
+ def parent?
34
+ !parent_type.nil?
35
+ end
36
+
37
+ # Returns true/false based on whether or not a parent is a singleton.
38
+ #
39
+ def parent_singleton?
40
+ !parent_type_from_request.nil? && parent_type_from_params.nil?
41
+ end
42
+
43
+ # Returns the current parent param, if there is a parent. (i.e. params[:post_id])
44
+ def parent_param
45
+ params["#{parent_type}_id".to_sym]
46
+ end
47
+
48
+ # Like the model method, but for a parent relationship.
49
+ #
50
+ def parent_model
51
+ parent_type.to_s.camelize.constantize
52
+ end
53
+
54
+ # Returns the current parent object if a parent object is present.
55
+ #
56
+ def parent_object
57
+ parent? && !parent_singleton? ? parent_model.find(parent_param) : nil
58
+ end
59
+
60
+ # If there is a parent, returns the relevant association proxy. Otherwise returns model.
61
+ #
62
+ def end_of_association_chain
63
+ parent? ? parent_association : model
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,64 @@
1
+ # Singleton Resource Helpers
2
+ #
3
+ # Used internally to transform a plural RESTful controller into a singleton
4
+ #
5
+ module ResourceController
6
+ module Helpers
7
+ module SingletonCustomizations
8
+ def self.included(subclass)
9
+ subclass.class_eval do
10
+ methods_to_undefine = [:param, :index, :collection, :load_collection, :collection_url,
11
+ :collection_path, :hash_for_collection_url, :hash_for_collection_path]
12
+ methods_to_undefine.each { |method| undef_method(method) if method_defined? method }
13
+
14
+ class << self
15
+ def singleton?
16
+ true
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ protected
23
+ # Used to fetch the current object in a singleton controller.
24
+ #
25
+ # By defult this method is able to fetch the current object for resources nested with the :has_one association only. (i.e. /users/1/image # => @user.image)
26
+ # In other cases you should override this method and provide your custom code to fetch a singleton resource object, like using a session hash.
27
+ #
28
+ # class AccountsController < ResourceController::Singleton
29
+ # private
30
+ # def object
31
+ # @object ||= Account.find(session[:account_id])
32
+ # end
33
+ # end
34
+ #
35
+ def object
36
+ @object ||= parent? ? end_of_association_chain : nil
37
+ end
38
+
39
+ # Returns the :has_one association proxy of the parent. (i.e. /users/1/image # => @user.image)
40
+ #
41
+ def parent_association
42
+ @parent_association ||= parent_object.send(model_name.to_sym)
43
+ end
44
+
45
+ # Used internally to provide the options to smart_url in a singleton controller.
46
+ #
47
+ def object_url_options(action_prefix = nil, alternate_object = nil)
48
+ [action_prefix] + namespaces + [parent_url_options, route_name.to_sym]
49
+ end
50
+
51
+ # Builds the object, but doesn't save it, during the new, and create action.
52
+ #
53
+ def build_object
54
+ @object ||= singleton_build_object_base.send parent? ? "build_#{model_name}".to_sym : :new, object_params
55
+ end
56
+
57
+ # Singleton controllers don't build off of association proxy, so we can't use end_of_association_chain here
58
+ #
59
+ def singleton_build_object_base
60
+ parent? ? parent_object : model
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,132 @@
1
+ # Thanks to Urligence, you get some free url helpers.
2
+ #
3
+ # No matter what your controller looks like...
4
+ #
5
+ # [edit_|new_]object_url # is the equivalent of saying [edit_|new_]post_url(@post)
6
+ # [edit_|new_]object_url(some_other_object) # allows you to specify an object, but still maintain any paths or namespaces that are present
7
+ #
8
+ # collection_url # is like saying posts_url
9
+ #
10
+ # Url helpers are especially useful when working with polymorphic controllers.
11
+ #
12
+ # # /posts/1/comments
13
+ # object_url #=> /posts/1/comments/#{@comment.to_param}
14
+ # object_url(comment) #=> /posts/1/comments/#{comment.to_param}
15
+ # edit_object_url #=> /posts/1/comments/#{@comment.to_param}/edit
16
+ # collection_url #=> /posts/1/comments
17
+ #
18
+ # # /products/1/comments
19
+ # object_url #=> /products/1/comments/#{@comment.to_param}
20
+ # object_url(comment) #=> /products/1/comments/#{comment.to_param}
21
+ # edit_object_url #=> /products/1/comments/#{@comment.to_param}/edit
22
+ # collection_url #=> /products/1/comments
23
+ #
24
+ # # /comments
25
+ # object_url #=> /comments/#{@comment.to_param}
26
+ # object_url(comment) #=> /comments/#{comment.to_param}
27
+ # edit_object_url #=> /comments/#{@comment.to_param}/edit
28
+ # collection_url #=> /comments
29
+ #
30
+ # Or with namespaced, nested controllers...
31
+ #
32
+ # # /admin/products/1/options
33
+ # object_url #=> /admin/products/1/options/#{@option.to_param}
34
+ # object_url(option) #=> /admin/products/1/options/#{option.to_param}
35
+ # edit_object_url #=> /admin/products/1/options/#{@option.to_param}/edit
36
+ # collection_url #=> /admin/products/1/options
37
+ #
38
+ # You get the idea. Everything is automagical! All parameters are inferred.
39
+ #
40
+ module ResourceController
41
+ module Helpers
42
+ module Urls
43
+ protected
44
+ ['', 'edit_'].each do |type|
45
+ symbol = type.blank? ? nil : type.gsub(/_/, '').to_sym
46
+
47
+ define_method("#{type}object_url") do |*alternate_object|
48
+ smart_url *object_url_options(symbol, alternate_object.first)
49
+ end
50
+
51
+ define_method("#{type}object_path") do |*alternate_object|
52
+ smart_path *object_url_options(symbol, alternate_object.first)
53
+ end
54
+
55
+ define_method("hash_for_#{type}object_url") do |*alternate_object|
56
+ hash_for_smart_url *object_url_options(symbol, alternate_object.first)
57
+ end
58
+
59
+ define_method("hash_for_#{type}object_path") do |*alternate_object|
60
+ hash_for_smart_path *object_url_options(symbol, alternate_object.first)
61
+ end
62
+ end
63
+
64
+ def new_object_url
65
+ smart_url *new_object_url_options
66
+ end
67
+
68
+ def new_object_path
69
+ smart_path *new_object_url_options
70
+ end
71
+
72
+ def hash_for_new_object_url
73
+ hash_for_smart_url *new_object_url_options
74
+ end
75
+
76
+ def hash_for_new_object_path
77
+ hash_for_smart_path *new_object_url_options
78
+ end
79
+
80
+ def collection_url
81
+ smart_url *collection_url_options
82
+ end
83
+
84
+ def collection_path
85
+ smart_path *collection_url_options
86
+ end
87
+
88
+ def hash_for_collection_url
89
+ hash_for_smart_url *collection_url_options
90
+ end
91
+
92
+ def hash_for_collection_path
93
+ hash_for_smart_path *collection_url_options
94
+ end
95
+
96
+ # Used internally to provide the options to smart_url from Urligence.
97
+ #
98
+ def collection_url_options
99
+ namespaces + [parent_url_options, route_name.to_s.pluralize.to_sym]
100
+ end
101
+
102
+ # Used internally to provide the options to smart_url from Urligence.
103
+ #
104
+ def object_url_options(action_prefix = nil, alternate_object = nil)
105
+ [action_prefix] + namespaces + [parent_url_options, [route_name.to_sym, alternate_object || object]]
106
+ end
107
+
108
+ # Used internally to provide the options to smart_url from Urligence.
109
+ #
110
+ def new_object_url_options
111
+ [:new] + namespaces + [parent_url_options, route_name.to_sym]
112
+ end
113
+
114
+ def parent_url_options
115
+ if parent?
116
+ parent_singleton? ? parent_type.to_sym : [parent_type.to_sym, parent_object]
117
+ else
118
+ nil
119
+ end
120
+ end
121
+
122
+ # Returns all of the current namespaces of the current controller, symbolized, in array form.
123
+ #
124
+ def namespaces
125
+ names = self.class.name.split("::")
126
+ names.pop
127
+
128
+ names.map(&:underscore).map(&:to_sym)
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,15 @@
1
+ module ResourceController
2
+
3
+ # == ResourceController::Singleton
4
+ #
5
+ # Inherit from this class to create your RESTful singleton controller. See the README for usage.
6
+ #
7
+ class Singleton < ::ApplicationController
8
+ unloadable
9
+
10
+ def self.inherited(subclass)
11
+ super
12
+ subclass.class_eval { resource_controller :singleton }
13
+ end
14
+ end
15
+ end
data/lib/urligence.rb ADDED
@@ -0,0 +1,50 @@
1
+ module Urligence
2
+ def smart_url(*objects)
3
+ urligence(*objects.push(:url))
4
+ end
5
+
6
+ def smart_path(*objects)
7
+ urligence(*objects.push(:path))
8
+ end
9
+
10
+ def hash_for_smart_url(*objects)
11
+ urligence(*objects.unshift(:hash_for).push(:url).push({:type => :hash}))
12
+ end
13
+
14
+ def hash_for_smart_path(*objects)
15
+ urligence(*objects.unshift(:hash_for).push(:path).push({:type => :hash}))
16
+ end
17
+
18
+ def urligence(*objects)
19
+ config = {}
20
+ config.merge!(objects.pop) if objects.last.is_a?(Hash)
21
+
22
+ objects.reject! { |object| object.nil? }
23
+
24
+ url_fragments = objects.collect do |obj|
25
+ if obj.is_a? Symbol
26
+ obj
27
+ elsif obj.is_a? Array
28
+ obj.first
29
+ else
30
+ obj.class.name.underscore.to_sym
31
+ end
32
+ end
33
+
34
+ unless config[:type] == :hash
35
+ send url_fragments.join("_"), *objects.flatten.select { |obj| !obj.is_a? Symbol }
36
+ else
37
+ params = {}
38
+ unparsed_params = objects.select { |obj| !obj.is_a? Symbol }
39
+ unparsed_params.each_with_index do |obj, i|
40
+ unless i == (unparsed_params.length-1)
41
+ params.merge!((obj.is_a? Array) ? {"#{obj.first}_id".to_sym => obj[1].to_param} : {"#{obj.class.name.underscore}_id".to_sym => obj.to_param})
42
+ else
43
+ params.merge!((obj.is_a? Array) ? {:id => obj[1].to_param} : {:id => obj.to_param})
44
+ end
45
+ end
46
+
47
+ send url_fragments.join("_"), params
48
+ end
49
+ end
50
+ end
data/rails/init.rb ADDED
@@ -0,0 +1,6 @@
1
+ ActionController::Base.class_eval do
2
+ include Urligence
3
+ helper_method :smart_url
4
+
5
+ extend ResourceController::ActionControllerExtension
6
+ end
data/test/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require(File.join(File.dirname(__FILE__), 'config', 'boot'))
5
+
6
+ require 'rake'
7
+ require 'rake/testtask'
8
+ require 'rake/rdoctask'
9
+
10
+ require 'tasks/rails'