Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Outdented protected code sections per contribution guide.

  • Loading branch information...
commit e875ad02195203760bc14c16835c08c2948a4376 1 parent 906abbf
@parndt authored
Showing with 2,999 additions and 2,999 deletions.
  1. +11 −11 actionmailer/lib/action_mailer/test_case.rb
  2. +22 −22 actionmailer/test/base_test.rb
  3. +1 −1  actionmailer/test/mail_helper_test.rb
  4. +9 −9 actionpack/lib/action_controller/caching/sweeping.rb
  5. +94 −94 actionpack/lib/action_controller/metal/data_streaming.rb
  6. +13 −13 actionpack/lib/action_controller/metal/flash.rb
  7. +34 −34 actionpack/lib/action_controller/metal/http_authentication.rb
  8. +1 −1  actionpack/lib/action_controller/metal/params_wrapper.rb
  9. +42 −42 actionpack/lib/action_controller/metal/request_forgery_protection.rb
  10. +1 −1  actionpack/lib/action_controller/metal/streaming.rb
  11. +8 −8 actionpack/lib/action_controller/test_case.rb
  12. +1 −1  actionpack/lib/action_dispatch/http/mime_negotiation.rb
  13. +1 −1  actionpack/lib/action_dispatch/middleware/flash.rb
  14. +972 −972 actionpack/lib/action_dispatch/routing/mapper.rb
  15. +1 −1  actionpack/lib/action_dispatch/routing/url_for.rb
  16. +5 −5 actionpack/lib/action_dispatch/testing/assertions/selector.rb
  17. +1 −1  actionpack/lib/action_view/renderer/abstract_renderer.rb
  18. +85 −85 actionpack/lib/action_view/template.rb
  19. +1 −1  actionpack/lib/action_view/template/handlers/builder.rb
  20. +1 −1  actionpack/test/abstract_unit.rb
  21. +9 −9 actionpack/test/controller/assert_select_test.rb
  22. +18 −18 actionpack/test/controller/filters_test.rb
  23. +7 −7 actionpack/test/controller/mime_responds_test.rb
  24. +3 −3 actionpack/test/controller/new_base/base_test.rb
  25. +1 −1  actionpack/test/controller/new_base/render_context_test.rb
  26. +4 −4 actionpack/test/controller/redirect_test.rb
  27. +11 −11 actionpack/test/controller/rescue_test.rb
  28. +221 −221 actionpack/test/controller/resources_test.rb
  29. +7 −7 actionpack/test/template/date_helper_test.rb
  30. +1 −1  actionpack/test/template/form_helper_test.rb
  31. +7 −7 actionpack/test/template/output_buffer_test.rb
  32. +6 −6 actionpack/test/template/url_helper_test.rb
  33. +8 −8 activemodel/lib/active_model/attribute_methods.rb
  34. +1 −1  activemodel/lib/active_model/mass_assignment_security.rb
  35. +58 −58 activemodel/lib/active_model/observer_array.rb
  36. +28 −28 activemodel/lib/active_model/observing.rb
  37. +1 −1  activerecord/lib/active_record/associations/join_dependency.rb
  38. +14 −14 activerecord/lib/active_record/associations/through_association.rb
  39. +1 −1  activerecord/lib/active_record/attribute_assignment.rb
  40. +1 −1  activerecord/lib/active_record/attribute_methods.rb
  41. +1 −1  activerecord/lib/active_record/attribute_methods/primary_key.rb
  42. +1 −1  activerecord/lib/active_record/attribute_methods/read.rb
  43. +1 −1  activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
  44. +8 −8 activerecord/lib/active_record/attribute_methods/write.rb
  45. +46 −46 activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
  46. +52 −52 activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
  47. +21 −21 activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
  48. +1 −1  activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
  49. +33 −33 activerecord/lib/active_record/connection_adapters/column.rb
  50. +15 −15 activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
  51. +91 −91 activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
  52. +1 −1  activerecord/lib/active_record/inheritance.rb
  53. +20 −20 activerecord/lib/active_record/observer.rb
  54. +1 −1  activerecord/lib/active_record/relation/delegation.rb
  55. +1 −1  activerecord/lib/active_record/relation/finder_methods.rb
  56. +1 −1  activerecord/lib/active_record/sanitization.rb
  57. +1 −1  activerecord/lib/active_record/scoping.rb
  58. +1 −1  activerecord/lib/active_record/scoping/default.rb
  59. +1 −1  activerecord/lib/active_record/transactions.rb
  60. +7 −7 activerecord/lib/rails/generators/active_record/migration/migration_generator.rb
  61. +4 −4 activerecord/lib/rails/generators/active_record/model/model_generator.rb
  62. +7 −7 activerecord/lib/rails/generators/active_record/session_migration/session_migration_generator.rb
  63. +19 −19 activerecord/test/cases/finder_test.rb
  64. +24 −24 activerecord/test/cases/locking_test.rb
  65. +9 −9 activerecord/test/cases/migration_test.rb
  66. +1 −1  activerecord/test/models/company.rb
  67. +1 −1  activerecord/test/models/company_in_module.rb
  68. +5 −5 activerecord/test/models/subject.rb
  69. +16 −16 activerecord/test/models/topic.rb
  70. +39 −39 activeresource/lib/active_resource/base.rb
  71. +15 −15 activeresource/test/cases/connection_test.rb
  72. +1 −1  activeresource/test/cases/validations_test.rb
  73. +27 −27 activesupport/lib/active_support/cache.rb
  74. +26 −26 activesupport/lib/active_support/cache/file_store.rb
  75. +32 −32 activesupport/lib/active_support/cache/mem_cache_store.rb
  76. +27 −27 activesupport/lib/active_support/cache/memory_store.rb
  77. +9 −9 activesupport/lib/active_support/cache/null_store.rb
  78. +19 −19 activesupport/lib/active_support/cache/strategy/local_cache.rb
  79. +14 −14 activesupport/lib/active_support/dependencies.rb
  80. +11 −11 activesupport/lib/active_support/duration.rb
  81. +12 −12 activesupport/lib/active_support/hash_with_indifferent_access.rb
  82. +15 −15 activesupport/lib/active_support/multibyte/chars.rb
  83. +7 −7 activesupport/lib/active_support/rescuable.rb
  84. +38 −38 activesupport/lib/active_support/testing/performance.rb
  85. +20 −20 activesupport/lib/active_support/testing/performance/jruby.rb
  86. +17 −17 activesupport/lib/active_support/testing/performance/rubinius.rb
  87. +29 −29 activesupport/lib/active_support/testing/performance/ruby.rb
  88. +7 −7 activesupport/lib/active_support/values/time_zone.rb
  89. +1 −1  activesupport/lib/active_support/xml_mini.rb
  90. +14 −14 activesupport/test/core_ext/date_ext_test.rb
  91. +7 −7 activesupport/test/core_ext/date_time_ext_test.rb
  92. +7 −7 activesupport/test/core_ext/duration_test.rb
  93. +7 −7 activesupport/test/core_ext/numeric_ext_test.rb
  94. +10 −10 activesupport/test/core_ext/time_ext_test.rb
  95. +14 −14 activesupport/test/core_ext/time_with_zone_test.rb
  96. +1 −1  activesupport/test/descendants_tracker_test_cases.rb
  97. +10 −10 activesupport/test/json/encoding_test.rb
  98. +23 −23 activesupport/test/multibyte_conformance.rb
  99. +4 −4 activesupport/test/notifications_test.rb
  100. +17 −17 activesupport/test/test_test.rb
  101. +7 −7 activesupport/test/time_zone_test.rb
  102. +63 −63 railties/lib/rails/generators.rb
  103. +20 −20 railties/lib/rails/generators/actions.rb
  104. +108 −108 railties/lib/rails/generators/base.rb
  105. +1 −1  railties/lib/rails/generators/erb.rb
  106. +1 −1  railties/lib/rails/generators/erb/mailer/mailer_generator.rb
  107. +126 −126 railties/lib/rails/generators/named_base.rb
  108. +1 −1  railties/lib/rails/generators/rails/assets/assets_generator.rb
  109. +7 −7 railties/lib/rails/generators/rails/generator/generator_generator.rb
  110. +35 −35 railties/lib/rails/generators/resource_helpers.rb
  111. +16 −16 railties/lib/rails/generators/test_case.rb
  112. +1 −1  railties/lib/rails/info_controller.rb
  113. +4 −4 railties/lib/rails/railtie.rb
  114. +1 −1  railties/lib/rails/railtie/configurable.rb
  115. +1 −1  railties/test/application/loading_test.rb
  116. +4 −4 railties/test/generators/actions_test.rb
  117. +4 −4 railties/test/generators/named_base_test.rb
  118. +18 −18 railties/test/rails_info_test.rb
