base_rails_app 0.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 (194) hide show
  1. data/LICENSE +1 -0
  2. data/README +1 -0
  3. data/lib/app/controllers/application_controller.rb +55 -0
  4. data/lib/app/controllers/password_resets_controller.rb +45 -0
  5. data/lib/app/controllers/user_sessions_controller.rb +25 -0
  6. data/lib/app/controllers/users_controller.rb +37 -0
  7. data/lib/app/helpers/application_helper.rb +4 -0
  8. data/lib/app/helpers/user_sessions_helper.rb +2 -0
  9. data/lib/app/helpers/users_helper.rb +2 -0
  10. data/lib/app/models/postman.rb +20 -0
  11. data/lib/app/models/user.rb +12 -0
  12. data/lib/app/models/user_session.rb +2 -0
  13. data/lib/app/views/application/404_not_found.html.erb +8 -0
  14. data/lib/app/views/layouts/application.html.erb +57 -0
  15. data/lib/app/views/password_resets/_sidebar.html.erb +0 -0
  16. data/lib/app/views/password_resets/edit.html.erb +33 -0
  17. data/lib/app/views/password_resets/new.html.erb +26 -0
  18. data/lib/app/views/postman/password_reset_instructions.html.erb +3 -0
  19. data/lib/app/views/postman/welcome_email.html.erb +3 -0
  20. data/lib/app/views/user_sessions/_form.html.erb +19 -0
  21. data/lib/app/views/user_sessions/_sidebar.html.erb +13 -0
  22. data/lib/app/views/user_sessions/new.html.erb +15 -0
  23. data/lib/app/views/users/_form.html.erb +28 -0
  24. data/lib/app/views/users/_sidebar.html.erb +6 -0
  25. data/lib/app/views/users/edit.html.erb +19 -0
  26. data/lib/app/views/users/new.html.erb +15 -0
  27. data/lib/app/views/users/show.html.erb +46 -0
  28. data/lib/base_rails_app.rb +5 -0
  29. data/lib/base_rails_app/boot.rb +2 -0
  30. data/lib/base_rails_app/tasks.rb +12 -0
  31. data/lib/config/configatron/cucumber.rb +0 -0
  32. data/lib/config/configatron/defaults.rb +4 -0
  33. data/lib/config/configatron/development.rb +1 -0
  34. data/lib/config/configatron/production.rb +0 -0
  35. data/lib/config/configatron/test.rb +0 -0
  36. data/lib/config/database.yml +25 -0
  37. data/lib/config/deploy.rb +15 -0
  38. data/lib/config/environments/cucumber.rb +22 -0
  39. data/lib/config/environments/development.rb +17 -0
  40. data/lib/config/environments/production.rb +28 -0
  41. data/lib/config/environments/test.rb +28 -0
  42. data/lib/config/gemtronics.rb +36 -0
  43. data/lib/config/initializers/backtrace_silencers.rb +7 -0
  44. data/lib/config/initializers/configatron.rb +1 -0
  45. data/lib/config/initializers/hoptoad.rb +3 -0
  46. data/lib/config/initializers/inflections.rb +10 -0
  47. data/lib/config/initializers/mailers.rb +1 -0
  48. data/lib/config/initializers/mime_types.rb +5 -0
  49. data/lib/config/initializers/new_rails_defaults.rb +21 -0
  50. data/lib/config/initializers/session_store.rb +17 -0
  51. data/lib/config/locales/en.yml +5 -0
  52. data/lib/config/routes.rb +51 -0
  53. data/lib/config/schedule.rb +20 -0
  54. data/lib/db/migrate/20090809175903_create_users.rb +30 -0
  55. data/lib/db/migrate/20090809204840_acts_as_taggable_on_migration.rb +29 -0
  56. data/lib/db/migrate/20090912171353_create_delayed_jobs.rb +20 -0
  57. data/lib/db/migrate/20090912171829_add_delayed_job_extras.rb +11 -0
  58. data/lib/db/migrate/20090929201455_add_more_time_columns_to_dj.rb +11 -0
  59. data/lib/db/schema.rb +72 -0
  60. data/lib/db/seeds.rb +7 -0
  61. data/lib/lib/tasks/cucumber.rake +36 -0
  62. data/lib/lib/tasks/rcov.rake +27 -0
  63. data/lib/lib/tasks/rspec.rake +183 -0
  64. data/lib/vendor/plugins/delayed_job/generators/delayed_job/delayed_job_generator.rb +22 -0
  65. data/lib/vendor/plugins/delayed_job/generators/delayed_job/templates/migration.rb +20 -0
  66. data/lib/vendor/plugins/delayed_job/init.rb +2 -0
  67. data/lib/vendor/plugins/delayed_job/lib/delayed/command.rb +65 -0
  68. data/lib/vendor/plugins/delayed_job/lib/delayed/job.rb +271 -0
  69. data/lib/vendor/plugins/delayed_job/lib/delayed/message_sending.rb +18 -0
  70. data/lib/vendor/plugins/delayed_job/lib/delayed/performable_method.rb +55 -0
  71. data/lib/vendor/plugins/delayed_job/lib/delayed/tasks.rb +15 -0
  72. data/lib/vendor/plugins/delayed_job/lib/delayed/worker.rb +54 -0
  73. data/lib/vendor/plugins/delayed_job/lib/delayed_job.rb +13 -0
  74. data/lib/vendor/plugins/delayed_job/recipes/delayed_job.rb +26 -0
  75. data/lib/vendor/plugins/delayed_job/tasks/jobs.rake +1 -0
  76. data/lib/vendor/plugins/hoptoad_notifier/install.rb +1 -0
  77. data/lib/vendor/plugins/hoptoad_notifier/lib/hoptoad_notifier.rb +418 -0
  78. data/lib/vendor/plugins/hoptoad_notifier/lib/hoptoad_tasks.rb +26 -0
  79. data/lib/vendor/plugins/hoptoad_notifier/recipes/hoptoad.rb +22 -0
  80. data/lib/vendor/plugins/hoptoad_notifier/tasks/hoptoad_notifier_tasks.rake +66 -0
  81. data/lib/vendor/plugins/inherited_resources/README.rdoc +524 -0
  82. data/lib/vendor/plugins/inherited_resources/inherited_resources.gemspec +71 -0
  83. data/lib/vendor/plugins/inherited_resources/init.rb +1 -0
  84. data/lib/vendor/plugins/inherited_resources/lib/inherited_resources.rb +23 -0
  85. data/lib/vendor/plugins/inherited_resources/lib/inherited_resources/actions.rb +79 -0
  86. data/lib/vendor/plugins/inherited_resources/lib/inherited_resources/base.rb +42 -0
  87. data/lib/vendor/plugins/inherited_resources/lib/inherited_resources/base_helpers.rb +363 -0
  88. data/lib/vendor/plugins/inherited_resources/lib/inherited_resources/belongs_to_helpers.rb +89 -0
  89. data/lib/vendor/plugins/inherited_resources/lib/inherited_resources/class_methods.rb +338 -0
  90. data/lib/vendor/plugins/inherited_resources/lib/inherited_resources/dsl.rb +26 -0
  91. data/lib/vendor/plugins/inherited_resources/lib/inherited_resources/dumb_responder.rb +20 -0
  92. data/lib/vendor/plugins/inherited_resources/lib/inherited_resources/has_scope_helpers.rb +83 -0
  93. data/lib/vendor/plugins/inherited_resources/lib/inherited_resources/legacy/respond_to.rb +156 -0
  94. data/lib/vendor/plugins/inherited_resources/lib/inherited_resources/legacy/responder.rb +200 -0
  95. data/lib/vendor/plugins/inherited_resources/lib/inherited_resources/polymorphic_helpers.rb +155 -0
  96. data/lib/vendor/plugins/inherited_resources/lib/inherited_resources/singleton_helpers.rb +95 -0
  97. data/lib/vendor/plugins/inherited_resources/lib/inherited_resources/url_helpers.rb +179 -0
  98. data/lib/vendor/plugins/inherited_resources/test/aliases_test.rb +139 -0
  99. data/lib/vendor/plugins/inherited_resources/test/association_chain_test.rb +125 -0
  100. data/lib/vendor/plugins/inherited_resources/test/base_test.rb +225 -0
  101. data/lib/vendor/plugins/inherited_resources/test/belongs_to_test.rb +87 -0
  102. data/lib/vendor/plugins/inherited_resources/test/class_methods_test.rb +138 -0
  103. data/lib/vendor/plugins/inherited_resources/test/customized_base_test.rb +162 -0
  104. data/lib/vendor/plugins/inherited_resources/test/customized_belongs_to_test.rb +76 -0
  105. data/lib/vendor/plugins/inherited_resources/test/defaults_test.rb +70 -0
  106. data/lib/vendor/plugins/inherited_resources/test/flash_test.rb +88 -0
  107. data/lib/vendor/plugins/inherited_resources/test/has_scope_test.rb +139 -0
  108. data/lib/vendor/plugins/inherited_resources/test/locales/en.yml +17 -0
  109. data/lib/vendor/plugins/inherited_resources/test/nested_belongs_to_test.rb +108 -0
  110. data/lib/vendor/plugins/inherited_resources/test/optional_belongs_to_test.rb +164 -0
  111. data/lib/vendor/plugins/inherited_resources/test/polymorphic_test.rb +186 -0
  112. data/lib/vendor/plugins/inherited_resources/test/redirect_to_test.rb +51 -0
  113. data/lib/vendor/plugins/inherited_resources/test/respond_to_test.rb +155 -0
  114. data/lib/vendor/plugins/inherited_resources/test/singleton_test.rb +83 -0
  115. data/lib/vendor/plugins/inherited_resources/test/test_helper.rb +38 -0
  116. data/lib/vendor/plugins/inherited_resources/test/url_helpers_test.rb +537 -0
  117. data/lib/vendor/plugins/inherited_resources/test/views/cars/edit.html.erb +1 -0
  118. data/lib/vendor/plugins/inherited_resources/test/views/cars/index.html.erb +1 -0
  119. data/lib/vendor/plugins/inherited_resources/test/views/cars/new.html.erb +1 -0
  120. data/lib/vendor/plugins/inherited_resources/test/views/cars/show.html.erb +1 -0
  121. data/lib/vendor/plugins/inherited_resources/test/views/cities/edit.html.erb +1 -0
  122. data/lib/vendor/plugins/inherited_resources/test/views/cities/index.html.erb +1 -0
  123. data/lib/vendor/plugins/inherited_resources/test/views/cities/new.html.erb +1 -0
  124. data/lib/vendor/plugins/inherited_resources/test/views/cities/show.html.erb +1 -0
  125. data/lib/vendor/plugins/inherited_resources/test/views/comments/edit.html.erb +1 -0
  126. data/lib/vendor/plugins/inherited_resources/test/views/comments/index.html.erb +1 -0
  127. data/lib/vendor/plugins/inherited_resources/test/views/comments/new.html.erb +1 -0
  128. data/lib/vendor/plugins/inherited_resources/test/views/comments/show.html.erb +1 -0
  129. data/lib/vendor/plugins/inherited_resources/test/views/employees/edit.html.erb +1 -0
  130. data/lib/vendor/plugins/inherited_resources/test/views/employees/index.html.erb +1 -0
  131. data/lib/vendor/plugins/inherited_resources/test/views/employees/new.html.erb +1 -0
  132. data/lib/vendor/plugins/inherited_resources/test/views/employees/show.html.erb +1 -0
  133. data/lib/vendor/plugins/inherited_resources/test/views/managers/edit.html.erb +1 -0
  134. data/lib/vendor/plugins/inherited_resources/test/views/managers/new.html.erb +1 -0
  135. data/lib/vendor/plugins/inherited_resources/test/views/managers/show.html.erb +1 -0
  136. data/lib/vendor/plugins/inherited_resources/test/views/painters/edit.html.erb +1 -0
  137. data/lib/vendor/plugins/inherited_resources/test/views/painters/index.html.erb +1 -0
  138. data/lib/vendor/plugins/inherited_resources/test/views/painters/new.html.erb +1 -0
  139. data/lib/vendor/plugins/inherited_resources/test/views/painters/show.html.erb +1 -0
  140. data/lib/vendor/plugins/inherited_resources/test/views/pets/edit.html.erb +1 -0
  141. data/lib/vendor/plugins/inherited_resources/test/views/pets/index.html.erb +1 -0
  142. data/lib/vendor/plugins/inherited_resources/test/views/pets/new.html.erb +1 -0
  143. data/lib/vendor/plugins/inherited_resources/test/views/pets/show.html.erb +1 -0
  144. data/lib/vendor/plugins/inherited_resources/test/views/products/edit.html.erb +1 -0
  145. data/lib/vendor/plugins/inherited_resources/test/views/products/index.html.erb +1 -0
  146. data/lib/vendor/plugins/inherited_resources/test/views/products/new.html.erb +1 -0
  147. data/lib/vendor/plugins/inherited_resources/test/views/products/show.html.erb +1 -0
  148. data/lib/vendor/plugins/inherited_resources/test/views/professors/edit.html.erb +1 -0
  149. data/lib/vendor/plugins/inherited_resources/test/views/professors/index.html.erb +1 -0
  150. data/lib/vendor/plugins/inherited_resources/test/views/professors/new.html.erb +1 -0
  151. data/lib/vendor/plugins/inherited_resources/test/views/professors/show.html.erb +1 -0
  152. data/lib/vendor/plugins/inherited_resources/test/views/projects/index.html.erb +1 -0
  153. data/lib/vendor/plugins/inherited_resources/test/views/projects/index.json.erb +1 -0
  154. data/lib/vendor/plugins/inherited_resources/test/views/projects/respond_to_skip_default_template.html.erb +1 -0
  155. data/lib/vendor/plugins/inherited_resources/test/views/projects/respond_with_resource.html.erb +1 -0
  156. data/lib/vendor/plugins/inherited_resources/test/views/students/edit.html.erb +1 -0
  157. data/lib/vendor/plugins/inherited_resources/test/views/students/new.html.erb +1 -0
  158. data/lib/vendor/plugins/inherited_resources/test/views/trees/edit.html.erb +1 -0
  159. data/lib/vendor/plugins/inherited_resources/test/views/trees/index.html.erb +1 -0
  160. data/lib/vendor/plugins/inherited_resources/test/views/trees/new.html.erb +1 -0
  161. data/lib/vendor/plugins/inherited_resources/test/views/trees/show.html.erb +1 -0
  162. data/lib/vendor/plugins/inherited_resources/test/views/users/edit.html.erb +1 -0
  163. data/lib/vendor/plugins/inherited_resources/test/views/users/index.html.erb +1 -0
  164. data/lib/vendor/plugins/inherited_resources/test/views/users/new.html.erb +1 -0
  165. data/lib/vendor/plugins/inherited_resources/test/views/users/show.html.erb +1 -0
  166. data/lib/vendor/plugins/web-app-theme/README.md +22 -0
  167. data/lib/vendor/plugins/web-app-theme/images/avatar.png +0 -0
  168. data/lib/vendor/plugins/web-app-theme/index.html +473 -0
  169. data/lib/vendor/plugins/web-app-theme/javascripts/jquery-1.3.min.js +19 -0
  170. data/lib/vendor/plugins/web-app-theme/javascripts/jquery.localscroll.js +104 -0
  171. data/lib/vendor/plugins/web-app-theme/javascripts/jquery.scrollTo.js +150 -0
  172. data/lib/vendor/plugins/web-app-theme/rails_generators/theme/templates/view_layout_administration.html.erb +48 -0
  173. data/lib/vendor/plugins/web-app-theme/rails_generators/theme/templates/view_layout_sign.html.erb +15 -0
  174. data/lib/vendor/plugins/web-app-theme/rails_generators/theme/theme_generator.rb +38 -0
  175. data/lib/vendor/plugins/web-app-theme/rails_generators/themed/templates/view_edit.html.erb +20 -0
  176. data/lib/vendor/plugins/web-app-theme/rails_generators/themed/templates/view_form.html.erb +10 -0
  177. data/lib/vendor/plugins/web-app-theme/rails_generators/themed/templates/view_new.html.erb +19 -0
  178. data/lib/vendor/plugins/web-app-theme/rails_generators/themed/templates/view_show.html.erb +23 -0
  179. data/lib/vendor/plugins/web-app-theme/rails_generators/themed/templates/view_sidebar.html.erb +13 -0
  180. data/lib/vendor/plugins/web-app-theme/rails_generators/themed/templates/view_signin.html.erb +39 -0
  181. data/lib/vendor/plugins/web-app-theme/rails_generators/themed/templates/view_signup.html.erb +56 -0
  182. data/lib/vendor/plugins/web-app-theme/rails_generators/themed/templates/view_tables.html.erb +50 -0
  183. data/lib/vendor/plugins/web-app-theme/rails_generators/themed/themed_generator.rb +89 -0
  184. data/lib/vendor/plugins/web-app-theme/stylesheets/base.css +336 -0
  185. data/lib/vendor/plugins/web-app-theme/stylesheets/themes/bec-green/style.css +290 -0
  186. data/lib/vendor/plugins/web-app-theme/stylesheets/themes/bec/style.css +301 -0
  187. data/lib/vendor/plugins/web-app-theme/stylesheets/themes/blue/style.css +280 -0
  188. data/lib/vendor/plugins/web-app-theme/stylesheets/themes/default/style.css +267 -0
  189. data/lib/vendor/plugins/web-app-theme/stylesheets/themes/djime-cerulean/style.css +298 -0
  190. data/lib/vendor/plugins/web-app-theme/stylesheets/themes/drastic-dark/style.css +373 -0
  191. data/lib/vendor/plugins/web-app-theme/stylesheets/themes/kathleene/style.css +272 -0
  192. data/lib/vendor/plugins/web-app-theme/stylesheets/themes/orange/style.css +263 -0
  193. data/lib/vendor/plugins/web-app-theme/stylesheets/themes/reidb-greenish/style.css +301 -0
  194. metadata +257 -0
