base_rails_app 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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