View
22 actionmailer/lib/action_mailer/test_case.rb
@@ -49,19 +49,19 @@ def determine_default_mailer(name)
end
end
- protected
+ protected
- def initialize_test_deliveries
- ActionMailer::Base.delivery_method = :test
- ActionMailer::Base.perform_deliveries = true
- ActionMailer::Base.deliveries.clear
- end
+ def initialize_test_deliveries
+ ActionMailer::Base.delivery_method = :test
+ ActionMailer::Base.perform_deliveries = true
+ ActionMailer::Base.deliveries.clear
+ end
- def set_expected_mail
- @expected = Mail.new
- @expected.content_type ["text", "plain", { "charset" => charset }]
- @expected.mime_version = '1.0'
- end
+ def set_expected_mail
+ @expected = Mail.new
+ @expected.content_type ["text", "plain", { "charset" => charset }]
+ @expected.mime_version = '1.0'
+ end
private
View
44 actionmailer/test/base_test.rb
@@ -610,28 +610,28 @@ def notify
assert_equal Set.new(["notify"]), FooMailer.action_methods
end
- protected
-
- # Execute the block setting the given values and restoring old values after
- # the block is executed.
- def swap(klass, new_values)
- old_values = {}
- new_values.each do |key, value|
- old_values[key] = klass.send key
- klass.send :"#{key}=", value
- end
- yield
- ensure
- old_values.each do |key, value|
- klass.send :"#{key}=", value
- end
+protected
+
+ # Execute the block setting the given values and restoring old values after
+ # the block is executed.
+ def swap(klass, new_values)
+ old_values = {}
+ new_values.each do |key, value|
+ old_values[key] = klass.send key
+ klass.send :"#{key}=", value
end
-
- def with_default(klass, new_values)
- old = klass.default_params
- klass.default(new_values)
- yield
- ensure
- klass.default_params = old
+ yield
+ ensure
+ old_values.each do |key, value|
+ klass.send :"#{key}=", value
end
+ end
+
+ def with_default(klass, new_values)
+ old = klass.default_params
+ klass.default(new_values)
+ yield
+ ensure
+ klass.default_params = old
+ end
end
View
2  actionmailer/test/mail_helper_test.rb
@@ -59,7 +59,7 @@ def use_block_format
end
end
- protected
+protected
def mail_with_defaults(&block)
mail(:to => "test@localhost", :from => "tester@example.com",
View
18 actionpack/lib/action_controller/caching/sweeping.rb
@@ -67,16 +67,16 @@ def after(controller)
self.controller = nil
end
- protected
- # gets the action cache path for the given options.
- def action_path_for(options)
- Actions::ActionCachePath.new(controller, options).path
- end
+ protected
+ # gets the action cache path for the given options.
+ def action_path_for(options)
+ Actions::ActionCachePath.new(controller, options).path
+ end
- # Retrieve instance variables set in the controller.
- def assigns(key)
- controller.instance_variable_get("@#{key}")
- end
+ # Retrieve instance variables set in the controller.
+ def assigns(key)
+ controller.instance_variable_get("@#{key}")
+ end
private
def callback(timing)
View
188 actionpack/lib/action_controller/metal/data_streaming.rb
@@ -13,103 +13,103 @@ module DataStreaming
:disposition => 'attachment'.freeze,
}.freeze
- protected
- # Sends the file. This uses a server-appropriate method (such as X-Sendfile)
- # via the Rack::Sendfile middleware. The header to use is set via
- # config.action_dispatch.x_sendfile_header.
- # Your server can also configure this for you by setting the X-Sendfile-Type header.
- #
- # Be careful to sanitize the path parameter if it is coming from a web
- # page. <tt>send_file(params[:path])</tt> allows a malicious user to
- # download any file on your server.
- #
- # Options:
- # * <tt>:filename</tt> - suggests a filename for the browser to use.
- # Defaults to <tt>File.basename(path)</tt>.
- # * <tt>:type</tt> - specifies an HTTP content type.
- # You can specify either a string or a symbol for a registered type register with
- # <tt>Mime::Type.register</tt>, for example :json
- # If omitted, type will be guessed from the file extension specified in <tt>:filename</tt>.
- # If no content type is registered for the extension, default type 'application/octet-stream' will be used.
- # * <tt>:disposition</tt> - specifies whether the file will be shown inline or downloaded.
- # Valid values are 'inline' and 'attachment' (default).
- # * <tt>:status</tt> - specifies the status code to send with the response. Defaults to 200.
- # * <tt>:url_based_filename</tt> - set to +true+ if you want the browser guess the filename from
- # the URL, which is necessary for i18n filenames on certain browsers
- # (setting <tt>:filename</tt> overrides this option).
- #
- # The default Content-Type and Content-Disposition headers are
- # set to download arbitrary binary files in as many browsers as
- # possible. IE versions 4, 5, 5.5, and 6 are all known to have
- # a variety of quirks (especially when downloading over SSL).
- #
- # Simple download:
- #
- # send_file '/path/to.zip'
- #
- # Show a JPEG in the browser:
- #
- # send_file '/path/to.jpeg', :type => 'image/jpeg', :disposition => 'inline'
- #
- # Show a 404 page in the browser:
- #
- # send_file '/path/to/404.html', :type => 'text/html; charset=utf-8', :status => 404
- #
- # Read about the other Content-* HTTP headers if you'd like to
- # provide the user with more information (such as Content-Description) in
- # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11.
- #
- # Also be aware that the document may be cached by proxies and browsers.
- # The Pragma and Cache-Control headers declare how the file may be cached
- # by intermediaries. They default to require clients to validate with
- # the server before releasing cached responses. See
- # http://www.mnot.net/cache_docs/ for an overview of web caching and
- # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9
- # for the Cache-Control header spec.
- def send_file(path, options = {}) #:doc:
- raise MissingFile, "Cannot read file #{path}" unless File.file?(path) and File.readable?(path)
+ protected
+ # Sends the file. This uses a server-appropriate method (such as X-Sendfile)
+ # via the Rack::Sendfile middleware. The header to use is set via
+ # config.action_dispatch.x_sendfile_header.
+ # Your server can also configure this for you by setting the X-Sendfile-Type header.
+ #
+ # Be careful to sanitize the path parameter if it is coming from a web
+ # page. <tt>send_file(params[:path])</tt> allows a malicious user to
+ # download any file on your server.
+ #
+ # Options:
+ # * <tt>:filename</tt> - suggests a filename for the browser to use.
+ # Defaults to <tt>File.basename(path)</tt>.
+ # * <tt>:type</tt> - specifies an HTTP content type.
+ # You can specify either a string or a symbol for a registered type register with
+ # <tt>Mime::Type.register</tt>, for example :json
+ # If omitted, type will be guessed from the file extension specified in <tt>:filename</tt>.
+ # If no content type is registered for the extension, default type 'application/octet-stream' will be used.
+ # * <tt>:disposition</tt> - specifies whether the file will be shown inline or downloaded.
+ # Valid values are 'inline' and 'attachment' (default).
+ # * <tt>:status</tt> - specifies the status code to send with the response. Defaults to 200.
+ # * <tt>:url_based_filename</tt> - set to +true+ if you want the browser guess the filename from
+ # the URL, which is necessary for i18n filenames on certain browsers
+ # (setting <tt>:filename</tt> overrides this option).
+ #
+ # The default Content-Type and Content-Disposition headers are
+ # set to download arbitrary binary files in as many browsers as
+ # possible. IE versions 4, 5, 5.5, and 6 are all known to have
+ # a variety of quirks (especially when downloading over SSL).
+ #
+ # Simple download:
+ #
+ # send_file '/path/to.zip'
+ #
+ # Show a JPEG in the browser:
+ #
+ # send_file '/path/to.jpeg', :type => 'image/jpeg', :disposition => 'inline'
+ #
+ # Show a 404 page in the browser:
+ #
+ # send_file '/path/to/404.html', :type => 'text/html; charset=utf-8', :status => 404
+ #
+ # Read about the other Content-* HTTP headers if you'd like to
+ # provide the user with more information (such as Content-Description) in
+ # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11.
+ #
+ # Also be aware that the document may be cached by proxies and browsers.
+ # The Pragma and Cache-Control headers declare how the file may be cached
+ # by intermediaries. They default to require clients to validate with
+ # the server before releasing cached responses. See
+ # http://www.mnot.net/cache_docs/ for an overview of web caching and
+ # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9
+ # for the Cache-Control header spec.
+ def send_file(path, options = {}) #:doc:
+ raise MissingFile, "Cannot read file #{path}" unless File.file?(path) and File.readable?(path)
- options[:filename] ||= File.basename(path) unless options[:url_based_filename]
- send_file_headers! options
+ options[:filename] ||= File.basename(path) unless options[:url_based_filename]
+ send_file_headers! options
- self.status = options[:status] || 200
- self.content_type = options[:content_type] if options.key?(:content_type)
- self.response_body = File.open(path, "rb")
- end
+ self.status = options[:status] || 200
+ self.content_type = options[:content_type] if options.key?(:content_type)
+ self.response_body = File.open(path, "rb")
+ end
- # Sends the given binary data to the browser. This method is similar to
- # <tt>render :text => data</tt>, but also allows you to specify whether
- # the browser should display the response as a file attachment (i.e. in a
- # download dialog) or as inline data. You may also set the content type,
- # the apparent file name, and other things.
- #
- # Options:
- # * <tt>:filename</tt> - suggests a filename for the browser to use.
- # * <tt>:type</tt> - specifies an HTTP content type. Defaults to 'application/octet-stream'. You can specify
- # either a string or a symbol for a registered type register with <tt>Mime::Type.register</tt>, for example :json
- # If omitted, type will be guessed from the file extension specified in <tt>:filename</tt>.
- # If no content type is registered for the extension, default type 'application/octet-stream' will be used.
- # * <tt>:disposition</tt> - specifies whether the file will be shown inline or downloaded.
- # Valid values are 'inline' and 'attachment' (default).
- # * <tt>:status</tt> - specifies the status code to send with the response. Defaults to 200.
- #
- # Generic data download:
- #
- # send_data buffer
- #
- # Download a dynamically-generated tarball:
- #
- # send_data generate_tgz('dir'), :filename => 'dir.tgz'
- #
- # Display an image Active Record in the browser:
- #
- # send_data image.data, :type => image.content_type, :disposition => 'inline'
- #
- # See +send_file+ for more information on HTTP Content-* headers and caching.
- def send_data(data, options = {}) #:doc:
- send_file_headers! options.dup
- render options.slice(:status, :content_type).merge(:text => data)
- end
+ # Sends the given binary data to the browser. This method is similar to
+ # <tt>render :text => data</tt>, but also allows you to specify whether
+ # the browser should display the response as a file attachment (i.e. in a
+ # download dialog) or as inline data. You may also set the content type,
+ # the apparent file name, and other things.
+ #
+ # Options:
+ # * <tt>:filename</tt> - suggests a filename for the browser to use.
+ # * <tt>:type</tt> - specifies an HTTP content type. Defaults to 'application/octet-stream'. You can specify
+ # either a string or a symbol for a registered type register with <tt>Mime::Type.register</tt>, for example :json
+ # If omitted, type will be guessed from the file extension specified in <tt>:filename</tt>.
+ # If no content type is registered for the extension, default type 'application/octet-stream' will be used.
+ # * <tt>:disposition</tt> - specifies whether the file will be shown inline or downloaded.
+ # Valid values are 'inline' and 'attachment' (default).
+ # * <tt>:status</tt> - specifies the status code to send with the response. Defaults to 200.
+ #
+ # Generic data download:
+ #
+ # send_data buffer
+ #
+ # Download a dynamically-generated tarball:
+ #
+ # send_data generate_tgz('dir'), :filename => 'dir.tgz'
+ #
+ # Display an image Active Record in the browser:
+ #
+ # send_data image.data, :type => image.content_type, :disposition => 'inline'
+ #
+ # See +send_file+ for more information on HTTP Content-* headers and caching.
+ def send_data(data, options = {}) #:doc:
+ send_file_headers! options.dup
+ render options.slice(:status, :content_type).merge(:text => data)
+ end
private
def send_file_headers!(options)
View
26 actionpack/lib/action_controller/metal/flash.rb
@@ -8,21 +8,21 @@ module Flash
helper_method :alert, :notice
end
- protected
- def redirect_to(options = {}, response_status_and_flash = {}) #:doc:
- if alert = response_status_and_flash.delete(:alert)
- flash[:alert] = alert
- end
-
- if notice = response_status_and_flash.delete(:notice)
- flash[:notice] = notice
- end
+ protected
+ def redirect_to(options = {}, response_status_and_flash = {}) #:doc:
+ if alert = response_status_and_flash.delete(:alert)
+ flash[:alert] = alert
+ end
- if other_flashes = response_status_and_flash.delete(:flash)
- flash.update(other_flashes)
- end
+ if notice = response_status_and_flash.delete(:notice)
+ flash[:notice] = notice
+ end
- super(options, response_status_and_flash)
+ if other_flashes = response_status_and_flash.delete(:flash)
+ flash.update(other_flashes)
end
+
+ super(options, response_status_and_flash)
+ end
end
end
View
68 actionpack/lib/action_controller/metal/http_authentication.rb
@@ -27,27 +27,27 @@ module HttpAuthentication
# class ApplicationController < ActionController::Base
# before_filter :set_account, :authenticate
#
- # protected
- # def set_account
- # @account = Account.find_by_url_name(request.subdomains.first)
- # end
+ # protected
+ # def set_account
+ # @account = Account.find_by_url_name(request.subdomains.first)
+ # end
#
- # def authenticate
- # case request.format
- # when Mime::XML, Mime::ATOM
- # if user = authenticate_with_http_basic { |u, p| @account.users.authenticate(u, p) }
- # @current_user = user
- # else
- # request_http_basic_authentication
- # end
+ # def authenticate
+ # case request.format
+ # when Mime::XML, Mime::ATOM
+ # if user = authenticate_with_http_basic { |u, p| @account.users.authenticate(u, p) }
+ # @current_user = user
# else
- # if session_authenticated?
- # @current_user = @account.users.find(session[:authenticated][:user_id])
- # else
- # redirect_to(login_url) and return false
- # end
+ # request_http_basic_authentication
+ # end
+ # else
+ # if session_authenticated?
+ # @current_user = @account.users.find(session[:authenticated][:user_id])
+ # else
+ # redirect_to(login_url) and return false
# end
# end
+ # end
# end
#
# In your integration tests, you can do something like this:
@@ -341,27 +341,27 @@ def opaque(secret_key)
# class ApplicationController < ActionController::Base
# before_filter :set_account, :authenticate
#
- # protected
- # def set_account
- # @account = Account.find_by_url_name(request.subdomains.first)
- # end
+ # protected
+ # def set_account
+ # @account = Account.find_by_url_name(request.subdomains.first)
+ # end
#
- # def authenticate
- # case request.format
- # when Mime::XML, Mime::ATOM
- # if user = authenticate_with_http_token { |t, o| @account.users.authenticate(t, o) }
- # @current_user = user
- # else
- # request_http_token_authentication
- # end
+ # def authenticate
+ # case request.format
+ # when Mime::XML, Mime::ATOM
+ # if user = authenticate_with_http_token { |t, o| @account.users.authenticate(t, o) }
+ # @current_user = user
# else
- # if session_authenticated?
- # @current_user = @account.users.find(session[:authenticated][:user_id])
- # else
- # redirect_to(login_url) and return false
- # end
+ # request_http_token_authentication
+ # end
+ # else
+ # if session_authenticated?
+ # @current_user = @account.users.find(session[:authenticated][:user_id])
+ # else
+ # redirect_to(login_url) and return false
# end
# end
+ # end
# end
#
#
View
2  actionpack/lib/action_controller/metal/params_wrapper.rb
@@ -134,7 +134,7 @@ def inherited(klass)
super
end
- protected
+ protected
# Determine the wrapper model from the controller's name. By convention,
# this could be done by trying to find the defined model that has the
View
84 actionpack/lib/action_controller/metal/request_forgery_protection.rb
@@ -76,54 +76,54 @@ def protect_from_forgery(options = {})
end
end
- protected
- # The actual before_filter that is used. Modify this to change how you handle unverified requests.
- def verify_authenticity_token
- unless verified_request?
- logger.warn "Can't verify CSRF token authenticity" if logger
- handle_unverified_request
- end
+ protected
+ # The actual before_filter that is used. Modify this to change how you handle unverified requests.
+ def verify_authenticity_token
+ unless verified_request?
+ logger.warn "Can't verify CSRF token authenticity" if logger
+ handle_unverified_request
end
+ end
- # This is the method that defines the application behavior when a request is found to be unverified.
- # By default, \Rails uses <tt>request_forgery_protection_method</tt> when it finds an unverified request:
- #
- # * <tt>:reset_session</tt> - Resets the session.
- # * <tt>:exception</tt>: - Raises ActionController::InvalidAuthenticityToken exception.
- def handle_unverified_request
- case request_forgery_protection_method
- when :exception
- raise ActionController::InvalidAuthenticityToken
- when :reset_session
- reset_session
- else
- raise ArgumentError, 'Invalid request forgery protection method, use :exception or :reset_session'
- end
+ # This is the method that defines the application behavior when a request is found to be unverified.
+ # By default, \Rails uses <tt>request_forgery_protection_method</tt> when it finds an unverified request:
+ #
+ # * <tt>:reset_session</tt> - Resets the session.
+ # * <tt>:exception</tt>: - Raises ActionController::InvalidAuthenticityToken exception.
+ def handle_unverified_request
+ case request_forgery_protection_method
+ when :exception
+ raise ActionController::InvalidAuthenticityToken
+ when :reset_session
+ reset_session
+ else
+ raise ArgumentError, 'Invalid request forgery protection method, use :exception or :reset_session'
end
+ end
- # Returns true or false if a request is verified. Checks:
- #
- # * is it a GET request? Gets should be safe and idempotent
- # * Does the form_authenticity_token match the given token value from the params?
- # * Does the X-CSRF-Token header match the form_authenticity_token
- def verified_request?
- !protect_against_forgery? || request.get? ||
- form_authenticity_token == params[request_forgery_protection_token] ||
- form_authenticity_token == request.headers['X-CSRF-Token']
- end
+ # Returns true or false if a request is verified. Checks:
+ #
+ # * is it a GET request? Gets should be safe and idempotent
+ # * Does the form_authenticity_token match the given token value from the params?
+ # * Does the X-CSRF-Token header match the form_authenticity_token
+ def verified_request?
+ !protect_against_forgery? || request.get? ||
+ form_authenticity_token == params[request_forgery_protection_token] ||
+ form_authenticity_token == request.headers['X-CSRF-Token']
+ end
- # Sets the token value for the current session.
- def form_authenticity_token
- session[:_csrf_token] ||= SecureRandom.base64(32)
- end
+ # Sets the token value for the current session.
+ def form_authenticity_token
+ session[:_csrf_token] ||= SecureRandom.base64(32)
+ end
- # The form's authenticity parameter. Override to provide your own.
- def form_authenticity_param
- params[request_forgery_protection_token]
- end
+ # The form's authenticity parameter. Override to provide your own.
+ def form_authenticity_param
+ params[request_forgery_protection_token]
+ end
- def protect_against_forgery?
- allow_forgery_protection
- end
+ def protect_against_forgery?
+ allow_forgery_protection
+ end
end
end
View
2  actionpack/lib/action_controller/metal/streaming.rb
@@ -200,7 +200,7 @@ module Streaming
include AbstractController::Rendering
- protected
+ protected
# Set proper cache control and transfer encoding when streaming
def _process_options(options) #:nodoc:
View
16 actionpack/lib/action_controller/test_case.rb
@@ -573,16 +573,16 @@ def self.included(base)
end
end
- protected
- def rescue_action_without_handler(e)
- self.exception = e
+ protected
+ def rescue_action_without_handler(e)
+ self.exception = e
- if request.remote_addr == "0.0.0.0"
- raise(e)
- else
- super(e)
- end
+ if request.remote_addr == "0.0.0.0"
+ raise(e)
+ else
+ super(e)
end
+ end
end
include Behavior
View
2  actionpack/lib/action_dispatch/http/mime_negotiation.rb
@@ -93,7 +93,7 @@ def negotiate_mime(order)
order.include?(Mime::ALL) ? formats.first : nil
end
- protected
+ protected
BROWSER_LIKE_ACCEPTS = /,\s*\*\/\*|\*\/\*\s*,/
View
2  actionpack/lib/action_dispatch/middleware/flash.rb
@@ -206,7 +206,7 @@ def notice=(message)
self[:notice] = message
end
- protected
+ protected
def now_is_loaded?
@now
end
View
1,944 actionpack/lib/action_dispatch/routing/mapper.rb
@@ -232,1119 +232,1119 @@ def default_controller
def default_action
@options[:action] || @scope[:action]
end
- end
-
- # Invokes Rack::Mount::Utils.normalize path and ensure that
- # (:locale) becomes (/:locale) instead of /(:locale). Except
- # for root cases, where the latter is the correct one.
- def self.normalize_path(path)
- path = Journey::Router::Utils.normalize_path(path)
- path.gsub!(%r{/(\(+)/?}, '\1/') unless path =~ %r{^/\(+[^/]+\)$}
- path
- end
-
- def self.normalize_name(name)
- normalize_path(name)[1..-1].gsub("/", "_")
- end
-
- module Base
- # You can specify what Rails should route "/" to with the root method:
- #
- # root :to => 'pages#main'
- #
- # For options, see +match+, as +root+ uses it internally.
- #
- # You can also pass a string which will expand
- #
- # root 'pages#main'
- #
- # You should put the root route at the top of <tt>config/routes.rb</tt>,
- # because this means it will be matched first. As this is the most popular route
- # of most Rails applications, this is beneficial.
- def root(options = {})
- options = { :to => options } if options.is_a?(String)
- match '/', { :as => :root }.merge(options)
end
- # Matches a url pattern to one or more routes. Any symbols in a pattern
- # are interpreted as url query parameters and thus available as +params+
- # in an action:
- #
- # # sets :controller, :action and :id in params
- # match ':controller/:action/:id'
- #
- # Two of these symbols are special, +:controller+ maps to the controller
- # and +:action+ to the controller's action. A pattern can also map
- # wildcard segments (globs) to params:
- #
- # match 'songs/*category/:title' => 'songs#show'
- #
- # # 'songs/rock/classic/stairway-to-heaven' sets
- # # params[:category] = 'rock/classic'
- # # params[:title] = 'stairway-to-heaven'
- #
- # When a pattern points to an internal route, the route's +:action+ and
- # +:controller+ should be set in options or hash shorthand. Examples:
- #
- # match 'photos/:id' => 'photos#show'
- # match 'photos/:id', :to => 'photos#show'
- # match 'photos/:id', :controller => 'photos', :action => 'show'
- #
- # A pattern can also point to a +Rack+ endpoint i.e. anything that
- # responds to +call+:
- #
- # match 'photos/:id' => lambda {|hash| [200, {}, "Coming soon"] }
- # match 'photos/:id' => PhotoRackApp
- # # Yes, controller actions are just rack endpoints
- # match 'photos/:id' => PhotosController.action(:show)
- #
- # === Options
- #
- # Any options not seen here are passed on as params with the url.
- #
- # [:controller]
- # The route's controller.
- #
- # [:action]
- # The route's action.
- #
- # [:path]
- # The path prefix for the routes.
- #
- # [:module]
- # The namespace for :controller.
- #
- # match 'path' => 'c#a', :module => 'sekret', :controller => 'posts'
- # #=> Sekret::PostsController
- #
- # See <tt>Scoping#namespace</tt> for its scope equivalent.
- #
- # [:as]
- # The name used to generate routing helpers.
- #
- # [:via]
- # Allowed HTTP verb(s) for route.
- #
- # match 'path' => 'c#a', :via => :get
- # match 'path' => 'c#a', :via => [:get, :post]
- #
- # [:to]
- # Points to a +Rack+ endpoint. Can be an object that responds to
- # +call+ or a string representing a controller's action.
- #
- # match 'path', :to => 'controller#action'
- # match 'path', :to => lambda { |env| [200, {}, "Success!"] }
- # match 'path', :to => RackApp
- #
- # [:on]
- # Shorthand for wrapping routes in a specific RESTful context. Valid
- # values are +:member+, +:collection+, and +:new+. Only use within
- # <tt>resource(s)</tt> block. For example:
- #
- # resource :bar do
- # match 'foo' => 'c#a', :on => :member, :via => [:get, :post]
- # end
- #
- # Is equivalent to:
- #
- # resource :bar do
- # member do
- # match 'foo' => 'c#a', :via => [:get, :post]
- # end
- # end
- #
- # [:constraints]
- # Constrains parameters with a hash of regular expressions or an
- # object that responds to <tt>matches?</tt>
- #
- # match 'path/:id', :constraints => { :id => /[A-Z]\d{5}/ }
- #
- # class Blacklist
- # def matches?(request) request.remote_ip == '1.2.3.4' end
- # end
- # match 'path' => 'c#a', :constraints => Blacklist.new
- #
- # See <tt>Scoping#constraints</tt> for more examples with its scope
- # equivalent.
- #
- # [:defaults]
- # Sets defaults for parameters
- #
- # # Sets params[:format] to 'jpg' by default
- # match 'path' => 'c#a', :defaults => { :format => 'jpg' }
- #
- # See <tt>Scoping#defaults</tt> for its scope equivalent.
- #
- # [:anchor]
- # Boolean to anchor a <tt>match</tt> pattern. Default is true. When set to
- # false, the pattern matches any request prefixed with the given path.
- #
- # # Matches any request starting with 'path'
- # match 'path' => 'c#a', :anchor => false
- def match(path, options=nil)
+ # Invokes Rack::Mount::Utils.normalize path and ensure that
+ # (:locale) becomes (/:locale) instead of /(:locale). Except
+ # for root cases, where the latter is the correct one.
+ def self.normalize_path(path)
+ path = Journey::Router::Utils.normalize_path(path)
+ path.gsub!(%r{/(\(+)/?}, '\1/') unless path =~ %r{^/\(+[^/]+\)$}
+ path
end
- # Mount a Rack-based application to be used within the application.
- #
- # mount SomeRackApp, :at => "some_route"
- #
- # Alternatively:
- #
- # mount(SomeRackApp => "some_route")
- #
- # For options, see +match+, as +mount+ uses it internally.
- #
- # All mounted applications come with routing helpers to access them.
- # These are named after the class specified, so for the above example
- # the helper is either +some_rack_app_path+ or +some_rack_app_url+.
- # To customize this helper's name, use the +:as+ option:
- #
- # mount(SomeRackApp => "some_route", :as => "exciting")
- #
- # This will generate the +exciting_path+ and +exciting_url+ helpers
- # which can be used to navigate to this mounted app.
- def mount(app, options = nil)
- if options
- path = options.delete(:at)
- else
- options = app
- app, path = options.find { |k, v| k.respond_to?(:call) }
- options.delete(app) if app
- end
-
- raise "A rack application must be specified" unless path
+ def self.normalize_name(name)
+ normalize_path(name)[1..-1].gsub("/", "_")
+ end
- options[:as] ||= app_name(app)
+ module Base
+ # You can specify what Rails should route "/" to with the root method:
+ #
+ # root :to => 'pages#main'
+ #
+ # For options, see +match+, as +root+ uses it internally.
+ #
+ # You can also pass a string which will expand
+ #
+ # root 'pages#main'
+ #
+ # You should put the root route at the top of <tt>config/routes.rb</tt>,
+ # because this means it will be matched first. As this is the most popular route
+ # of most Rails applications, this is beneficial.
+ def root(options = {})
+ options = { :to => options } if options.is_a?(String)
+ match '/', { :as => :root }.merge(options)
+ end
+
+ # Matches a url pattern to one or more routes. Any symbols in a pattern
+ # are interpreted as url query parameters and thus available as +params+
+ # in an action:
+ #
+ # # sets :controller, :action and :id in params
+ # match ':controller/:action/:id'
+ #
+ # Two of these symbols are special, +:controller+ maps to the controller
+ # and +:action+ to the controller's action. A pattern can also map
+ # wildcard segments (globs) to params:
+ #
+ # match 'songs/*category/:title' => 'songs#show'
+ #
+ # # 'songs/rock/classic/stairway-to-heaven' sets
+ # # params[:category] = 'rock/classic'
+ # # params[:title] = 'stairway-to-heaven'
+ #
+ # When a pattern points to an internal route, the route's +:action+ and
+ # +:controller+ should be set in options or hash shorthand. Examples:
+ #
+ # match 'photos/:id' => 'photos#show'
+ # match 'photos/:id', :to => 'photos#show'
+ # match 'photos/:id', :controller => 'photos', :action => 'show'
+ #
+ # A pattern can also point to a +Rack+ endpoint i.e. anything that
+ # responds to +call+:
+ #
+ # match 'photos/:id' => lambda {|hash| [200, {}, "Coming soon"] }
+ # match 'photos/:id' => PhotoRackApp
+ # # Yes, controller actions are just rack endpoints
+ # match 'photos/:id' => PhotosController.action(:show)
+ #
+ # === Options
+ #
+ # Any options not seen here are passed on as params with the url.
+ #
+ # [:controller]
+ # The route's controller.
+ #
+ # [:action]
+ # The route's action.
+ #
+ # [:path]
+ # The path prefix for the routes.
+ #
+ # [:module]
+ # The namespace for :controller.
+ #
+ # match 'path' => 'c#a', :module => 'sekret', :controller => 'posts'
+ # #=> Sekret::PostsController
+ #
+ # See <tt>Scoping#namespace</tt> for its scope equivalent.
+ #
+ # [:as]
+ # The name used to generate routing helpers.
+ #
+ # [:via]
+ # Allowed HTTP verb(s) for route.
+ #
+ # match 'path' => 'c#a', :via => :get
+ # match 'path' => 'c#a', :via => [:get, :post]
+ #
+ # [:to]
+ # Points to a +Rack+ endpoint. Can be an object that responds to
+ # +call+ or a string representing a controller's action.
+ #
+ # match 'path', :to => 'controller#action'
+ # match 'path', :to => lambda { |env| [200, {}, "Success!"] }
+ # match 'path', :to => RackApp
+ #
+ # [:on]
+ # Shorthand for wrapping routes in a specific RESTful context. Valid
+ # values are +:member+, +:collection+, and +:new+. Only use within
+ # <tt>resource(s)</tt> block. For example:
+ #
+ # resource :bar do
+ # match 'foo' => 'c#a', :on => :member, :via => [:get, :post]
+ # end
+ #
+ # Is equivalent to:
+ #
+ # resource :bar do
+ # member do
+ # match 'foo' => 'c#a', :via => [:get, :post]
+ # end
+ # end
+ #
+ # [:constraints]
+ # Constrains parameters with a hash of regular expressions or an
+ # object that responds to <tt>matches?</tt>
+ #
+ # match 'path/:id', :constraints => { :id => /[A-Z]\d{5}/ }
+ #
+ # class Blacklist
+ # def matches?(request) request.remote_ip == '1.2.3.4' end
+ # end
+ # match 'path' => 'c#a', :constraints => Blacklist.new
+ #
+ # See <tt>Scoping#constraints</tt> for more examples with its scope
+ # equivalent.
+ #
+ # [:defaults]
+ # Sets defaults for parameters
+ #
+ # # Sets params[:format] to 'jpg' by default
+ # match 'path' => 'c#a', :defaults => { :format => 'jpg' }
+ #
+ # See <tt>Scoping#defaults</tt> for its scope equivalent.
+ #
+ # [:anchor]
+ # Boolean to anchor a <tt>match</tt> pattern. Default is true. When set to
+ # false, the pattern matches any request prefixed with the given path.
+ #
+ # # Matches any request starting with 'path'
+ # match 'path' => 'c#a', :anchor => false
+ def match(path, options=nil)
+ end
+
+ # Mount a Rack-based application to be used within the application.
+ #
+ # mount SomeRackApp, :at => "some_route"
+ #
+ # Alternatively:
+ #
+ # mount(SomeRackApp => "some_route")
+ #
+ # For options, see +match+, as +mount+ uses it internally.
+ #
+ # All mounted applications come with routing helpers to access them.
+ # These are named after the class specified, so for the above example
+ # the helper is either +some_rack_app_path+ or +some_rack_app_url+.
+ # To customize this helper's name, use the +:as+ option:
+ #
+ # mount(SomeRackApp => "some_route", :as => "exciting")
+ #
+ # This will generate the +exciting_path+ and +exciting_url+ helpers
+ # which can be used to navigate to this mounted app.
+ def mount(app, options = nil)
+ if options
+ path = options.delete(:at)
+ else
+ options = app
+ app, path = options.find { |k, v| k.respond_to?(:call) }
+ options.delete(app) if app
+ end
- match(path, options.merge(:to => app, :anchor => false, :format => false))
+ raise "A rack application must be specified" unless path
- define_generate_prefix(app, options[:as])
- self
- end
+ options[:as] ||= app_name(app)
- def default_url_options=(options)
- @set.default_url_options = options
- end
- alias_method :default_url_options, :default_url_options=
+ match(path, options.merge(:to => app, :anchor => false, :format => false))
- def with_default_scope(scope, &block)
- scope(scope) do
- instance_exec(&block)
+ define_generate_prefix(app, options[:as])
+ self
end
- end
-
- private
- def app_name(app)
- return unless app.respond_to?(:routes)
- if app.respond_to?(:railtie_name)
- app.railtie_name
- else
- class_name = app.class.is_a?(Class) ? app.name : app.class.name
- ActiveSupport::Inflector.underscore(class_name).gsub("/", "_")
+ def default_url_options=(options)
+ @set.default_url_options = options
end
- end
-
- def define_generate_prefix(app, name)
- return unless app.respond_to?(:routes) && app.routes.respond_to?(:define_mounted_helper)
-
- _route = @set.named_routes.routes[name.to_sym]
- _routes = @set
- app.routes.define_mounted_helper(name)
- app.routes.singleton_class.class_eval do
- define_method :mounted? do
- true
- end
+ alias_method :default_url_options, :default_url_options=
- define_method :_generate_prefix do |options|
- prefix_options = options.slice(*_route.segment_keys)
- # we must actually delete prefix segment keys to avoid passing them to next url_for
- _route.segment_keys.each { |k| options.delete(k) }
- prefix = _routes.url_helpers.send("#{name}_path", prefix_options)
- prefix = '' if prefix == '/'
- prefix
+ def with_default_scope(scope, &block)
+ scope(scope) do
+ instance_exec(&block)
end
end
- end
- end
-
- module HttpHelpers
- # Define a route that only recognizes HTTP GET.
- # For supported arguments, see <tt>Base#match</tt>.
- #
- # Example:
- #
- # get 'bacon', :to => 'food#bacon'
- def get(*args, &block)
- map_method(:get, args, &block)
- end
-
- # Define a route that only recognizes HTTP POST.
- # For supported arguments, see <tt>Base#match</tt>.
- #
- # Example:
- #
- # post 'bacon', :to => 'food#bacon'
- def post(*args, &block)
- map_method(:post, args, &block)
- end
- # Define a route that only recognizes HTTP PATCH.
- # For supported arguments, see <tt>Base#match</tt>.
- #
- # Example:
- #
- # patch 'bacon', :to => 'food#bacon'
- def patch(*args, &block)
- map_method(:patch, args, &block)
- end
-
- # Define a route that only recognizes HTTP PUT.
- # For supported arguments, see <tt>Base#match</tt>.
- #
- # Example:
- #
- # put 'bacon', :to => 'food#bacon'
- def put(*args, &block)
- map_method(:put, args, &block)
- end
-
- # Define a route that only recognizes HTTP DELETE.
- # For supported arguments, see <tt>Base#match</tt>.
- #
- # Example:
- #
- # delete 'broccoli', :to => 'food#broccoli'
- def delete(*args, &block)
- map_method(:delete, args, &block)
- end
-
- private
- def map_method(method, args, &block)
- options = args.extract_options!
- options[:via] = method
- match(*args, options, &block)
- self
- end
- end
-
- # You may wish to organize groups of controllers under a namespace.
- # Most commonly, you might group a number of administrative controllers
- # under an +admin+ namespace. You would place these controllers under
- # the <tt>app/controllers/admin</tt> directory, and you can group them
- # together in your router:
- #
- # namespace "admin" do
- # resources :posts, :comments
- # end
- #
- # This will create a number of routes for each of the posts and comments
- # controller. For <tt>Admin::PostsController</tt>, Rails will create:
- #
- # GET /admin/posts
- # GET /admin/posts/new
- # POST /admin/posts
- # GET /admin/posts/1
- # GET /admin/posts/1/edit
- # PATCH/PUT /admin/posts/1
- # DELETE /admin/posts/1
- #
- # If you want to route /posts (without the prefix /admin) to
- # <tt>Admin::PostsController</tt>, you could use
- #
- # scope :module => "admin" do
- # resources :posts
- # end
- #
- # or, for a single case
- #
- # resources :posts, :module => "admin"
- #
- # If you want to route /admin/posts to +PostsController+
- # (without the Admin:: module prefix), you could use
- #
- # scope "/admin" do
- # resources :posts
- # end
- #
- # or, for a single case
- #
- # resources :posts, :path => "/admin/posts"
- #
- # In each of these cases, the named routes remain the same as if you did
- # not use scope. In the last case, the following paths map to
- # +PostsController+:
- #
- # GET /admin/posts
- # GET /admin/posts/new
- # POST /admin/posts
- # GET /admin/posts/1
- # GET /admin/posts/1/edit
- # PATCH/PUT /admin/posts/1
- # DELETE /admin/posts/1
- module Scoping
- # Scopes a set of routes to the given default options.
- #
- # Take the following route definition as an example:
- #
- # scope :path => ":account_id", :as => "account" do
- # resources :projects
- # end
- #
- # This generates helpers such as +account_projects_path+, just like +resources+ does.
- # The difference here being that the routes generated are like /:account_id/projects,
- # rather than /accounts/:account_id/projects.
- #
- # === Options
- #
- # Takes same options as <tt>Base#match</tt> and <tt>Resources#resources</tt>.
- #
- # === Examples
- #
- # # route /posts (without the prefix /admin) to <tt>Admin::PostsController</tt>
- # scope :module => "admin" do
- # resources :posts
- # end
- #
- # # prefix the posts resource's requests with '/admin'
- # scope :path => "/admin" do
- # resources :posts
- # end
- #
- # # prefix the routing helper name: +sekret_posts_path+ instead of +posts_path+
- # scope :as => "sekret" do
- # resources :posts
- # end
- def scope(*args)
- options = args.extract_options!
- options = options.dup
-
- options[:path] = args.first if args.first.is_a?(String)
- recover = {}
-
- options[:constraints] ||= {}
- unless options[:constraints].is_a?(Hash)
- block, options[:constraints] = options[:constraints], {}
- end
+ private
+ def app_name(app)
+ return unless app.respond_to?(:routes)
- scope_options.each do |option|
- if value = options.delete(option)
- recover[option] = @scope[option]
- @scope[option] = send("merge_#{option}_scope", @scope[option], value)
+ if app.respond_to?(:railtie_name)
+ app.railtie_name
+ else
+ class_name = app.class.is_a?(Class) ? app.name : app.class.name
+ ActiveSupport::Inflector.underscore(class_name).gsub("/", "_")
end
end
- recover[:block] = @scope[:blocks]
- @scope[:blocks] = merge_blocks_scope(@scope[:blocks], block)
+ def define_generate_prefix(app, name)
+ return unless app.respond_to?(:routes) && app.routes.respond_to?(:define_mounted_helper)
- recover[:options] = @scope[:options]
- @scope[:options] = merge_options_scope(@scope[:options], options)
+ _route = @set.named_routes.routes[name.to_sym]
+ _routes = @set
+ app.routes.define_mounted_helper(name)
+ app.routes.singleton_class.class_eval do
+ define_method :mounted? do
+ true
+ end
- yield
- self
- ensure
- scope_options.each do |option|
- @scope[option] = recover[option] if recover.has_key?(option)
+ define_method :_generate_prefix do |options|
+ prefix_options = options.slice(*_route.segment_keys)
+ # we must actually delete prefix segment keys to avoid passing them to next url_for
+ _route.segment_keys.each { |k| options.delete(k) }
+ prefix = _routes.url_helpers.send("#{name}_path", prefix_options)
+ prefix = '' if prefix == '/'
+ prefix
+ end
+ end
end
-
- @scope[:options] = recover[:options]
- @scope[:blocks] = recover[:block]
end
- # Scopes routes to a specific controller
- #
- # Example:
- # controller "food" do
- # match "bacon", :action => "bacon"
- # end
- def controller(controller, options={})
- options[:controller] = controller
- scope(options) { yield }
+ module HttpHelpers
+ # Define a route that only recognizes HTTP GET.
+ # For supported arguments, see <tt>Base#match</tt>.
+ #
+ # Example:
+ #
+ # get 'bacon', :to => 'food#bacon'
+ def get(*args, &block)
+ map_method(:get, args, &block)
+ end
+
+ # Define a route that only recognizes HTTP POST.
+ # For supported arguments, see <tt>Base#match</tt>.
+ #
+ # Example:
+ #
+ # post 'bacon', :to => 'food#bacon'
+ def post(*args, &block)
+ map_method(:post, args, &block)
+ end
+
+ # Define a route that only recognizes HTTP PATCH.
+ # For supported arguments, see <tt>Base#match</tt>.
+ #
+ # Example:
+ #
+ # patch 'bacon', :to => 'food#bacon'
+ def patch(*args, &block)
+ map_method(:patch, args, &block)
+ end
+
+ # Define a route that only recognizes HTTP PUT.
+ # For supported arguments, see <tt>Base#match</tt>.
+ #
+ # Example:
+ #
+ # put 'bacon', :to => 'food#bacon'
+ def put(*args, &block)
+ map_method(:put, args, &block)
+ end
+
+ # Define a route that only recognizes HTTP DELETE.
+ # For supported arguments, see <tt>Base#match</tt>.
+ #
+ # Example:
+ #
+ # delete 'broccoli', :to => 'food#broccoli'
+ def delete(*args, &block)
+ map_method(:delete, args, &block)
+ end
+
+ private
+ def map_method(method, args, &block)
+ options = args.extract_options!
+ options[:via] = method
+ match(*args, options, &block)
+ self
+ end
end
- # Scopes routes to a specific namespace. For example:
+ # You may wish to organize groups of controllers under a namespace.
+ # Most commonly, you might group a number of administrative controllers
+ # under an +admin+ namespace. You would place these controllers under
+ # the <tt>app/controllers/admin</tt> directory, and you can group them
+ # together in your router:
#
- # namespace :admin do
- # resources :posts
+ # namespace "admin" do
+ # resources :posts, :comments
# end
#
- # This generates the following routes:
- #
- # admin_posts GET /admin/posts(.:format) admin/posts#index
- # admin_posts POST /admin/posts(.:format) admin/posts#create
- # new_admin_post GET /admin/posts/new(.:format) admin/posts#new
- # edit_admin_post GET /admin/posts/:id/edit(.:format) admin/posts#edit
- # admin_post GET /admin/posts/:id(.:format) admin/posts#show
- # admin_post PATCH/PUT /admin/posts/:id(.:format) admin/posts#update
- # admin_post DELETE /admin/posts/:id(.:format) admin/posts#destroy
- #
- # === Options
- #
- # The +:path+, +:as+, +:module+, +:shallow_path+ and +:shallow_prefix+
- # options all default to the name of the namespace.
- #
- # For options, see <tt>Base#match</tt>. For +:shallow_path+ option, see
- # <tt>Resources#resources</tt>.
+ # This will create a number of routes for each of the posts and comments
+ # controller. For <tt>Admin::PostsController</tt>, Rails will create:
#
- # === Examples
+ # GET /admin/posts
+ # GET /admin/posts/new
+ # POST /admin/posts
+ # GET /admin/posts/1
+ # GET /admin/posts/1/edit
+ # PATCH/PUT /admin/posts/1
+ # DELETE /admin/posts/1
#
- # # accessible through /sekret/posts rather than /admin/posts
- # namespace :admin, :path => "sekret" do
- # resources :posts
- # end
- #
- # # maps to <tt>Sekret::PostsController</tt> rather than <tt>Admin::PostsController</tt>
- # namespace :admin, :module => "sekret" do
- # resources :posts
- # end
+ # If you want to route /posts (without the prefix /admin) to
+ # <tt>Admin::PostsController</tt>, you could use
#
- # # generates +sekret_posts_path+ rather than +admin_posts_path+
- # namespace :admin, :as => "sekret" do
- # resources :posts
- # end
- def namespace(path, options = {})
- path = path.to_s
- options = { :path => path, :as => path, :module => path,
- :shallow_path => path, :shallow_prefix => path }.merge!(options)
- scope(options) { yield }
- end
-
- # === Parameter Restriction
- # Allows you to constrain the nested routes based on a set of rules.
- # For instance, in order to change the routes to allow for a dot character in the +id+ parameter:
- #
- # constraints(:id => /\d+\.\d+/) do
+ # scope :module => "admin" do
# resources :posts
# end
#
- # Now routes such as +/posts/1+ will no longer be valid, but +/posts/1.1+ will be.
- # The +id+ parameter must match the constraint passed in for this example.
+ # or, for a single case
#
- # You may use this to also restrict other parameters:
- #
- # resources :posts do
- # constraints(:post_id => /\d+\.\d+/) do
- # resources :comments
- # end
- # end
- #
- # === Restricting based on IP
+ # resources :posts, :module => "admin"
#
- # Routes can also be constrained to an IP or a certain range of IP addresses:
+ # If you want to route /admin/posts to +PostsController+
+ # (without the Admin:: module prefix), you could use
#
- # constraints(:ip => /192.168.\d+.\d+/) do
+ # scope "/admin" do
# resources :posts
# end
#
- # Any user connecting from the 192.168.* range will be able to see this resource,
- # where as any user connecting outside of this range will be told there is no such route.
- #
- # === Dynamic request matching
- #
- # Requests to routes can be constrained based on specific criteria:
- #
- # constraints(lambda { |req| req.env["HTTP_USER_AGENT"] =~ /iPhone/ }) do
- # resources :iphones
- # end
- #
- # You are able to move this logic out into a class if it is too complex for routes.
- # This class must have a +matches?+ method defined on it which either returns +true+
- # if the user should be given access to that route, or +false+ if the user should not.
- #
- # class Iphone
- # def self.matches?(request)
- # request.env["HTTP_USER_AGENT"] =~ /iPhone/
- # end
- # end
- #
- # An expected place for this code would be +lib/constraints+.
- #
- # This class is then used like this:
- #
- # constraints(Iphone) do
- # resources :iphones
- # end
- def constraints(constraints = {})
- scope(:constraints => constraints) { yield }
- end
-
- # Allows you to set default parameters for a route, such as this:
- # defaults :id => 'home' do
- # match 'scoped_pages/(:id)', :to => 'pages#show'
- # end
- # Using this, the +:id+ parameter here will default to 'home'.
- def defaults(defaults = {})
- scope(:defaults => defaults) { yield }
- end
-
- private
- def scope_options #:nodoc:
- @scope_options ||= private_methods.grep(/^merge_(.+)_scope$/) { $1.to_sym }
- end
-
- def merge_path_scope(parent, child) #:nodoc:
- Mapper.normalize_path("#{parent}/#{child}")
- end
-
- def merge_shallow_path_scope(parent, child) #:nodoc:
- Mapper.normalize_path("#{parent}/#{child}")
- end
-
- def merge_as_scope(parent, child) #:nodoc:
- parent ? "#{parent}_#{child}" : child
- end
-
- def merge_shallow_prefix_scope(parent, child) #:nodoc:
- parent ? "#{parent}_#{child}" : child
- end
-
- def merge_module_scope(parent, child) #:nodoc:
- parent ? "#{parent}/#{child}" : child
- end
-
- def merge_controller_scope(parent, child) #:nodoc:
- child
- end
-
- def merge_path_names_scope(parent, child) #:nodoc:
- merge_options_scope(parent, child)
- end
-
- def merge_constraints_scope(parent, child) #:nodoc:
- merge_options_scope(parent, child)
- end
-
- def merge_defaults_scope(parent, child) #:nodoc:
- merge_options_scope(parent, child)
- end
+ # or, for a single case
+ #
+ # resources :posts, :path => "/admin/posts"
+ #
+ # In each of these cases, the named routes remain the same as if you did
+ # not use scope. In the last case, the following paths map to
+ # +PostsController+:
+ #
+ # GET /admin/posts
+ # GET /admin/posts/new
+ # POST /admin/posts
+ # GET /admin/posts/1
+ # GET /admin/posts/1/edit
+ # PATCH/PUT /admin/posts/1
+ # DELETE /admin/posts/1
+ module Scoping
+ # Scopes a set of routes to the given default options.
+ #
+ # Take the following route definition as an example:
+ #
+ # scope :path => ":account_id", :as => "account" do
+ # resources :projects
+ # end
+ #
+ # This generates helpers such as +account_projects_path+, just like +resources+ does.
+ # The difference here being that the routes generated are like /:account_id/projects,
+ # rather than /accounts/:account_id/projects.
+ #
+ # === Options
+ #
+ # Takes same options as <tt>Base#match</tt> and <tt>Resources#resources</tt>.
+ #
+ # === Examples
+ #
+ # # route /posts (without the prefix /admin) to <tt>Admin::PostsController</tt>
+ # scope :module => "admin" do
+ # resources :posts
+ # end
+ #
+ # # prefix the posts resource's requests with '/admin'
+ # scope :path => "/admin" do
+ # resources :posts
+ # end
+ #
+ # # prefix the routing helper name: +sekret_posts_path+ instead of +posts_path+
+ # scope :as => "sekret" do
+ # resources :posts
+ # end
+ def scope(*args)
+ options = args.extract_options!
+ options = options.dup
+
+ options[:path] = args.first if args.first.is_a?(String)
+ recover = {}
+
+ options[:constraints] ||= {}
+ unless options[:constraints].is_a?(Hash)
+ block, options[:constraints] = options[:constraints], {}
+ end
- def merge_blocks_scope(parent, child) #:nodoc:
- merged = parent ? parent.dup : []
- merged << child if child
- merged
- end
+ scope_options.each do |option|
+ if value = options.delete(option)
+ recover[option] = @scope[option]
+ @scope[option] = send("merge_#{option}_scope", @scope[option], value)
+ end
+ end
- def merge_options_scope(parent, child) #:nodoc:
- (parent || {}).except(*override_keys(child)).merge(child)
- end
+ recover[:block] = @scope[:blocks]
+ @scope[:blocks] = merge_blocks_scope(@scope[:blocks], block)
- def merge_shallow_scope(parent, child) #:nodoc:
- child ? true : false
- end
+ recover[:options] = @scope[:options]
+ @scope[:options] = merge_options_scope(@scope[:options], options)
- def override_keys(child) #:nodoc:
- child.key?(:only) || child.key?(:except) ? [:only, :except] : []
- end
- end
-
- # Resource routing allows you to quickly declare all of the common routes
- # for a given resourceful controller. Instead of declaring separate routes
- # for your +index+, +show+, +new+, +edit+, +create+, +update+ and +destroy+
- # actions, a resourceful route declares them in a single line of code:
- #
- # resources :photos
- #
- # Sometimes, you have a resource that clients always look up without
- # referencing an ID. A common example, /profile always shows the profile of
- # the currently logged in user. In this case, you can use a singular resource
- # to map /profile (rather than /profile/:id) to the show action.
- #
- # resource :profile
- #
- # It's common to have resources that are logically children of other
- # resources:
- #
- # resources :magazines do
- # resources :ads
- # end
- #
- # You may wish to organize groups of controllers under a namespace. Most
- # commonly, you might group a number of administrative controllers under
- # an +admin+ namespace. You would place these controllers under the
- # <tt>app/controllers/admin</tt> directory, and you can group them together
- # in your router:
- #
- # namespace "admin" do
- # resources :posts, :comments
- # end
- #
- # By default the +:id+ parameter doesn't accept dots. If you need to
- # use dots as part of the +:id+ parameter add a constraint which
- # overrides this restriction, e.g:
- #
- # resources :articles, :id => /[^\/]+/
- #
- # This allows any character other than a slash as part of your +:id+.
- #
- module Resources
- # CANONICAL_ACTIONS holds all actions that does not need a prefix or
- # a path appended since they fit properly in their scope level.
- VALID_ON_OPTIONS = [:new, :collection, :member]
- RESOURCE_OPTIONS = [:as, :controller, :path, :only, :except]
- CANONICAL_ACTIONS = %w(index create new show update destroy)
-
- class Resource #:nodoc:
- attr_reader :controller, :path, :options
-
- def initialize(entities, options = {})
- @name = entities.to_s
- @path = (options[:path] || @name).to_s
- @controller = (options[:controller] || @name).to_s
- @as = options[:as]
- @options = options
- end
-
- def default_actions
- [:index, :create, :new, :show, :update, :destroy, :edit]
- end
-
- def actions
- if only = @options[:only]
- Array(only).map(&:to_sym)
- elsif except = @options[:except]
- default_actions - Array(except).map(&:to_sym)
- else
- default_actions
+ yield
+ self
+ ensure
+ scope_options.each do |option|
+ @scope[option] = recover[option] if recover.has_key?(option)
end
- end
- def name
- @as || @name
+ @scope[:options] = recover[:options]
+ @scope[:blocks] = recover[:block]
+ end
+
+ # Scopes routes to a specific controller
+ #
+ # Example:
+ # controller "food" do
+ # match "bacon", :action => "bacon"
+ # end
+ def controller(controller, options={})
+ options[:controller] = controller
+ scope(options) { yield }
+ end
+
+ # Scopes routes to a specific namespace. For example:
+ #
+ # namespace :admin do
+ # resources :posts
+ # end
+ #
+ # This generates the following routes:
+ #
+ # admin_posts GET /admin/posts(.:format) admin/posts#index
+ # admin_posts POST /admin/posts(.:format) admin/posts#create
+ # new_admin_post GET /admin/posts/new(.:format) admin/posts#new
+ # edit_admin_post GET /admin/posts/:id/edit(.:format) admin/posts#edit
+ # admin_post GET /admin/posts/:id(.:format) admin/posts#show
+ # admin_post PATCH/PUT /admin/posts/:id(.:format) admin/posts#update
+ # admin_post DELETE /admin/posts/:id(.:format) admin/posts#destroy
+ #
+ # === Options
+ #
+ # The +:path+, +:as+, +:module+, +:shallow_path+ and +:shallow_prefix+
+ # options all default to the name of the namespace.
+ #
+ # For options, see <tt>Base#match</tt>. For +:shallow_path+ option, see
+ # <tt>Resources#resources</tt>.
+ #
+ # === Examples
+ #
+ # # accessible through /sekret/posts rather than /admin/posts
+ # namespace :admin, :path => "sekret" do
+ # resources :posts
+ # end
+ #
+ # # maps to <tt>Sekret::PostsController</tt> rather than <tt>Admin::PostsController</tt>
+ # namespace :admin, :module => "sekret" do
+ # resources :posts
+ # end
+ #
+ # # generates +sekret_posts_path+ rather than +admin_posts_path+
+ # namespace :admin, :as => "sekret" do
+ # resources :posts
+ # end
+ def namespace(path, options = {})
+ path = path.to_s
+ options = { :path => path, :as => path, :module => path,
+ :shallow_path => path, :shallow_prefix => path }.merge!(options)
+ scope(options) { yield }
+ end
+
+ # === Parameter Restriction
+ # Allows you to constrain the nested routes based on a set of rules.
+ # For instance, in order to change the routes to allow for a dot character in the +id+ parameter:
+ #
+ # constraints(:id => /\d+\.\d+/) do
+ # resources :posts
+ # end
+ #
+ # Now routes such as +/posts/1+ will no longer be valid, but +/posts/1.1+ will be.
+ # The +id+ parameter must match the constraint passed in for this example.
+ #
+ # You may use this to also restrict other parameters:
+ #
+ # resources :posts do
+ # constraints(:post_id => /\d+\.\d+/) do
+ # resources :comments
+ # end
+ # end
+ #
+ # === Restricting based on IP
+ #
+ # Routes can also be constrained to an IP or a certain range of IP addresses:
+ #
+ # constraints(:ip => /192.168.\d+.\d+/) do
+ # resources :posts
+ # end
+ #
+ # Any user connecting from the 192.168.* range will be able to see this resource,
+ # where as any user connecting outside of this range will be told there is no such route.
+ #
+ # === Dynamic request matching
+ #
+ # Requests to routes can be constrained based on specific criteria:
+ #
+ # constraints(lambda { |req| req.env["HTTP_USER_AGENT"] =~ /iPhone/ }) do
+ # resources :iphones
+ # end
+ #
+ # You are able to move this logic out into a class if it is too complex for routes.
+ # This class must have a +matches?+ method defined on it which either returns +true+
+ # if the user should be given access to that route, or +false+ if the user should not.
+ #
+ # class Iphone
+ # def self.matches?(request)
+ # request.env["HTTP_USER_AGENT"] =~ /iPhone/
+ # end
+ # end
+ #
+ # An expected place for this code would be +lib/constraints+.
+ #
+ # This class is then used like this:
+ #
+ # constraints(Iphone) do
+ # resources :iphones
+ # end
+ def constraints(constraints = {})
+ scope(:constraints => constraints) { yield }
+ end
+
+ # Allows you to set default parameters for a route, such as this:
+ # defaults :id => 'home' do
+ # match 'scoped_pages/(:id)', :to => 'pages#show'
+ # end
+ # Using this, the +:id+ parameter here will default to 'home'.
+ def defaults(defaults = {})
+ scope(:defaults => defaults) { yield }
end
- def plural
- @plural ||= name.to_s
+ private
+ def scope_options #:nodoc:
+ @scope_options ||= private_methods.grep(/^merge_(.+)_scope$/) { $1.to_sym }
end
- def singular
- @singular ||= name.to_s.singularize
+ def merge_path_scope(parent, child) #:nodoc:
+ Mapper.normalize_path("#{parent}/#{child}")
end
- alias :member_name :singular
-
- # Checks for uncountable plurals, and appends "_index" if the plural
- # and singular form are the same.
- def collection_name
- singular == plural ? "#{plural}_index" : plural
+ def merge_shallow_path_scope(parent, child) #:nodoc:
+ Mapper.normalize_path("#{parent}/#{child}")
end
- def resource_scope
- { :controller => controller }
+ def merge_as_scope(parent, child) #:nodoc:
+ parent ? "#{parent}_#{child}" : child
end
- alias :collection_scope :path
-
- def member_scope
- "#{path}/:id"
+ def merge_shallow_prefix_scope(parent, child) #:nodoc:
+ parent ? "#{parent}_#{child}" : child
end
- def new_scope(new_path)
- "#{path}/#{new_path}"
+ def merge_module_scope(parent, child) #:nodoc:
+ parent ? "#{parent}/#{child}" : child
end
- def nested_scope
- "#{path}/:#{singular}_id"
+ def merge_controller_scope(parent, child) #:nodoc:
+ child
end
- end
-
- class SingletonResource < Resource #:nodoc:
- def initialize(entities, options)
- super
- @as = nil
- @controller = (options[:controller] || plural).to_s
- @as = options[:as]
+ def merge_path_names_scope(parent, child) #:nodoc:
+ merge_options_scope(parent, child)
end
- def default_actions
- [:show, :create, :update, :destroy, :new, :edit]
+ def merge_constraints_scope(parent, child) #:nodoc:
+ merge_options_scope(parent, child)
end
- def plural
- @plural ||= name.to_s.pluralize
+ def merge_defaults_scope(parent, child) #:nodoc:
+ merge_options_scope(parent, child)
end
- def singular
- @singular ||= name.to_s
+ def merge_blocks_scope(parent, child) #:nodoc:
+ merged = parent ? parent.dup : []
+ merged << child if child
+ merged
end
- alias :member_name :singular
- alias :collection_name :singular
-
- alias :member_scope :path
- alias :nested_scope :path
- end
-
- def resources_path_names(options)
- @scope[:path_names].merge!(options)
- end
-
- # Sometimes, you have a resource that clients always look up without
- # referencing an ID. A common example, /profile always shows the
- # profile of the currently logged in user. In this case, you can use
- # a singular resource to map /profile (rather than /profile/:id) to
- # the show action:
- #
- # resource :geocoder
- #
- # creates six different routes in your application, all mapping to
- # the +GeoCoders+ controller (note that the controller is named after
- # the plural):
- #
- # GET /geocoder/new
- # POST /geocoder
- # GET /geocoder
- # GET /geocoder/edit
- # PATCH/PUT /geocoder
- # DELETE /geocoder
- #
- # === Options
- # Takes same options as +resources+.
- def resource(*resources, &block)
- options = resources.extract_options!
-
- if apply_common_behavior_for(:resource, resources, options, &block)
- return self
+ def merge_options_scope(parent, child) #:nodoc:
+ (parent || {}).except(*override_keys(child)).merge(child)
end
- resource_scope(:resource, SingletonResource.new(resources.pop, options)) do
- yield if block_given?
-
- collection do
- post :create
- end if parent_resource.actions.include?(:create)
-
- new do
- get :new
- end if parent_resource.actions.include?(:new)
-
- member do
- get :edit if parent_resource.actions.include?(:edit)
- get :show if parent_resource.actions.include?(:show)
- if parent_resource.actions.include?(:update)
- patch :update
- put :update
- end
- delete :destroy if parent_resource.actions.include?(:destroy)
- end
+ def merge_shallow_scope(parent, child) #:nodoc:
+ child ? true : false
end
- self
+ def override_keys(child) #:nodoc:
+ child.key?(:only) || child.key?(:except) ? [:only, :except] : []
+ end
end
- # In Rails, a resourceful route provides a mapping between HTTP verbs
- # and URLs and controller actions. By convention, each action also maps
- # to particular CRUD operations in a database. A single entry in the
- # routing file, such as
+ # Resource routing allows you to quickly declare all of the common routes
+ # for a given resourceful controller. Instead of declaring separate routes
+ # for your +index+, +show+, +new+, +edit+, +create+, +update+ and +destroy+
+ # actions, a resourceful route declares them in a single line of code:
#
- # resources :photos
+ # resources :photos
#
- # creates seven different routes in your application, all mapping to
- # the +Photos+ controller:
+ # Sometimes, you have a resource that clients always look up without
+ # referencing an ID. A common example, /profile always shows the profile of
+ # the currently logged in user. In this case, you can use a singular resource
+ # to map /profile (rather than /profile/:id) to the show action.
#
- # GET /photos
- # GET /photos/new
- # POST /photos
- # GET /photos/:id
- # GET /photos/:id/edit
- # PATCH/PUT /photos/:id
- # DELETE /photos/:id
+ # resource :profile
#
- # Resources can also be nested infinitely by using this block syntax:
+ # It's common to have resources that are logically children of other
+ # resources:
#
- # resources :photos do
- # resources :comments
+ # resources :magazines do
+ # resources :ads
# end
#
- # This generates the following comments routes:
- #
- # GET /photos/:photo_id/comments
- # GET /photos/:photo_id/comments/new
- # POST /photos/:photo_id/comments
- # GET /photos/:photo_id/comments/:id
- # GET /photos/:photo_id/comments/:id/edit
- # PATCH/PUT /photos/:photo_id/comments/:id
- # DELETE /photos/:photo_id/comments/:id
+ # You may wish to organize groups of controllers under a namespace. Most
+ # commonly, you might group a number of administrative controllers under
+ # an +admin+ namespace. You would place these controllers under the
+ # <tt>app/controllers/admin</tt> directory, and you can group them together
+ # in your router:
#
- # === Options
- # Takes same options as <tt>Base#match</tt> as well as:
- #
- # [:path_names]
- # Allows you to change the segment component of the +edit+ and +new+ actions.
- # Actions not specified are not changed.
- #
- # resources :posts, :path_names => { :new => "brand_new" }
- #
- # The above example will now change /posts/new to /posts/brand_new
- #
- # [:path]
- # Allows you to change the path prefix for the resource.
- #
- # resources :posts, :path => 'postings'
- #
- # The resource and all segments will now route to /postings instead of /posts
- #
- # [:only]
- # Only generate routes for the given actions.
- #
- # resources :cows, :only => :show
- # resources :cows, :only => [:show, :index]
- #
- # [:except]
- # Generate all routes except for the given actions.
- #
- # resources :cows, :except => :show
- # resources :cows, :except => [:show, :index]
- #
- # [:shallow]
- # Generates shallow routes for nested resource(s). When placed on a parent resource,
- # generates shallow routes for all nested resources.
- #
- # resources :posts, :shallow => true do
- # resources :comments
- # end
- #
- # Is the same as:
- #
- # resources :posts do
- # resources :comments, :except => [:show, :edit, :update, :destroy]
- # end
- # resources :comments, :only => [:show, :edit, :update, :destroy]
- #
- # This allows URLs for resources that otherwise would be deeply nested such
- # as a comment on a blog post like <tt>/posts/a-long-permalink/comments/1234</tt>
- # to be shortened to just <tt>/comments/1234</tt>.
- #
- # [:shallow_path]
- # Prefixes nested shallow routes with the specified path.
- #
- # scope :shallow_path => "sekret" do
- # resources :posts do
- # resources :comments, :shallow => true
- # end
- # end
+ # namespace "admin" do
+ # resources :posts, :comments
+ # end
#
- # The +comments+ resource here will have the following routes generated for it:
+ # By default the +:id+ parameter doesn't accept dots. If you need to
+ # use dots as part of the +:id+ parameter add a constraint which
+ # overrides this restriction, e.g:
#
- # post_comments GET /posts/:post_id/comments(.:format)
- # post_comments POST /posts/:post_id/comments(.:format)
- # new_post_comment GET /posts/:post_id/comments/new(.:format)
- # edit_comment GET /sekret/comments/:id/edit(.:format)
- # comment GET /sekret/comments/:id(.:format)
- # comment PATCH/PUT /sekret/comments/:id(.:format)
- # comment DELETE /sekret/comments/:id(.:format)
+ # resources :articles, :id => /[^\/]+/
#
- # === Examples
+ # This allows any character other than a slash as part of your +:id+.
#
- # # routes call <tt>Admin::PostsController</tt>
- # resources :posts, :module => "admin"
- #
- # # resource actions are at /admin/posts.
- # resources :posts, :path => "admin/posts"
- def resources(*resources, &block)
- options = resources.extract_options!
+ module Resources
+ # CANONICAL_ACTIONS holds all actions that does not need a prefix or
+ # a path appended since they fit properly in their scope level.
+ VALID_ON_OPTIONS = [:new, :collection, :member]
+ RESOURCE_OPTIONS = [:as, :controller, :path, :only, :except]
+ CANONICAL_ACTIONS = %w(index create new show update destroy)
+
+ class Resource #:nodoc:
+ attr_reader :controller, :path, :options
+
+ def initialize(entities, options = {})
+ @name = entities.to_s
+ @path = (options[:path] || @name).to_s
+ @controller = (options[:controller] || @name).to_s
+ @as = options[:as]
+ @options = options
+ end
+
+ def default_actions
+ [:index, :create, :new, :show, :update, :destroy, :edit]
+ end
+
+ def actions
+ if only = @options[:only]
+ Array(only).map(&:to_sym)
+ elsif except = @options[:except]
+ default_actions - Array(except).map(&:to_sym)
+ else
+ default_actions
+ end
+ end
+
+ def name
+ @as || @name
+ end
+
+ def plural
+ @plural ||= name.to_s
+ end
+
+ def singular
+ @singular ||= name.to_s.singularize
+ end
+
+ alias :member_name :singular
+
+ # Checks for uncountable plurals, and appends "_index" if the plural
+ # and singular form are the same.
+ def collection_name
+ singular == plural ? "#{plural}_index" : plural
+ end
+
+ def resource_scope
+ { :controller => controller }
+ end
+
+ alias :collection_scope :path
+
+ def member_scope
+ "#{path}/:id"
+ end
+
+ def new_scope(new_path)
+ "#{path}/#{new_path}"
+ end
+
+ def nested_scope
+ "#{path}/:#{singular}_id"
+ end
- if apply_common_behavior_for(:resources, resources, options, &block)
- return self
end
- resource_scope(:resources, Resource.new(resources.pop, options)) do
- yield if block_given?
+ class SingletonResource < Resource #:nodoc:
+ def initialize(entities, options)
+ super
+ @as = nil
+ @controller = (options[:controller] || plural).to_s
+ @as = options[:as]
+ end
- collection do
- get :index if parent_resource.actions.include?(:index)
- post :create if parent_resource.actions.include?(:create)
+ def default_actions
+ [:show, :create, :update, :destroy, :new, :edit]
end
- new do
- get :new
- end if parent_resource.actions.include?(:new)
+ def plural
+ @plural ||= name.to_s.pluralize
+ end
+
+ def singular
+ @singular ||= name.to_s
+ end
+
+ alias :member_name :singular
+ alias :collection_name :singular
+
+ alias :member_scope :path
+ alias :nested_scope :path
+ end
+
+ def resources_path_names(options)
+ @scope[:path_names].merge!(options)
+ end
+
+ # Sometimes, you have a resource that clients always look up without
+ # referencing an ID. A common example, /profile always shows the
+ # profile of the currently logged in user. In this case, you can use
+ # a singular resource to map /profile (rather than /profile/:id) to
+ # the show action:
+ #
+ # resource :geocoder
+ #
+ # creates six different routes in your application, all mapping to
+ # the +GeoCoders+ controller (note that the controller is named after
+ # the plural):
+ #
+ # GET /geocoder/new
+ # POST /geocoder
+ # GET /geocoder
+ # GET /geocoder/edit
+ # PATCH/PUT /geocoder
+ # DELETE /geocoder
+ #
+ # === Options
+ # Takes same options as +resources+.
+ def resource(*resources, &block)
+ options = resources.extract_options!
+
+ if apply_common_behavior_for(:resource, resources, options, &block)
+ return self
+ end
- member do
- get :edit if parent_resource.actions.include?(:edit)
- get :show if parent_resource.actions.include?(:show)
- if parent_resource.actions.include?(:update)
- patch :update
- put :update
+ resource_scope(:resource, SingletonResource.new(resources.pop, options)) do
+ yield if block_given?
+
+ collection do
+ post :create
+ end if parent_resource.actions.include?(:create)
+
+ new do
+ get :new
+ end if parent_resource.actions.include?(:new)
+
+ member do
+ get :edit if parent_resource.actions.include?(:edit)
+ get :show if parent_resource.actions.include?(:show)
+ if parent_resource.actions.include?(:update)
+ patch :update
+ put :update
+ end
+ delete :destroy if parent_resource.actions.include?(:destroy)
end
- delete :destroy if parent_resource.actions.include?(:destroy)
end
- end
- self
- end
+ self
+ end
+
+ # In Rails, a resourceful route provides a mapping between HTTP verbs
+ # and URLs and controller actions. By convention, each action also maps
+ # to particular CRUD operations in a database. A single entry in the
+ # routing file, such as
+ #
+ # resources :photos
+ #
+ # creates seven different routes in your application, all mapping to
+ # the +Photos+ controller:
+ #
+ # GET /photos
+ # GET /photos/new
+ # POST /photos
+ # GET /photos/:id
+ # GET /photos/:id/edit
+ # PATCH/PUT /photos/:id
+ # DELETE /photos/:id
+ #
+ # Resources can also be nested infinitely by using this block syntax:
+ #
+ # resources :photos do
+ # resources :comments
+ # end
+ #
+ # This generates the following comments routes:
+ #
+ # GET /photos/:photo_id/comments
+ # GET /photos/:photo_id/comments/new
+ # POST /photos/:photo_id/comments
+ # GET /photos/:photo_id/comments/:id
+ # GET /photos/:photo_id/comments/:id/edit
+ # PATCH/PUT /photos/:photo_id/comments/:id
+ # DELETE /photos/:photo_id/comments/:id
+ #
+ # === Options
+ # Takes same options as <tt>Base#match</tt> as well as:
+ #
+ # [:path_names]
+ # Allows you to change the segment component of the +edit+ and +new+ actions.
+ # Actions not specified are not changed.
+ #
+ # resources :posts, :path_names => { :new => "brand_new" }
+ #
+ # The above example will now change /posts/new to /posts/brand_new
+ #
+ # [:path]
+ # Allows you to change the path prefix for the resource.
+ #
+ # resources :posts, :path => 'postings'
+ #
+ # The resource and all segments will now route to /postings instead of /posts
+ #
+ # [:only]
+ # Only generate routes for the given actions.
+ #
+ # resources :cows, :only => :show
+ # resources :cows, :only => [:show, :index]
+ #
+ # [:except]
+ # Generate all routes except for the given actions.
+ #
+ # resources :cows, :except => :show
+ # resources :cows, :except => [:show, :index]
+ #
+ # [:shallow]
+ # Generates shallow routes for nested resource(s). When placed on a parent resource,
+ # generates shallow routes for all nested resources.
+ #
+ # resources :posts, :shallow => true do
+ # resources :comments
+ # end
+ #
+ # Is the same as:
+ #
+ # resources :posts do
+ # resources :comments, :except => [:show, :edit, :update, :destroy]
+ # end