@@ -0,0 +1,26 @@
1
+ require 'net/http'
2
+ require 'uri'
3
+ require 'active_support'
4
+
5
+ module HoptoadTasks
6
+ def self.deploy(opts = {})
7
+ if HoptoadNotifier.api_key.blank?
8
+ puts "I don't seem to be configured with an API key. Please check your configuration."
9
+ return false
10
+ end
11
+
12
+ if opts[:rails_env].blank?
13
+ puts "I don't know to which Rails environment you are deploying (use the TO=production option)."
14
+ return false
15
+ end
16
+
17
+ params = {'api_key' => HoptoadNotifier.api_key}
18
+ opts.each {|k,v| params["deploy[#{k}]"] = v }
19
+
20
+ url = URI.parse("http://#{HoptoadNotifier.host}/deploys.txt")
21
+ response = Net::HTTP.post_form(url, params)
22
+ puts response.body
23
+ return Net::HTTPSuccess === response
24
+ end
25
+ end
26
+
@@ -0,0 +1,22 @@
1
+ # When Hoptoad is installed as a plugin this is loaded automatically.
2
+ #
3
+ # When Hoptoad installed as a gem, you need to add
4
+ # require 'hoptoad_notifier/recipes/hoptoad'
5
+ # to your deploy.rb
6
+ #
7
+ # Defines deploy:notify_hoptoad which will send information about the deploy to Hoptoad.
8
+ #
9
+ after "deploy", "deploy:notify_hoptoad"
10
+ after "deploy:migrations", "deploy:notify_hoptoad"
11
+
12
+ namespace :deploy do
13
+ desc "Notify Hoptoad of the deployment"
14
+ task :notify_hoptoad do
15
+ rails_env = fetch(:rails_env, "production")
16
+ local_user = ENV['USER'] || ENV['USERNAME']
17
+ notify_command = "rake hoptoad:deploy TO=#{rails_env} REVISION=#{current_revision} REPO=#{repository} USER=#{local_user}"
18
+ puts "Notifying Hoptoad of Deploy (#{notify_command})"
19
+ `#{notify_command}`
20
+ puts "Hoptoad Notification Complete."
21
+ end
22
+ end
@@ -0,0 +1,66 @@
1
+ namespace :hoptoad do
2
+ desc "Notify Hoptoad of a new deploy."
3
+ task :deploy => :environment do
4
+ require 'hoptoad_tasks'
5
+ HoptoadTasks.deploy(:rails_env => ENV['TO'],
6
+ :scm_revision => ENV['REVISION'],
7
+ :scm_repository => ENV['REPO'],
8
+ :local_username => ENV['USER'])
9
+ end
10
+
11
+ desc "Verify your plugin installation by sending a test exception to the hoptoad service"
12
+ task :test => :environment do
13
+ require 'action_controller/test_process'
14
+ require 'app/controllers/application' if File.exists?('app/controllers/application.rb')
15
+
16
+ request = ActionController::TestRequest.new
17
+ response = ActionController::TestResponse.new
18
+
19
+ class HoptoadTestingException < RuntimeError; end
20
+
21
+ unless HoptoadNotifier.api_key
22
+ puts "Hoptoad needs an API key configured! Check the README to see how to add it."
23
+ exit
24
+ end
25
+
26
+ in_controller = ApplicationController.included_modules.include? HoptoadNotifier::Catcher
27
+ in_base = ActionController::Base.included_modules.include? HoptoadNotifier::Catcher
28
+ if !in_controller || !in_base
29
+ puts "HoptoadNotifier::Catcher must be included inside your ApplicationController class."
30
+ exit
31
+ end
32
+
33
+ puts 'Setting up the Controller.'
34
+ class ApplicationController
35
+ # This is to bypass any filters that may prevent access to the action.
36
+ prepend_before_filter :test_hoptoad
37
+ def test_hoptoad
38
+ puts "Raising '#{exception_class.name}' to simulate application failure."
39
+ raise exception_class.new, 'Testing hoptoad via "rake hoptoad:test". If you can see this, it works.'
40
+ end
41
+
42
+ def rescue_action exception
43
+ rescue_action_in_public exception
44
+ end
45
+
46
+ def public_environment?
47
+ true
48
+ end
49
+
50
+ # Ensure we actually have an action to go to.
51
+ def verify; end
52
+
53
+ def exception_class
54
+ exception_name = ENV['EXCEPTION'] || "HoptoadTestingException"
55
+ Object.const_get(exception_name)
56
+ rescue
57
+ Object.const_set(exception_name, Class.new(Exception))
58
+ end
59
+ end
60
+
61
+ puts 'Processing request.'
62
+ class HoptoadVerificationController < ApplicationController; end
63
+ HoptoadVerificationController.new.process(request, response)
64
+ end
65
+ end
66
+
@@ -0,0 +1,524 @@
1
+ Inherited Resources
2
+ License: MIT
3
+ Version: 0.9.1
4
+
5
+ == Description
6
+
7
+ Inherited Resources speeds up development by making your controllers inherit
8
+ all restful actions so you just have to focus on what is important. It makes
9
+ your controllers more powerful and cleaner at the same time.
10
+
11
+ Plus, making your controllers follow a pattern, it helps you to write better
12
+ code by following fat models and skinny controllers convention. There is
13
+ a screencast made by Fabio Akita about its features:
14
+
15
+ http://akitaonrails.com/2009/09/01/screencast-real-thin-restful-controllers-with-inherited-resources
16
+
17
+ Inherited Resources is tested and compatible with Rails 2.2.x and Rails 2.3.x.
18
+
19
+ keywords: resources, controller, singleton, belongs_to, polymorphic, named_scope and I18n
20
+
21
+ == Installation
22
+
23
+ Install Inherited Resources is very easy. It is stored in GitHub, so just run
24
+ the following:
25
+
26
+ gem sources -a http://gems.github.com
27
+ sudo gem install josevalim-inherited_resources
28
+
29
+ If you want it as plugin, just do:
30
+
31
+ script/plugin install git://github.com/josevalim/inherited_resources.git
32
+
33
+ == Rspec known bug
34
+
35
+ When used with integrate_views equals to false, rspec overwrites default_render,
36
+ render and some other controller methods which makes Inherited Resources not work
37
+ properly. In such cases, you have to set integrate_views to true.
38
+
39
+ == Basic Usage
40
+
41
+ To use Inherited Resources you just have to inherit (duh) it:
42
+
43
+ class ProjectsController < InheritedResources::Base
44
+ end
45
+
46
+ And all actions are defined and working, check it! Your projects collection
47
+ (in the index action) is still available in the instance variable @projects
48
+ and your project resource (all other actions) is available as @ project.
49
+
50
+ The next step is to define which mime types this controller provides:
51
+
52
+ class ProjectsController < InheritedResources::Base
53
+ respond_to :html, :xml, :json
54
+ end
55
+
56
+ You can also specify them based per action:
57
+
58
+ class ProjectsController < InheritedResources::Base
59
+ respond_to :html, :xml, :json
60
+ respond_to :js, :only => :create
61
+ respond_to :iphone, :except => [ :edit, :update ]
62
+ end
63
+
64
+ For each request, it first checkes if the "controller/action.format" file is
65
+ available (for example "projects/create.xml") and if it's not, it checks if
66
+ the resource respond to :to_format (in this case, :to_xml). Otherwise returns 404.
67
+
68
+ Another option is to specify which actions the controller will inherit from
69
+ the InheritedResources::Base:
70
+
71
+ class ProjectsController < InheritedResources::Base
72
+ actions :index, :show, :new, :create
73
+ end
74
+
75
+ Or:
76
+
77
+ class ProjectsController < InheritedResources::Base
78
+ actions :all, :except => [ :edit, :update, :destroy ]
79
+ end
80
+
81
+ In your views, you will get the following helpers:
82
+
83
+ resource #=> @project
84
+ collection #=> @projects
85
+ resource_class #=> Project
86
+
87
+ As you might expect, collection (@projects instance variable) is only available
88
+ on index actions.
89
+
90
+ If for some reason you cannot inherit from InheritedResources::Base, you can
91
+ call inherit_resources in your controller class scope:
92
+
93
+ class AccountsController < ApplicationController
94
+ inherit_resources
95
+ end
96
+
97
+ == Overwriting defaults
98
+
99
+ Whenever you inherit from InheritedResources, several defaults are assumed.
100
+ For example you can have an AccountsController to account management while the
101
+ resource is an User:
102
+
103
+ class AccountsController < InheritedResources::Base
104
+ defaults :resource_class => User, :collection_name => 'users', :instance_name => 'user'
105
+ end
106
+
107
+ In the case above, in your views you will have @users and @user variables, but
108
+ the routes used will still be accounts_url and account_url. If you plan also to
109
+ change the routes, you can use :route_collection_name and :route_instance_name.
110
+
111
+ Namespaced controllers work out of the box, but if you need to specify a
112
+ different route prefix, you can do the following:
113
+
114
+ class Administrators::PeopleController < InheritedResources::Base
115
+ defaults :route_prefix => 'admin'
116
+ end
117
+
118
+ Then your named routes will be: 'admin_people_url', 'admin_person_url' instead
119
+ of 'administrators_people_url' and 'administrators_person_url'.
120
+
121
+ If you want to customize how resources are retrieved you can overwrite
122
+ collection and resource methods. The first is called on index action and the
123
+ second on all other actions. Let's suppose you want to add pagination to your
124
+ projects collection:
125
+
126
+ class ProjectsController < InheritedResources::Base
127
+ protected
128
+ def collection
129
+ @projects ||= end_of_association_chain.paginate(:page => params[:page])
130
+ end
131
+ end
132
+
133
+ The end_of_association_chain returns your resource after nesting all associations
134
+ and scopes (more about this below).
135
+
136
+ InheritedResources also introduces another method called begin_of_association_chain.
137
+ It's mostly used when you want to create resources based on the @current_user and
138
+ you have urls like "account/projects". In such cases, you have to do
139
+ @current_user.projects.find or @current_user.projects.build in your actions.
140
+
141
+ You can deal with it just doing:
142
+
143
+ class ProjectsController < InheritedResources::Base
144
+ protected
145
+ def begin_of_association_chain
146
+ @current_user
147
+ end
148
+ end
149
+
150
+ == Overwriting actions
151
+
152
+ Let's suppose that after destroying a project you want to redirect to your
153
+ root url instead of redirecting to projects url. You just have to do:
154
+
155
+ class ProjectsController < InheritedResources::Base
156
+ def destroy
157
+ super do |format|
158
+ format.html { redirect_to root_url }
159
+ end
160
+ end
161
+ end
162
+
163
+ You are opening your action and giving the parent action a new behavior. On
164
+ the other hand, I have to agree that calling super is not very readable. That's
165
+ why all methods have aliases. So this is equivalent:
166
+
167
+ class ProjectsController < InheritedResources::Base
168
+ def destroy
169
+ destroy! do |format|
170
+ format.html { redirect_to root_url }
171
+ end
172
+ end
173
+ end
174
+
175
+ Even more, since most of the times when you change a create, update or destroy
176
+ action is because you want to to change to where it redirects, a shortcut is
177
+ provided. So you can do:
178
+
179
+ class ProjectsController < InheritedResources::Base
180
+ def destroy
181
+ destroy!{ root_url }
182
+ end
183
+ end
184
+
185
+ Now let's suppose that before create a project you have to do something special
186
+ but you don't want to create a before filter for it:
187
+
188
+ class ProjectsController < InheritedResources::Base
189
+ def create
190
+ @project = Project.new(params[:project])
191
+ @project.something_special!
192
+ create!
193
+ end
194
+ end
195
+
196
+ Yes, that simple! The nice part is since you already set the instance variable
197
+ @project, it will not build a project again.
198
+
199
+ Before we finish this topic, we should talk about one more thing: "success/failure
200
+ blocks". Let's suppose that when we update our project, in case of failure, we
201
+ want to redirect to the project url instead of re-rendering the edit template.
202
+
203
+ Our first attempt to do this would be:
204
+
205
+ class ProjectsController < InheritedResources::Base
206
+ def update
207
+ update! do |format|
208
+ unless @project.errors.empty? # failure
209
+ format.html { redirect_to project_url(@project) }
210
+ end
211
+ end
212
+ end
213
+ end
214
+
215
+ Looks to verbose, right? We can actually do:
216
+
217
+ class ProjectsController < InheritedResources::Base
218
+ def update
219
+ update! do |success, failure|
220
+ failure.html { redirect_to project_url(@project) }
221
+ end
222
+ end
223
+ end
224
+
225
+ Much better! So explaining everything: when you give a block which expects one
226
+ argument it will be executed in both scenarios: success and failure. But If you
227
+ give a block that expects two arguments, the first will be executed only in
228
+ success scenarios and the second in failure scenarios. You keep everything
229
+ clean and organized inside the same action.
230
+
231
+ == Some DSL
232
+
233
+ For those DSL lovers, InheritedResources won't leave you alone. You can overwrite
234
+ your success/failure blocks straight from your class binding. For it, you just
235
+ need to add a DSL block to your application controller:
236
+
237
+ class ApplicationController < ActionController::Base
238
+ include InheritedResources::DSL
239
+ end
240
+
241
+ And then you can rewrite the last example as:
242
+
243
+ class ProjectsController < InheritedResources::Base
244
+ update! do |success, failure|
245
+ failure.html { redirect_to project_url(@project) }
246
+ end
247
+ end
248
+
249
+ == Flash messages and I18n
250
+
251
+ Flash messages are powered by I18n api. It checks for messages in the following
252
+ order:
253
+
254
+ flash.controller_name.action_name.status
255
+ flash.actions.action_name.status
256
+
257
+ If none is available, a default message in english set. In a create action
258
+ on projects controller, it will search for:
259
+
260
+ flash.projects.create.status
261
+ flash.actions.create.status
262
+
263
+ The status can be :notice (when the object can be created, updated
264
+ or destroyed with success) or :error (when the objecy cannot be created
265
+ or updated).
266
+
267
+ Those messages are interpolated by using the resource class human name, which
268
+ is also localized and it means you can set:
269
+
270
+ flash:
271
+ actions:
272
+ create:
273
+ notice: "Hooray! {{resource_name}} was successfully created!"
274
+
275
+ It will replace {{resource_name}} by the human name of the resource class,
276
+ which is "Project" in this case.
277
+
278
+ But sometimes, flash messages are not that simple. Sometimes you want to say
279
+ the title of the project while updating a project. Well, that's easy also:
280
+
281
+ flash:
282
+ projects:
283
+ update:
284
+ notice: "Hooray! The project "{{project_title}}" was updated!"
285
+
286
+ Since :project_title is not available for interpolation by default, you have
287
+ to overwrite interpolation_options.
288
+
289
+ def interpolation_options
290
+ { :project_title => @project.title }
291
+ end
292
+
293
+ Then you will finally have:
294
+
295
+ "Hooray! The project "Plataforma" was updated!"
296
+
297
+ By default, resource name is capitalized. If you want to make it lower case, you
298
+ can add to your application controller:
299
+
300
+ def interpolation_options
301
+ { :resource_name => resource_class.human_name.downcase }
302
+ end
303
+
304
+ Finally, if your controller is namespaced, for example Admin::ProjectsController,
305
+ the messages will be checked in the following order:
306
+
307
+ flash.admin.projects.create.notice
308
+ flash.admin.actions.create.notice
309
+ flash.projects.create.notice
310
+ flash.actions.create.notice
311
+
312
+ == Has Scope
313
+
314
+ InheritedResources tries to integrate nicely with your model. In order to do so,
315
+ it also is named_scope fluent. Let's suppose our Project model with the scopes:
316
+
317
+ class Project < ActiveRecord::Base
318
+ named_scope :featured, :conditions => { :featured => true }
319
+ named_scope :by_methodology, proc {|methodology| { :conditions => { :methodology => methodology } } }
320
+ named_scope :limit, proc{|limit| :limit => limit.to_i }
321
+ end
322
+
323
+ Your controller:
324
+
325
+ class ProjectsController < InheritedResources::Base
326
+ has_scope :featured, :boolean => true, :only => :index
327
+ has_scope :by_methodology
328
+ has_scope :limit, :default => 10
329
+ end
330
+
331
+ Then for each request:
332
+
333
+ /projects
334
+ #=> acts like a normal request, but returning 10 projects
335
+
336
+ /projects?featured=true
337
+ #=> calls the featured named scope and bring 10 featured projects
338
+
339
+ /projects?featured=true&by_methodology=agile&limit=20
340
+ #=> brings 20 featured projects with methodology agile
341
+
342
+ You can retrieve the current scopes in use with :current_scopes method.
343
+ In the last case, it would return:
344
+
345
+ { :featured => "true", :by_methodology => "agile", :limit => "20" }
346
+
347
+ Finally, let's suppose you store on the session how many projects the user sees
348
+ per page. In such cases, you can give a proc as default value:
349
+
350
+ has_scope :limit, :default => proc{|c| c.session[:limit] || 10 }
351
+
352
+ == Belongs to
353
+
354
+ Finally, our Projects are going to get some Tasks. Then you create a
355
+ TasksController and do:
356
+
357
+ class TasksController < InheritedResources::Base
358
+ belongs_to :project
359
+ end
360
+
361
+ belongs_to accepts several options to be able to configure the association.
362
+ For example, if you want urls like /projects/:project_title/tasks, you can
363
+ customize how InheritedResources find your projects:
364
+
365
+ class TasksController < InheritedResources::Base
366
+ belongs_to :project, :finder => :find_by_title!, :param => :project_title
367
+ end
368
+
369
+ It also accepts :route_name, :parent_class and :instance_name as options.
370
+ Check the lib/inherited_resources/class_methods.rb for more.
371
+
372
+ == Nested belongs to
373
+
374
+ Now, our Tasks get some Comments and you need to nest even deeper. Good
375
+ practices says that you should never nest more than two resources, but sometimes
376
+ you have to for security reasons. So this is an example of how you can do it:
377
+
378
+ class CommentsController < InheritedResources::Base
379
+ nested_belongs_to :project, :task
380
+ end
381
+
382
+ If you need to configure any of these belongs to, you can nest them using blocks:
383
+
384
+ class CommentsController < InheritedResources::Base
385
+ belongs_to :project, :finder => :find_by_title!, :param => :project_title do
386
+ belongs_to :task
387
+ end
388
+ end
389
+
390
+ Warning: calling several belongs_to is the same as nesting them:
391
+
392
+ class CommentsConroller < InheritedResources::Base
393
+ belongs_to :project
394
+ belongs_to :task
395
+ end
396
+
397
+ In other words, the code above is the same as calling nested_belongs_to.
398
+
399
+ == Polymorphic belongs to
400
+
401
+ We can go even further. Let's suppose our Projects can now have Files, Messages
402
+ and Tasks, and they are all commentable. In this case, the best solution is to
403
+ use polymorphism:
404
+
405
+ class CommentsController < InheritedResources::Base
406
+ belongs_to :task, :file, :message, :polymorphic => true
407
+ # polymorphic_belongs_to :task, :file, :message
408
+ end
409
+
410
+ You can even use it with nested resources:
411
+
412
+ class CommentsController < InheritedResources::Base
413
+ belongs_to :project do
414
+ belongs_to :task, :file, :message, :polymorphic => true
415
+ end
416
+ end
417
+
418
+ The url in such cases can be:
419
+
420
+ /project/1/task/13/comments
421
+ /project/1/file/11/comments
422
+ /project/1/message/9/comments
423
+
424
+ When using polymorphic associations, you get some free helpers:
425
+
426
+ parent? #=> true
427
+ parent_type #=> :task
428
+ parent_class #=> Task
429
+ parent #=> @task
430
+
431
+ Right now, Inherited Resources is limited and does not allow you
432
+ to have two polymorphic associations nested.
433
+
434
+ == Optional belongs to
435
+
436
+ Later you decide to create a view to show all comments, independent if they belong
437
+ to a task, file or message. You can reuse your polymorphic controller just doing:
438
+
439
+ class ProjectsController < InheritedResources::Base
440
+ belongs_to :task, :file, :message, :optional => true
441
+ # optional_belongs_to :task, :file, :message
442
+ end
443
+
444
+ This will handle all those urls properly:
445
+
446
+ /comment/1
447
+ /tasks/2/comment/5
448
+ /files/10/comment/3
449
+ /messages/13/comment/11
450
+
451
+ This is treated as a special type of polymorphic associations, thus all helpers
452
+ are available. As you expect, when no parent is found, the helpers return:
453
+
454
+ parent? #=> false
455
+ parent_type #=> nil
456
+ parent_class #=> nil
457
+ parent #=> nil
458
+
459
+ == Singletons
460
+
461
+ Now we are going to add manager to projects. We say that Manager is a singleton
462
+ resource because a Project has just one manager. You should declare it as
463
+ has_one (or resource) in your routes.
464
+
465
+ To declare an association as singleton, you just have to give the :singleton
466
+ option.
467
+
468
+ class ManagersController < InheritedResources::Base
469
+ belongs_to :project, :singleton => true
470
+ # singleton_belongs_to :project
471
+ end
472
+
473
+ It will deal with everything again and hide the action :index from you.
474
+
475
+ == URL Helpers
476
+
477
+ When you use InheritedResources it creates some URL helpers.
478
+ And they handle everything for you. :)
479
+
480
+ # /posts/1/comments
481
+ resource_url # => /posts/1/comments/#{@comment.to_param}
482
+ resource_url(comment) # => /posts/1/comments/#{comment.to_param}
483
+ new_resource_url # => /posts/1/comments/new
484
+ edit_resource_url # => /posts/1/comments/#{@comment.to_param}/edit
485
+ edit_resource_url(comment) #=> /posts/1/comments/#{comment.to_param}/edit
486
+ collection_url # => /posts/1/comments
487
+ parent_url # => /posts/1
488
+
489
+ # /projects/1/tasks
490
+ resource_url # => /projects/1/tasks/#{@task.to_param}
491
+ resource_url(task) # => /projects/1/tasks/#{task.to_param}
492
+ new_resource_url # => /projects/1/tasks/new
493
+ edit_resource_url # => /projects/1/tasks/#{@task.to_param}/edit
494
+ edit_resource_url(task) # => /projects/1/tasks/#{task.to_param}/edit
495
+ collection_url # => /projects/1/tasks
496
+ parent_url # => /projects/1
497
+
498
+ # /users
499
+ resource_url # => /users/#{@user.to_param}
500
+ resource_url(user) # => /users/#{user.to_param}
501
+ new_resource_url # => /users/new
502
+ edit_resource_url # => /users/#{@user.to_param}/edit
503
+ edit_resource_url(user) # => /users/#{user.to_param}/edit
504
+ collection_url # => /users
505
+ parent_url # => /
506
+
507
+ Those urls helpers also accepts a hash as options, just as in named routes.
508
+
509
+ # /projects/1/tasks
510
+ collection_url(:page => 1, :limit => 10) #=> /projects/1/tasks?page=1&limit=10
511
+
512
+ In polymorphic cases, you can also give the parent as parameter to collection_url.
513
+
514
+ Another nice thing is that those urls are not guessed during runtime. They are
515
+ all created when your application is loaded (except for polymorphic
516
+ associations, that relies on Rails polymorphic_url).
517
+
518
+ == Bugs and Feedback
519
+
520
+ If you discover any bugs or want to drop a line, join us in the mailing list:
521
+
522
+ http://groups.google.com/group/inherited_resources
523
+
524
+ Copyright (c) 2009 José Valim http://blog.plataformatec.com.br