Skip to content
Browse files

Merge branch 'master' of github.com:rails/rails

  • Loading branch information...
2 parents d5d7171 + c1d7327 commit 91963e9e33eb5a28297323f1346aeb8b643e9d65 @wycats wycats committed Apr 26, 2010
Showing with 814 additions and 818 deletions.
  1. +0 −2 actionmailer/test/old_base/mail_service_test.rb
  2. +2 −0 actionpack/CHANGELOG
  3. +0 −1 actionpack/lib/abstract_controller.rb
  4. +0 −21 actionpack/lib/abstract_controller/assigns.rb
  5. +4 −13 actionpack/lib/abstract_controller/base.rb
  6. +0 −1 actionpack/lib/abstract_controller/helpers.rb
  7. +1 −1 actionpack/lib/abstract_controller/logger.rb
  8. +4 −1 actionpack/lib/action_controller/base.rb
  9. +2 −4 actionpack/lib/action_controller/caching.rb
  10. +4 −4 actionpack/lib/action_controller/caching/pages.rb
  11. +9 −39 actionpack/lib/action_controller/deprecated/base.rb
  12. +2 −2 actionpack/lib/action_controller/metal/compatibility.rb
  13. +2 −2 actionpack/lib/action_controller/metal/helpers.rb
  14. +2 −2 actionpack/lib/action_controller/metal/renderers.rb
  15. +44 −74 actionpack/lib/action_controller/metal/request_forgery_protection.rb
  16. +26 −39 actionpack/lib/action_controller/railtie.rb
  17. +134 −126 actionpack/lib/action_controller/test_case.rb
  18. +1 −1 actionpack/lib/action_dispatch/routing/url_for.rb
  19. +1 −1 actionpack/lib/action_view/helpers/active_model_helper.rb
  20. +1 −1 actionpack/lib/action_view/helpers/url_helper.rb
  21. +1 −1 actionpack/lib/action_view/test_case.rb
  22. +7 −1 actionpack/test/abstract_unit.rb
  23. +1 −1 actionpack/test/controller/assert_select_test.rb
  24. +2 −1 actionpack/test/controller/layout_test.rb
  25. +18 −0 actionpack/test/controller/render_json_test.rb
  26. +17 −7 actionpack/test/controller/render_xml_test.rb
  27. +2 −2 actionpack/test/controller/send_file_test.rb
  28. +15 −1 actionpack/test/controller/url_for_test.rb
  29. +8 −2 actionpack/test/dispatch/routing_test.rb
  30. +4 −4 actionpack/test/template/active_model_helper_test.rb
  31. +0 −3 actionpack/test/template/form_tag_helper_test.rb
  32. +1 −0 actionpack/test/template/text_helper_test.rb
  33. +1 −0 activemodel/lib/active_model/locale/en.yml
  34. +17 −18 activemodel/lib/active_model/serializers/xml.rb
  35. +18 −11 activemodel/lib/active_model/validations/numericality.rb
  36. +9 −9 activemodel/test/cases/validations/i18n_validation_test.rb
  37. +2 −0 activerecord/CHANGELOG
  38. +1 −2 activerecord/lib/active_record/base.rb
  39. +3 −7 activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
  40. +23 −134 activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
  41. +9 −7 activerecord/lib/active_record/fixtures.rb
  42. +2 −2 activerecord/lib/active_record/railties/databases.rake
  43. +0 −11 activerecord/lib/active_record/serializers/xml_serializer.rb
  44. +2 −2 activerecord/test/cases/finder_test.rb
  45. +9 −1 activerecord/test/cases/fixtures_test.rb
  46. +2 −0 activerecord/test/fixtures/admin/accounts.yml
  47. +7 −0 activerecord/test/fixtures/admin/users.yml
  48. +5 −0 activerecord/test/models/admin.rb
  49. +3 −0 activerecord/test/models/admin/account.rb
  50. +3 −0 activerecord/test/models/admin/user.rb
  51. +9 −0 activerecord/test/schema/schema.rb
  52. +5 −0 activeresource/CHANGELOG
  53. +3 −72 activeresource/lib/active_resource/base.rb
  54. +1 −2 activeresource/test/cases/base_test.rb
  55. +7 −0 activesupport/CHANGELOG
  56. +19 −18 activesupport/lib/active_support/configurable.rb
  57. +2 −1 activesupport/lib/active_support/core_ext/kernel/reporting.rb
  58. +2 −1 activesupport/lib/active_support/core_ext/uri.rb
  59. +5 −1 activesupport/lib/active_support/hash_with_indifferent_access.rb
  60. +19 −5 activesupport/lib/active_support/json/encoding.rb
  61. +2 −2 activesupport/lib/active_support/multibyte/chars.rb
  62. +15 −5 activesupport/lib/active_support/notifications/fanout.rb
  63. +2 −1 activesupport/lib/active_support/testing/isolation.rb
  64. +42 −0 activesupport/test/configurable_test.rb
  65. +39 −2 activesupport/test/core_ext/hash_ext_test.rb
  66. +1 −1 activesupport/test/core_ext/uri_ext_test.rb
  67. +19 −2 activesupport/test/json/encoding_test.rb
  68. +1 −1 activesupport/test/multibyte_chars_test.rb
  69. +22 −0 activesupport/test/notifications_test.rb
  70. +1 −0 railties/Rakefile
  71. +2 −2 railties/lib/rails/application.rb
  72. +2 −2 railties/lib/rails/application/configuration.rb
  73. +2 −1 railties/lib/rails/commands/dbconsole.rb
  74. +2 −1 railties/lib/rails/commands/runner.rb
  75. +2 −1 railties/lib/rails/engine.rb
  76. +3 −2 railties/lib/rails/generators/actions.rb
  77. +1 −1 railties/lib/rails/generators/erb/scaffold/templates/show.html.erb
  78. +2 −1 railties/lib/rails/generators/rails/app/app_generator.rb
  79. +0 −3 railties/lib/rails/generators/rails/app/templates/Rakefile
  80. +2 −6 railties/lib/rails/generators/rails/stylesheets/templates/scaffold.css
  81. +2 −0 railties/lib/rails/tasks/documentation.rake
  82. +3 −1 railties/lib/rails/test_help.rb
  83. +3 −1 railties/lib/rails/test_unit/testing.rake
  84. +5 −66 railties/test/application/configuration_test.rb
  85. +0 −54 railties/test/application/middleware_stack_defaults_test.rb
  86. +93 −0 railties/test/application/middleware_test.rb
  87. +23 −0 railties/test/application/rake_test.rb
  88. +19 −0 railties/test/isolation/abstract_unit.rb
  89. +1 −0 tools/profile
View
2 actionmailer/test/old_base/mail_service_test.rb
@@ -866,7 +866,6 @@ def test_multipart_with_utf8_subject
regex = Regexp.escape('Subject: Foo =?UTF-8?Q?=C3=A1=C3=AB=C3=B4=?= =?UTF-8?Q?_=C3=AE=C3=BC=?=')
assert_match(/#{regex}/, mail.encoded)
string = "Foo áëô îü"
- string.force_encoding('UTF-8') if string.respond_to?(:force_encoding)
assert_match(string, mail.subject)
end
@@ -875,7 +874,6 @@ def test_implicitly_multipart_with_utf8
regex = Regexp.escape('Subject: Foo =?UTF-8?Q?=C3=A1=C3=AB=C3=B4=?= =?UTF-8?Q?_=C3=AE=C3=BC=?=')
assert_match(/#{regex}/, mail.encoded)
string = "Foo áëô îü"
- string.force_encoding('UTF-8') if string.respond_to?(:force_encoding)
assert_match(string, mail.subject)
end
View
2 actionpack/CHANGELOG
@@ -1,5 +1,7 @@
*Rails 3.0.0 [beta 4/release candidate] (unreleased)*
+* Renamed the field error CSS class from fieldWithErrors to field_with_errors for consistency. [Jeremy Kemper]
+
* Add support for shorthand routes like /projects/status(.:format) #4423 [Diego Carrion]
* Changed translate helper so that it doesn’t mark every translation as safe HTML. Only keys with a "_html" suffix and keys named "html" are considered to be safe HTML. All other translations are left untouched. [Craig Davey]
View
1 actionpack/lib/abstract_controller.rb
@@ -12,7 +12,6 @@
module AbstractController
extend ActiveSupport::Autoload
- autoload :Assigns
autoload :Base
autoload :Callbacks
autoload :Collector
View
21 actionpack/lib/abstract_controller/assigns.rb
@@ -1,21 +0,0 @@
-module AbstractController
- module Assigns
- # This method should return a hash with assigns.
- # You can overwrite this configuration per controller.
- # :api: public
- def view_assigns
- hash = {}
- variables = instance_variable_names
- variables -= protected_instance_variables if respond_to?(:protected_instance_variables)
- variables.each { |name| hash[name] = instance_variable_get(name) }
- hash
- end
-
- # This method assigns the hash specified in _assigns_hash to the given object.
- # :api: private
- # TODO Ideally, this should be done on AV::Base.new initialization.
- def _evaluate_assigns(object)
- view_assigns.each { |k,v| object.instance_variable_set(k, v) }
- end
- end
-end
View
17 actionpack/lib/abstract_controller/base.rb
@@ -1,4 +1,4 @@
-require 'active_support/ordered_options'
+require 'active_support/configurable'
module AbstractController
class Error < StandardError; end
@@ -8,6 +8,8 @@ class Base
attr_internal :response_body
attr_internal :action_name
+ include ActiveSupport::Configurable
+
class << self
attr_reader :abstract
alias_method :abstract?, :abstract
@@ -29,14 +31,6 @@ def descendants
@descendants ||= []
end
- def config
- @config ||= ActiveSupport::InheritableOptions.new(superclass < Base ? superclass.config : {})
- end
-
- def configure
- yield config
- end
-
# A list of all internal methods for a controller. This finds the first
# abstract superclass of a controller, and gets a list of all public
# instance methods on that abstract class. Public instance methods of
@@ -99,10 +93,6 @@ def controller_path
abstract!
- def config
- @config ||= ActiveSupport::InheritableOptions.new(self.class.config)
- end
-
# Calls the action going through the entire action dispatch stack.
#
# The actual method that is called is determined by calling
@@ -133,6 +123,7 @@ def action_methods
end
private
+
# Returns true if the name can be considered an action. This can
# be overridden in subclasses to modify the semantics of what
# can be considered an action.
View
1 actionpack/lib/abstract_controller/helpers.rb
@@ -8,7 +8,6 @@ module Helpers
included do
class_attribute :_helpers
- delegate :_helpers, :to => :'self.class'
self._helpers = Module.new
end
View
2 actionpack/lib/abstract_controller/logger.rb
@@ -6,7 +6,7 @@ module Logger
extend ActiveSupport::Concern
included do
- cattr_accessor :logger
+ config_accessor :logger
extend ActiveSupport::Benchmarkable
end
end
View
5 actionpack/lib/action_controller/base.rb
@@ -65,8 +65,11 @@ def self.subclasses
@subclasses ||= []
end
+ # TODO Move this to the appropriate module
+ config_accessor :assets_dir, :asset_path, :javascripts_dir, :stylesheets_dir
+
ActiveSupport.run_load_hooks(:action_controller, self)
end
end
-require "action_controller/deprecated/base"
+require "action_controller/deprecated/base"
View
6 actionpack/lib/action_controller/caching.rb
@@ -63,12 +63,10 @@ def cache_configured?
included do
extend ConfigMethods
- delegate :perform_caching, :perform_caching=, :to => :config
- singleton_class.delegate :perform_caching, :perform_caching=, :to => :config
- self.perform_caching = true
+ config_accessor :perform_caching
+ self.perform_caching = true if perform_caching.nil?
end
-
def caching_allowed?
request.get? && response.status == 200
end
View
8 actionpack/lib/action_controller/caching/pages.rb
@@ -44,17 +44,17 @@ module Pages
# For Rails, this directory has already been set to Rails.public_path (which is usually set to <tt>Rails.root + "/public"</tt>). Changing
# this setting can be useful to avoid naming conflicts with files in <tt>public/</tt>, but doing so will likely require configuring your
# web server to look in the new location for cached files.
- singleton_class.delegate :page_cache_directory, :page_cache_directory=, :to => :config
- self.page_cache_directory = ''
+ config_accessor :page_cache_directory
+ self.page_cache_directory ||= ''
##
# :singleton-method:
# Most Rails requests do not have an extension, such as <tt>/weblog/new</tt>. In these cases, the page caching mechanism will add one in
# order to make it easy for the cached files to be picked up properly by the web server. By default, this cache extension is <tt>.html</tt>.
# If you want something else, like <tt>.php</tt> or <tt>.shtml</tt>, just set Base.page_cache_extension. In cases where a request already has an
# extension, such as <tt>.xml</tt> or <tt>.rss</tt>, page caching will not add an extension. This allows it to work well with RESTful apps.
- singleton_class.delegate :page_cache_extension, :page_cache_extension=, :to => :config
- self.page_cache_extension = '.html'
+ config_accessor :page_cache_extension
+ self.page_cache_extension ||= '.html'
end
module ClassMethods
View
48 actionpack/lib/action_controller/deprecated/base.rb
@@ -1,33 +1,16 @@
module ActionController
class Base
- class << self
- def deprecated_config_accessor(option, message = nil)
- deprecated_config_reader(option, message)
- deprecated_config_writer(option, message)
+ # Deprecated methods. Wrap them in a module so they can be overwritten by plugins
+ # (like the verify method.)
+ module DeprecatedBehavior #:nodoc:
+ def relative_url_root
+ ActiveSupport::Deprecation.warn "ActionController::Base.relative_url_root is ineffective. " <<
+ "Please stop using it.", caller
end
- def deprecated_config_reader(option, message = nil)
- message ||= "Reading #{option} directly from ActionController::Base is deprecated. " \
- "Please read it from config.#{option}"
-
- self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
- def #{option}
- ActiveSupport::Deprecation.warn #{message.inspect}, caller
- config.#{option}
- end
- RUBY
- end
-
- def deprecated_config_writer(option, message = nil)
- message ||= "Setting #{option} directly on ActionController::Base is deprecated. " \
- "Please set it on config.action_controller.#{option}"
-
- self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
- def #{option}=(val)
- ActiveSupport::Deprecation.warn #{message.inspect}, caller
- config.#{option} = val
- end
- RUBY
+ def relative_url_root=
+ ActiveSupport::Deprecation.warn "ActionController::Base.relative_url_root= is ineffective. " <<
+ "Please stop using it.", caller
end
def consider_all_requests_local
@@ -125,9 +108,7 @@ def use_accept_header
def use_accept_header=(val)
use_accept_header
end
- end
- module DeprecatedBehavior
# This method has been moved to ActionDispatch::Request.filter_parameters
def filter_parameter_logging(*args, &block)
ActiveSupport::Deprecation.warn("Setting filter_parameter_logging in ActionController is deprecated and has no longer effect, please set 'config.filter_parameters' in config/application.rb instead", caller)
@@ -146,17 +127,6 @@ def verify(*args)
extend DeprecatedBehavior
- deprecated_config_writer :session_options
- deprecated_config_writer :session_store
-
- deprecated_config_accessor :assets_dir
- deprecated_config_accessor :asset_path
- deprecated_config_accessor :helpers_path
- deprecated_config_accessor :javascripts_dir
- deprecated_config_accessor :page_cache_directory
- deprecated_config_accessor :relative_url_root, "relative_url_root is ineffective. Please stop using it"
- deprecated_config_accessor :stylesheets_dir
-
delegate :consider_all_requests_local, :consider_all_requests_local=,
:allow_concurrency, :allow_concurrency=, :to => :"self.class"
end
View
4 actionpack/lib/action_controller/metal/compatibility.rb
@@ -21,8 +21,8 @@ class << self
delegate :default_charset=, :to => "ActionDispatch::Response"
end
- # cattr_reader :protected_instance_variables
- cattr_accessor :protected_instance_variables
+ # TODO: Update protected instance variables list
+ config_accessor :protected_instance_variables
self.protected_instance_variables = %w(@assigns @performed_redirect @performed_render
@variables_added @request_origin @url
@parent_controller @action_name
View
4 actionpack/lib/action_controller/metal/helpers.rb
@@ -52,8 +52,8 @@ module Helpers
include AbstractController::Helpers
included do
- class_attribute :helpers_path
- self.helpers_path = []
+ config_accessor :helpers_path
+ self.helpers_path ||= []
end
module ClassMethods
View
4 actionpack/lib/action_controller/metal/renderers.rb
@@ -79,12 +79,12 @@ def self._write_render_options
add :js do |js, options|
self.content_type ||= Mime::JS
- self.response_body = js.respond_to?(:to_js) ? js.to_js : js
+ self.response_body = js.respond_to?(:to_js) ? js.to_js(options) : js
end
add :xml do |xml, options|
self.content_type ||= Mime::XML
- self.response_body = xml.respond_to?(:to_xml) ? xml.to_xml : xml
+ self.response_body = xml.respond_to?(:to_xml) ? xml.to_xml(options) : xml
end
add :update do |proc, options|
View
118 actionpack/lib/action_controller/metal/request_forgery_protection.rb
@@ -4,6 +4,45 @@ module ActionController #:nodoc:
class InvalidAuthenticityToken < ActionControllerError #:nodoc:
end
+ # Protecting controller actions from CSRF attacks by ensuring that all forms are coming from the current
+ # web application, not a forged link from another site, is done by embedding a token based on a random
+ # string stored in the session (which an attacker wouldn't know) in all forms and Ajax requests generated
+ # by Rails and then verifying the authenticity of that token in the controller. Only HTML/JavaScript
+ # requests are checked, so this will not protect your XML API (presumably you'll have a different
+ # authentication scheme there anyway). Also, GET requests are not protected as these should be
+ # idempotent anyway.
+ #
+ # This is turned on with the <tt>protect_from_forgery</tt> method, which will check the token and raise an
+ # ActionController::InvalidAuthenticityToken if it doesn't match what was expected. You can customize the
+ # error message in production by editing public/422.html. A call to this method in ApplicationController is
+ # generated by default in post-Rails 2.0 applications.
+ #
+ # The token parameter is named <tt>authenticity_token</tt> by default. If you are generating an HTML form
+ # manually (without the use of Rails' <tt>form_for</tt>, <tt>form_tag</tt> or other helpers), you have to
+ # include a hidden field named like that and set its value to what is returned by
+ # <tt>form_authenticity_token</tt>.
+ #
+ # Request forgery protection is disabled by default in test environment. If you are upgrading from Rails
+ # 1.x, add this to config/environments/test.rb:
+ #
+ # # Disable request forgery protection in test environment
+ # config.action_controller.allow_forgery_protection = false
+ #
+ # == Learn more about CSRF (Cross-Site Request Forgery) attacks
+ #
+ # Here are some resources:
+ # * http://isc.sans.org/diary.html?storyid=1750
+ # * http://en.wikipedia.org/wiki/Cross-site_request_forgery
+ #
+ # Keep in mind, this is NOT a silver-bullet, plug 'n' play, warm security blanket for your rails application.
+ # There are a few guidelines you should follow:
+ #
+ # * Keep your GET requests safe and idempotent. More reading material:
+ # * http://www.xml.com/pub/a/2002/04/24/deviant.html
+ # * http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1
+ # * Make sure the session cookies that Rails creates are non-persistent. Check in Firefox and look
+ # for "Expires: at end of session"
+ #
module RequestForgeryProtection
extend ActiveSupport::Concern
@@ -12,54 +51,17 @@ module RequestForgeryProtection
included do
# Sets the token parameter name for RequestForgery. Calling +protect_from_forgery+
# sets it to <tt>:authenticity_token</tt> by default.
- config.request_forgery_protection_token ||= :authenticity_token
+ config_accessor :request_forgery_protection_token
+ self.request_forgery_protection_token ||= :authenticity_token
# Controls whether request forgergy protection is turned on or not. Turned off by default only in test mode.
- config.allow_forgery_protection ||= true
+ config_accessor :allow_forgery_protection
+ self.allow_forgery_protection = true if allow_forgery_protection.nil?
helper_method :form_authenticity_token
helper_method :protect_against_forgery?
end
- # Protecting controller actions from CSRF attacks by ensuring that all forms are coming from the current
- # web application, not a forged link from another site, is done by embedding a token based on a random
- # string stored in the session (which an attacker wouldn't know) in all forms and Ajax requests generated
- # by Rails and then verifying the authenticity of that token in the controller. Only HTML/JavaScript
- # requests are checked, so this will not protect your XML API (presumably you'll have a different
- # authentication scheme there anyway). Also, GET requests are not protected as these should be
- # idempotent anyway.
- #
- # This is turned on with the <tt>protect_from_forgery</tt> method, which will check the token and raise an
- # ActionController::InvalidAuthenticityToken if it doesn't match what was expected. You can customize the
- # error message in production by editing public/422.html. A call to this method in ApplicationController is
- # generated by default in post-Rails 2.0 applications.
- #
- # The token parameter is named <tt>authenticity_token</tt> by default. If you are generating an HTML form
- # manually (without the use of Rails' <tt>form_for</tt>, <tt>form_tag</tt> or other helpers), you have to
- # include a hidden field named like that and set its value to what is returned by
- # <tt>form_authenticity_token</tt>.
- #
- # Request forgery protection is disabled by default in test environment. If you are upgrading from Rails
- # 1.x, add this to config/environments/test.rb:
- #
- # # Disable request forgery protection in test environment
- # config.action_controller.allow_forgery_protection = false
- #
- # == Learn more about CSRF (Cross-Site Request Forgery) attacks
- #
- # Here are some resources:
- # * http://isc.sans.org/diary.html?storyid=1750
- # * http://en.wikipedia.org/wiki/Cross-site_request_forgery
- #
- # Keep in mind, this is NOT a silver-bullet, plug 'n' play, warm security blanket for your rails application.
- # There are a few guidelines you should follow:
- #
- # * Keep your GET requests safe and idempotent. More reading material:
- # * http://www.xml.com/pub/a/2002/04/24/deviant.html
- # * http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1
- # * Make sure the session cookies that Rails creates are non-persistent. Check in Firefox and look
- # for "Expires: at end of session"
- #
module ClassMethods
# Turn on request forgery protection. Bear in mind that only non-GET, HTML/JavaScript requests are checked.
#
@@ -79,22 +81,6 @@ def protect_from_forgery(options = {})
self.request_forgery_protection_token ||= :authenticity_token
before_filter :verify_authenticity_token, options
end
-
- def request_forgery_protection_token
- config.request_forgery_protection_token
- end
-
- def request_forgery_protection_token=(val)
- config.request_forgery_protection_token = val
- end
-
- def allow_forgery_protection
- config.allow_forgery_protection
- end
-
- def allow_forgery_protection=(val)
- config.allow_forgery_protection = val
- end
end
protected
@@ -104,22 +90,6 @@ def protect_from_forgery(options = {})
before_filter :verify_authenticity_token, options
end
- def request_forgery_protection_token
- config.request_forgery_protection_token
- end
-
- def request_forgery_protection_token=(val)
- config.request_forgery_protection_token = val
- end
-
- def allow_forgery_protection
- config.allow_forgery_protection
- end
-
- def allow_forgery_protection=(val)
- config.allow_forgery_protection = val
- end
-
# The actual before_filter that is used. Modify this to change how you handle unverified requests.
def verify_authenticity_token
verified_request? || raise(ActionController::InvalidAuthenticityToken)
@@ -146,7 +116,7 @@ def form_authenticity_param
end
def protect_against_forgery?
- config.allow_forgery_protection
+ allow_forgery_protection
end
end
end
View
65 actionpack/lib/action_controller/railtie.rb
@@ -13,64 +13,51 @@ module ActionController
class Railtie < Rails::Railtie
config.action_controller = ActiveSupport::OrderedOptions.new
- ad = config.action_dispatch
- config.action_controller.singleton_class.send(:define_method, :session) do
- ActiveSupport::Deprecation.warn "config.action_controller.session has been " \
- "renamed to config.action_dispatch.session.", caller
- ad.session
- end
+ config.action_controller.singleton_class.tap do |d|
+ d.send(:define_method, :session) do
+ ActiveSupport::Deprecation.warn "config.action_controller.session has been deprecated. " <<
+ "Please use Rails.application.config.session_store instead.", caller
+ end
- config.action_controller.singleton_class.send(:define_method, :session=) do |val|
- ActiveSupport::Deprecation.warn "config.action_controller.session has been " \
- "renamed to config.action_dispatch.session.", caller
- ad.session = val
- end
+ d.send(:define_method, :session=) do |val|
+ ActiveSupport::Deprecation.warn "config.action_controller.session= has been deprecated. " <<
+ "Please use config.session_store(name, options) instead.", caller
+ end
- config.action_controller.singleton_class.send(:define_method, :session_store) do
- ActiveSupport::Deprecation.warn "config.action_controller.session_store has been " \
- "renamed to config.action_dispatch.session_store.", caller
- ad.session_store
- end
+ d.send(:define_method, :session_store) do
+ ActiveSupport::Deprecation.warn "config.action_controller.session_store has been deprecated. " <<
+ "Please use Rails.application.config.session_store instead.", caller
+ end
- config.action_controller.singleton_class.send(:define_method, :session_store=) do |val|
- ActiveSupport::Deprecation.warn "config.action_controller.session_store has been " \
- "renamed to config.action_dispatch.session_store.", caller
- ad.session_store = val
+ d.send(:define_method, :session_store=) do |val|
+ ActiveSupport::Deprecation.warn "config.action_controller.session_store= has been deprecated. " <<
+ "Please use config.session_store(name, options) instead.", caller
+ end
end
log_subscriber :action_controller, ActionController::Railties::LogSubscriber.new
- initializer "action_controller.logger" do
- ActiveSupport.on_load(:action_controller) { self.logger ||= Rails.logger }
- end
-
- initializer "action_controller.page_cache_directory" do
- ActiveSupport.on_load(:action_controller) do
- self.page_cache_directory = Rails.public_path
- end
- end
-
initializer "action_controller.set_configs" do |app|
paths = app.config.paths
ac = app.config.action_controller
- ac.assets_dir = paths.public.to_a.first
- ac.javascripts_dir = paths.public.javascripts.to_a.first
- ac.stylesheets_dir = paths.public.stylesheets.to_a.first
+ ac.assets_dir ||= paths.public.to_a.first
+ ac.javascripts_dir ||= paths.public.javascripts.to_a.first
+ ac.stylesheets_dir ||= paths.public.stylesheets.to_a.first
+ ac.page_cache_directory ||= paths.public.to_a.first
+ ac.helpers_path ||= paths.app.helpers.to_a
ActiveSupport.on_load(:action_controller) do
self.config.merge!(ac)
end
end
- initializer "action_controller.initialize_framework_caches" do
- ActiveSupport.on_load(:action_controller) { self.cache_store ||= RAILS_CACHE }
+ initializer "action_controller.logger" do
+ ActiveSupport.on_load(:action_controller) { self.logger ||= Rails.logger }
end
- initializer "action_controller.set_helpers_path" do |app|
- ActiveSupport.on_load(:action_controller) do
- self.helpers_path = app.config.paths.app.helpers.to_a
- end
+ initializer "action_controller.initialize_framework_caches" do
+ ActiveSupport.on_load(:action_controller) { self.cache_store ||= RAILS_CACHE }
end
initializer "action_controller.url_helpers" do |app|
View
260 actionpack/lib/action_controller/test_case.rb
@@ -36,6 +36,7 @@ def setup_subscriptions
end
def teardown_subscriptions
+ ActiveSupport::Notifications.unsubscribe("action_view.render_template")
ActiveSupport::Notifications.unsubscribe("action_view.render_template!")
end
@@ -282,165 +283,143 @@ def initialize(session = {})
#
# assert_redirected_to page_url(:title => 'foo')
class TestCase < ActiveSupport::TestCase
- include ActionDispatch::TestProcess
- include ActionController::TemplateAssertions
+ module Behavior
+ extend ActiveSupport::Concern
+ include ActionDispatch::TestProcess
- attr_reader :response, :request
+ attr_reader :response, :request
- # Executes a request simulating GET HTTP method and set/volley the response
- def get(action, parameters = nil, session = nil, flash = nil)
- process(action, parameters, session, flash, "GET")
- end
+ module ClassMethods
- # Executes a request simulating POST HTTP method and set/volley the response
- def post(action, parameters = nil, session = nil, flash = nil)
- process(action, parameters, session, flash, "POST")
- end
+ # Sets the controller class name. Useful if the name can't be inferred from test class.
+ # Expects +controller_class+ as a constant. Example: <tt>tests WidgetController</tt>.
+ def tests(controller_class)
+ self.controller_class = controller_class
+ end
+
+ def controller_class=(new_class)
+ prepare_controller_class(new_class) if new_class
+ write_inheritable_attribute(:controller_class, new_class)
+ end
- # Executes a request simulating PUT HTTP method and set/volley the response
- def put(action, parameters = nil, session = nil, flash = nil)
- process(action, parameters, session, flash, "PUT")
- end
+ def controller_class
+ if current_controller_class = read_inheritable_attribute(:controller_class)
+ current_controller_class
+ else
+ self.controller_class = determine_default_controller_class(name)
+ end
+ end
- # Executes a request simulating DELETE HTTP method and set/volley the response
- def delete(action, parameters = nil, session = nil, flash = nil)
- process(action, parameters, session, flash, "DELETE")
- end
+ def determine_default_controller_class(name)
+ name.sub(/Test$/, '').constantize
+ rescue NameError
+ nil
+ end
- # Executes a request simulating HEAD HTTP method and set/volley the response
- def head(action, parameters = nil, session = nil, flash = nil)
- process(action, parameters, session, flash, "HEAD")
- end
+ def prepare_controller_class(new_class)
+ new_class.send :include, ActionController::TestCase::RaiseActionExceptions
+ end
- def xml_http_request(request_method, action, parameters = nil, session = nil, flash = nil)
- @request.env['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
- @request.env['HTTP_ACCEPT'] ||= [Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ')
- returning __send__(request_method, action, parameters, session, flash) do
- @request.env.delete 'HTTP_X_REQUESTED_WITH'
- @request.env.delete 'HTTP_ACCEPT'
end
- end
- alias xhr :xml_http_request
-
- def process(action, parameters = nil, session = nil, flash = nil, http_method = 'GET')
- # Sanity check for required instance variables so we can give an
- # understandable error message.
- %w(@routes @controller @request @response).each do |iv_name|
- if !(instance_variable_names.include?(iv_name) || instance_variable_names.include?(iv_name.to_sym)) || instance_variable_get(iv_name).nil?
- raise "#{iv_name} is nil: make sure you set it in your test's setup method."
- end
+
+ # Executes a request simulating GET HTTP method and set/volley the response
+ def get(action, parameters = nil, session = nil, flash = nil)
+ process(action, parameters, session, flash, "GET")
end
- @request.recycle!
- @response.recycle!
- @controller.response_body = nil
- @controller.formats = nil
- @controller.params = nil
-
- @html_document = nil
- @request.env['REQUEST_METHOD'] = http_method
-
- parameters ||= {}
- @request.assign_parameters(@routes, @controller.class.name.underscore.sub(/_controller$/, ''), action.to_s, parameters)
-
- @request.session = ActionController::TestSession.new(session) unless session.nil?
- @request.session["flash"] = @request.flash.update(flash || {})
- @request.session["flash"].sweep
-
- @controller.request = @request
- @controller.params.merge!(parameters)
- build_request_uri(action, parameters)
- Base.class_eval { include Testing }
- @controller.process_with_new_base_test(@request, @response)
- @request.session.delete('flash') if @request.session['flash'].blank?
- @response
- end
+ # Executes a request simulating POST HTTP method and set/volley the response
+ def post(action, parameters = nil, session = nil, flash = nil)
+ process(action, parameters, session, flash, "POST")
+ end
- include ActionDispatch::Assertions
+ # Executes a request simulating PUT HTTP method and set/volley the response
+ def put(action, parameters = nil, session = nil, flash = nil)
+ process(action, parameters, session, flash, "PUT")
+ end
- # When the request.remote_addr remains the default for testing, which is 0.0.0.0, the exception is simply raised inline
- # (bystepping the regular exception handling from rescue_action). If the request.remote_addr is anything else, the regular
- # rescue_action process takes place. This means you can test your rescue_action code by setting remote_addr to something else
- # than 0.0.0.0.
- #
- # The exception is stored in the exception accessor for further inspection.
- module RaiseActionExceptions
- def self.included(base)
- base.class_eval do
- attr_accessor :exception
- protected :exception, :exception=
- end
+ # Executes a request simulating DELETE HTTP method and set/volley the response
+ def delete(action, parameters = nil, session = nil, flash = nil)
+ process(action, parameters, session, flash, "DELETE")
end
- protected
- def rescue_action_without_handler(e)
- self.exception = e
+ # Executes a request simulating HEAD HTTP method and set/volley the response
+ def head(action, parameters = nil, session = nil, flash = nil)
+ process(action, parameters, session, flash, "HEAD")
+ end
- if request.remote_addr == "0.0.0.0"
- raise(e)
- else
- super(e)
+ def xml_http_request(request_method, action, parameters = nil, session = nil, flash = nil)
+ @request.env['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
+ @request.env['HTTP_ACCEPT'] ||= [Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ')
+ returning __send__(request_method, action, parameters, session, flash) do
+ @request.env.delete 'HTTP_X_REQUESTED_WITH'
+ @request.env.delete 'HTTP_ACCEPT'
+ end
+ end
+ alias xhr :xml_http_request
+
+ def process(action, parameters = nil, session = nil, flash = nil, http_method = 'GET')
+ # Sanity check for required instance variables so we can give an
+ # understandable error message.
+ %w(@routes @controller @request @response).each do |iv_name|
+ if !(instance_variable_names.include?(iv_name) || instance_variable_names.include?(iv_name.to_sym)) || instance_variable_get(iv_name).nil?
+ raise "#{iv_name} is nil: make sure you set it in your test's setup method."
end
end
- end
- setup :setup_controller_request_and_response
+ @request.recycle!
+ @response.recycle!
+ @controller.response_body = nil
+ @controller.formats = nil
+ @controller.params = nil
- @@controller_class = nil
+ @html_document = nil
+ @request.env['REQUEST_METHOD'] = http_method
- class << self
- # Sets the controller class name. Useful if the name can't be inferred from test class.
- # Expects +controller_class+ as a constant. Example: <tt>tests WidgetController</tt>.
- def tests(controller_class)
- self.controller_class = controller_class
- end
+ parameters ||= {}
+ @request.assign_parameters(@routes, @controller.class.name.underscore.sub(/_controller$/, ''), action.to_s, parameters)
- def controller_class=(new_class)
- prepare_controller_class(new_class) if new_class
- write_inheritable_attribute(:controller_class, new_class)
- end
+ @request.session = ActionController::TestSession.new(session) unless session.nil?
+ @request.session["flash"] = @request.flash.update(flash || {})
+ @request.session["flash"].sweep
- def controller_class
- if current_controller_class = read_inheritable_attribute(:controller_class)
- current_controller_class
- else
- self.controller_class = determine_default_controller_class(name)
- end
+ @controller.request = @request
+ @controller.params.merge!(parameters)
+ build_request_uri(action, parameters)
+ Base.class_eval { include Testing }
+ @controller.process_with_new_base_test(@request, @response)
+ @request.session.delete('flash') if @request.session['flash'].blank?
+ @response
end
- def determine_default_controller_class(name)
- name.sub(/Test$/, '').constantize
- rescue NameError
- nil
- end
+ def setup_controller_request_and_response
+ @request = TestRequest.new
+ @response = TestResponse.new
- def prepare_controller_class(new_class)
- new_class.send :include, RaiseActionExceptions
- end
- end
+ if klass = self.class.controller_class
+ @controller ||= klass.new rescue nil
+ end
- def setup_controller_request_and_response
- @request = TestRequest.new
- @response = TestResponse.new
+ @request.env.delete('PATH_INFO')
- if klass = self.class.controller_class
- @controller ||= klass.new rescue nil
+ if @controller
+ @controller.request = @request
+ @controller.params = {}
+ end
end
- @request.env.delete('PATH_INFO')
-
- if @controller
- @controller.request = @request
- @controller.params = {}
+ # Cause the action to be rescued according to the regular rules for rescue_action when the visitor is not local
+ def rescue_action_in_public!
+ @request.remote_addr = '208.77.188.166' # example.com
end
- end
- # Cause the action to be rescued according to the regular rules for rescue_action when the visitor is not local
- def rescue_action_in_public!
- @request.remote_addr = '208.77.188.166' # example.com
- end
+ included do
+ include ActionController::TemplateAssertions
+ include ActionDispatch::Assertions
+ setup :setup_controller_request_and_response
+ end
private
+
def build_request_uri(action, parameters)
unless @request.env["PATH_INFO"]
options = @controller.__send__(:url_options).merge(parameters)
@@ -458,4 +437,33 @@ def build_request_uri(action, parameters)
end
end
end
+
+ # When the request.remote_addr remains the default for testing, which is 0.0.0.0, the exception is simply raised inline
+ # (bystepping the regular exception handling from rescue_action). If the request.remote_addr is anything else, the regular
+ # rescue_action process takes place. This means you can test your rescue_action code by setting remote_addr to something else
+ # than 0.0.0.0.
+ #
+ # The exception is stored in the exception accessor for further inspection.
+ module RaiseActionExceptions
+ def self.included(base)
+ base.class_eval do
+ attr_accessor :exception
+ protected :exception, :exception=
+ end
+ end
+
+ protected
+ def rescue_action_without_handler(e)
+ self.exception = e
+
+ if request.remote_addr == "0.0.0.0"
+ raise(e)
+ else
+ super(e)
+ end
+ end
+ end
+
+ include Behavior
+ end
end
View
2 actionpack/lib/action_dispatch/routing/url_for.rb
@@ -128,7 +128,7 @@ def url_for(options = nil)
when String
options
when nil, Hash
- _router.url_for(url_options.merge(options || {}))
+ _router.url_for(url_options.merge((options || {}).symbolize_keys))
else
polymorphic_url(options)
end
View
2 actionpack/lib/action_view/helpers/active_model_helper.rb
@@ -6,7 +6,7 @@
module ActionView
ActiveSupport.on_load(:action_view) do
class ActionView::Base
- @@field_error_proc = Proc.new{ |html_tag, instance| "<div class=\"fieldWithErrors\">#{html_tag}</div>".html_safe }
+ @@field_error_proc = Proc.new{ |html_tag, instance| "<div class=\"field_with_errors\">#{html_tag}</div>".html_safe }
cattr_accessor :field_error_proc
end
end
View
2 actionpack/lib/action_view/helpers/url_helper.rb
@@ -102,7 +102,7 @@ def url_for(options = {})
escape = true
options
when Hash
- options = { :only_path => options[:host].nil? }.update(options.to_hash.symbolize_keys)
+ options = { :only_path => options[:host].nil? }.update(options.symbolize_keys)
escape = options.key?(:escape) ? options.delete(:escape) : false
super
when :back
View
2 actionpack/lib/action_view/test_case.rb
@@ -31,8 +31,8 @@ def initialize
include ActionController::PolymorphicRoutes
include ActionController::RecordIdentifier
+ include AbstractController::Helpers
include ActionView::Helpers
- include ActionController::Helpers
class_inheritable_accessor :helper_class
attr_accessor :controller, :output_buffer, :rendered
View
8 actionpack/test/abstract_unit.rb
@@ -143,6 +143,12 @@ def config
end
end
+class ActionDispatch::IntegrationTest < ActiveSupport::TestCase
+ setup do
+ @routes = SharedTestRoutes
+ end
+end
+
class ActionController::IntegrationTest < ActiveSupport::TestCase
def self.build_app(routes = nil)
RoutedRackApp.new(routes || ActionDispatch::Routing::RouteSet.new) do |middleware|
@@ -275,4 +281,4 @@ module ActionController
class Base
include SharedTestRoutes.url_helpers
end
-end
+end
View
2 actionpack/test/controller/assert_select_test.rb
@@ -1,3 +1,4 @@
+# encoding: utf-8
#--
# Copyright (c) 2006 Assaf Arkin (http://labnotes.org)
# Under MIT and/or CC By license.
@@ -347,7 +348,6 @@ def test_assert_select_rjs_with_unicode
assert_select str, :text => "\343\203\201\343\202\261\343\203\203\343\203\210"
assert_select str, "\343\203\201\343\202\261\343\203\203\343\203\210"
if str.respond_to?(:force_encoding)
- str.force_encoding(Encoding::UTF_8)
assert_select str, /\343\203\201..\343\203\210/u
assert_raise(Assertion) { assert_select str, /\343\203\201.\343\203\210/u }
else
View
3 actionpack/test/controller/layout_test.rb
@@ -1,4 +1,5 @@
require 'abstract_unit'
+require 'rbconfig'
# The view_paths array must be set on Base and not LayoutTest so that LayoutTest's inherited
# method has access to the view_paths array when looking for a layout to automatically assign.
@@ -209,7 +210,7 @@ def test_layout_status_is_rendered
end
end
-unless RUBY_PLATFORM =~ /mswin|mingw/
+unless Config::CONFIG['host_os'] =~ /mswin|mingw/
class LayoutSymlinkedTest < LayoutTest
layout "symlinked/symlinked_layout"
end
View
18 actionpack/test/controller/render_json_test.rb
@@ -3,6 +3,14 @@
require 'pathname'
class RenderJsonTest < ActionController::TestCase
+ class JsonRenderable
+ def as_json(options={})
+ hash = { :a => :b, :c => :d, :e => :f }
+ hash.except!(*options[:except]) if options[:except]
+ hash
+ end
+ end
+
class TestController < ActionController::Base
protect_from_forgery
@@ -37,6 +45,10 @@ def render_symbol_json
def render_json_with_render_to_string
render :json => {:hello => render_to_string(:partial => 'partial')}
end
+
+ def render_json_with_extra_options
+ render :json => JsonRenderable.new, :except => [:c, :e]
+ end
end
tests TestController
@@ -91,4 +103,10 @@ def test_render_json_with_render_to_string
assert_equal '{"hello":"partial html"}', @response.body
assert_equal 'application/json', @response.content_type
end
+
+ def test_render_json_forwards_extra_options
+ get :render_json_with_extra_options
+ assert_equal '{"a":"b"}', @response.body
+ assert_equal 'application/json', @response.content_type
+ end
end
View
24 actionpack/test/controller/render_xml_test.rb
@@ -3,6 +3,13 @@
require 'pathname'
class RenderXmlTest < ActionController::TestCase
+ class XmlRenderable
+ def to_xml(options)
+ options[:root] ||= "i-am-xml"
+ "<#{options[:root]}/>"
+ end
+ end
+
class TestController < ActionController::Base
protect_from_forgery
@@ -20,13 +27,7 @@ def render_with_object_location
end
def render_with_to_xml
- to_xmlable = Class.new do
- def to_xml
- "<i-am-xml/>"
- end
- end.new
-
- render :xml => to_xmlable
+ render :xml => XmlRenderable.new
end
def formatted_xml_erb
@@ -35,6 +36,10 @@ def formatted_xml_erb
def render_xml_with_custom_content_type
render :xml => "<blah/>", :content_type => "application/atomsvc+xml"
end
+
+ def render_xml_with_custom_options
+ render :xml => XmlRenderable.new, :root => "i-am-THE-xml"
+ end
end
tests TestController
@@ -58,6 +63,11 @@ def test_rendering_xml_should_call_to_xml_if_possible
assert_equal "<i-am-xml/>", @response.body
end
+ def test_rendering_xml_should_call_to_xml_with_extra_options
+ get :render_xml_with_custom_options
+ assert_equal "<i-am-THE-xml/>", @response.body
+ end
+
def test_rendering_with_object_location_should_set_header_with_url_for
with_routing do |set|
set.draw do |map|
View
4 actionpack/test/controller/send_file_test.rb
@@ -25,7 +25,7 @@ def data
end
def multibyte_text_data
- send_data("Кирилица\n祝您好運", options)
+ send_data("Кирилица\n祝您好運.", options)
end
end
@@ -128,7 +128,7 @@ def test_send_file_headers_with_mime_lookup_with_symbol
assert_equal 'image/png', @controller.content_type
end
-
+
def test_send_file_headers_with_bad_symbol
options = {
View
16 actionpack/test/controller/url_for_test.rb
@@ -257,10 +257,24 @@ def test_multiple_includes_maintain_distinct_options
assert_equal second_class.default_url_options[:host], second_host
end
+ def test_with_stringified_keys
+ assert_equal("/c", W.new.url_for('controller' => 'c', 'only_path' => true))
+ assert_equal("/c/a", W.new.url_for('controller' => 'c', 'action' => 'a', 'only_path' => true))
+ end
+
+ def test_with_hash_with_indifferent_access
+ W.default_url_options[:controller] = 'd'
+ W.default_url_options[:only_path] = false
+ assert_equal("/c", W.new.url_for(HashWithIndifferentAccess.new('controller' => 'c', 'only_path' => true)))
+
+ W.default_url_options[:action] = 'b'
+ assert_equal("/c/a", W.new.url_for(HashWithIndifferentAccess.new('controller' => 'c', 'action' => 'a', 'only_path' => true)))
+ end
+
private
def extract_params(url)
url.split('?', 2).last.split('&').sort
end
end
end
-end
+end
View
10 actionpack/test/dispatch/routing_test.rb
@@ -237,8 +237,8 @@ def call(env)
AltRoutes = ActionDispatch::Routing::RouteSet.new(AltRequest)
AltRoutes.draw do
- get "/" => XHeader.new, :constraints => {:x_header => /HEADER/}
- get "/" => AltApp.new
+ get "/" => TestRoutingMapper::TestAltApp::XHeader.new, :constraints => {:x_header => /HEADER/}
+ get "/" => TestRoutingMapper::TestAltApp::AltApp.new
end
def app
@@ -1000,6 +1000,12 @@ def test_url_generator_for_generic_route
end
end
+ def test_assert_recognizes_account_overview
+ with_test_routes do
+ assert_recognizes({:controller => "account", :action => "overview"}, "/account/overview")
+ end
+ end
+
private
def with_test_routes
yield
View
8 actionpack/test/template/active_model_helper_test.rb
@@ -27,26 +27,26 @@ def setup
def test_text_area_with_errors
assert_dom_equal(
- %(<div class="fieldWithErrors"><textarea cols="40" id="post_body" name="post[body]" rows="20">Back to the hill and over it again!</textarea></div>),
+ %(<div class="field_with_errors"><textarea cols="40" id="post_body" name="post[body]" rows="20">Back to the hill and over it again!</textarea></div>),
text_area("post", "body")
)
end
def test_text_field_with_errors
assert_dom_equal(
- %(<div class="fieldWithErrors"><input id="post_author_name" name="post[author_name]" size="30" type="text" value="" /></div>),
+ %(<div class="field_with_errors"><input id="post_author_name" name="post[author_name]" size="30" type="text" value="" /></div>),
text_field("post", "author_name")
)
end
def test_field_error_proc
old_proc = ActionView::Base.field_error_proc
ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
- %(<div class=\"fieldWithErrors\">#{html_tag} <span class="error">#{[instance.error_message].join(', ')}</span></div>).html_safe
+ %(<div class=\"field_with_errors\">#{html_tag} <span class="error">#{[instance.error_message].join(', ')}</span></div>).html_safe
end
assert_dom_equal(
- %(<div class="fieldWithErrors"><input id="post_author_name" name="post[author_name]" size="30" type="text" value="" /> <span class="error">can't be empty</span></div>),
+ %(<div class="field_with_errors"><input id="post_author_name" name="post[author_name]" size="30" type="text" value="" /> <span class="error">can't be empty</span></div>),
text_field("post", "author_name")
)
ensure
View
3 actionpack/test/template/form_tag_helper_test.rb
@@ -3,9 +3,6 @@
class FormTagHelperTest < ActionView::TestCase
tests ActionView::Helpers::FormTagHelper
- # include ActiveSupport::Configurable
- # DEFAULT_CONFIG = ActionView::DEFAULT_CONFIG
-
def setup
super
@controller = BasicController.new
View
1 actionpack/test/template/text_helper_test.rb
@@ -1,3 +1,4 @@
+# encoding: us-ascii
require 'abstract_unit'
require 'testing_sandbox'
begin
View
1 activemodel/lib/active_model/locale/en.yml
@@ -17,6 +17,7 @@ en:
too_short: "is too short (minimum is {{count}} characters)"
wrong_length: "is the wrong length (should be {{count}} characters)"
not_a_number: "is not a number"
+ not_an_integer: "must be an integer"
greater_than: "must be greater than {{count}}"
greater_than_or_equal_to: "must be greater than or equal to {{count}}"
equal_to: "must be equal to {{count}}"
View
35 activemodel/lib/active_model/serializers/xml.rb
@@ -1,6 +1,7 @@
require 'active_support/core_ext/array/wrap'
require 'active_support/core_ext/class/attribute_accessors'
require 'active_support/core_ext/hash/conversions'
+require 'active_support/core_ext/hash/slice'
module ActiveModel
module Serializers
@@ -12,8 +13,10 @@ class Serializer #:nodoc:
class Attribute #:nodoc:
attr_reader :name, :value, :type
- def initialize(name, serializable)
+ def initialize(name, serializable, raw_value=nil)
@name, @serializable = name, serializable
+ @raw_value = raw_value || @serializable.send(name)
+
@type = compute_type
@value = compute_value
end
@@ -51,28 +54,25 @@ def decorations(include_types = true)
protected
def compute_type
- value = @serializable.send(name)
- type = Hash::XML_TYPE_NAMES[value.class.name]
- type ||= :string if value.respond_to?(:to_str)
+ type = Hash::XML_TYPE_NAMES[@raw_value.class.name]
+ type ||= :string if @raw_value.respond_to?(:to_str)
type ||= :yaml
type
end
def compute_value
- value = @serializable.send(name)
-
if formatter = Hash::XML_FORMATTING[type.to_s]
- value ? formatter.call(value) : nil
+ @raw_value ? formatter.call(@raw_value) : nil
else
- value
+ @raw_value
end
end
end
class MethodAttribute < Attribute #:nodoc:
protected
def compute_type
- Hash::XML_TYPE_NAMES[@serializable.send(name).class.name] || :string
+ Hash::XML_TYPE_NAMES[@raw_value.class.name] || :string
end
end
@@ -92,25 +92,24 @@ def initialize(serializable, options = nil)
# then because <tt>:except</tt> is set to a default value, the second
# level model can have both <tt>:except</tt> and <tt>:only</tt> set. So if
# <tt>:only</tt> is set, always delete <tt>:except</tt>.
- def serializable_attribute_names
- attribute_names = @serializable.attributes.keys.sort
-
+ def serializable_attributes_hash
+ attributes = @serializable.attributes
if options[:only].any?
- attribute_names &= options[:only]
+ attributes.slice(*options[:only])
elsif options[:except].any?
- attribute_names -= options[:except]
+ attributes.except(*options[:except])
+ else
+ attributes
end
-
- attribute_names
end
def serializable_attributes
- serializable_attribute_names.collect { |name| Attribute.new(name, @serializable) }
+ serializable_attributes_hash.map { |name, value| self.class::Attribute.new(name, @serializable, value) }
end
def serializable_method_attributes
Array.wrap(options[:methods]).inject([]) do |methods, name|
- methods << MethodAttribute.new(name.to_s, @serializable) if @serializable.respond_to?(name.to_s)
+ methods << self.class::MethodAttribute.new(name.to_s, @serializable) if @serializable.respond_to?(name.to_s)
methods
end
end
View
29 activemodel/lib/active_model/validations/numericality.rb
@@ -25,11 +25,18 @@ def validate_each(record, attr_name, value)
return if options[:allow_nil] && raw_value.nil?
- unless value = parse_raw_value(raw_value, options)
+ unless value = parse_raw_value_as_a_number(raw_value)
record.errors.add(attr_name, :not_a_number, :value => raw_value, :default => options[:message])
return
end
+ if options[:only_integer]
+ unless value = parse_raw_value_as_an_integer(raw_value)
+ record.errors.add(attr_name, :not_an_integer, :value => raw_value, :default => options[:message])
+ return
+ end
+ end
+
options.slice(*CHECKS.keys).each do |option, option_value|
case option
when :odd, :even
@@ -44,23 +51,23 @@ def validate_each(record, attr_name, value)
record.errors.add(attr_name, option, :default => options[:message], :value => value, :count => option_value)
end
end
- end
+ end
end
protected
- def parse_raw_value(raw_value, options)
- if options[:only_integer]
- raw_value.to_i if raw_value.to_s =~ /\A[+-]?\d+\Z/
- else
- begin
- Kernel.Float(raw_value)
- rescue ArgumentError, TypeError
- nil
- end
+ def parse_raw_value_as_a_number(raw_value)
+ begin
+ Kernel.Float(raw_value)
+ rescue ArgumentError, TypeError
+ nil
end
end
+ def parse_raw_value_as_an_integer(raw_value)
+ raw_value.to_i if raw_value.to_s =~ /\A[+-]?\d+\Z/
+ end
+
end
module ClassMethods
View
18 activemodel/test/cases/validations/i18n_validation_test.rb
@@ -217,15 +217,15 @@ def test_validates_numericality_of_generates_message_with_custom_default_message
def test_validates_numericality_of_only_integer_generates_message
Person.validates_numericality_of :title, :only_integer => true
- @person.title = 'a'
- @person.errors.expects(:generate_message).with(:title, :not_a_number, {:value => 'a', :default => nil})
+ @person.title = '0.0'
+ @person.errors.expects(:generate_message).with(:title, :not_an_integer, {:value => '0.0', :default => nil})
@person.valid?
end
def test_validates_numericality_of_only_integer_generates_message_with_custom_default_message
Person.validates_numericality_of :title, :only_integer => true, :message => 'custom'
- @person.title = 'a'
- @person.errors.expects(:generate_message).with(:title, :not_a_number, {:value => 'a', :default => 'custom'})
+ @person.title = '0.0'
+ @person.errors.expects(:generate_message).with(:title, :not_an_integer, {:value => '0.0', :default => 'custom'})
@person.valid?
end
@@ -441,20 +441,20 @@ def test_validates_numericality_of_finds_global_default_translation
# validates_numericality_of with :only_integer w/o mocha
def test_validates_numericality_of_only_integer_finds_custom_model_key_translation
- I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {:title => {:not_a_number => 'custom message'}}}}}}
- I18n.backend.store_translations 'en', :errors => {:messages => {:not_a_number => 'global message'}}
+ I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {:title => {:not_an_integer => 'custom message'}}}}}}
+ I18n.backend.store_translations 'en', :errors => {:messages => {:not_an_integer => 'global message'}}
Person.validates_numericality_of :title, :only_integer => true
- @person.title = 'a'
+ @person.title = '1.0'
@person.valid?
assert_equal ['custom message'], @person.errors[:title]
end
def test_validates_numericality_of_only_integer_finds_global_default_translation
- I18n.backend.store_translations 'en', :errors => {:messages => {:not_a_number => 'global message'}}
+ I18n.backend.store_translations 'en', :errors => {:messages => {:not_an_integer => 'global message'}}
Person.validates_numericality_of :title, :only_integer => true
- @person.title = 'a'
+ @person.title = '1.0'
@person.valid?
assert_equal ['global message'], @person.errors[:title]
end
View
2 activerecord/CHANGELOG
@@ -1,5 +1,7 @@
*Rails 3.0.0 [beta 4/release candidate] (unreleased)*
+* PostgreSQL: drop support for old postgres driver. Use pg 0.9.0 or later. [Jeremy Kemper]
+
* Observers can prevent records from saving by returning false, just like before_save and friends. #4087 [Mislav Marohnić]
View
3 activerecord/lib/active_record/base.rb
@@ -1844,8 +1844,7 @@ def []=(attr_name, value)
# user.is_admin? # => true
def attributes=(new_attributes, guard_protected_attributes = true)
return if new_attributes.nil?
- attributes = new_attributes.dup
- attributes.stringify_keys!
+ attributes = new_attributes.stringify_keys
multi_parameter_attributes = []
attributes = remove_attributes_protected_from_mass_assignment(attributes) if guard_protected_attributes
View
10 activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
@@ -13,12 +13,12 @@ def quote(value, column = nil)
when String, ActiveSupport::Multibyte::Chars
value = value.to_s
if column && column.type == :binary && column.class.respond_to?(:string_to_binary)
- "#{quoted_string_prefix}'#{quote_string(column.class.string_to_binary(value))}'" # ' (for ruby-mode)
+ "'#{quote_string(column.class.string_to_binary(value))}'" # ' (for ruby-mode)
elsif column && [:integer, :float].include?(column.type)
value = column.type == :integer ? value.to_i : value.to_f
value.to_s
else
- "#{quoted_string_prefix}'#{quote_string(value)}'" # ' (for ruby-mode)
+ "'#{quote_string(value)}'" # ' (for ruby-mode)
end
when NilClass then "NULL"
when TrueClass then (column && column.type == :integer ? '1' : quoted_true)
@@ -30,7 +30,7 @@ def quote(value, column = nil)
if value.acts_like?(:date) || value.acts_like?(:time)
"'#{quoted_date(value)}'"
else
- "#{quoted_string_prefix}'#{quote_string(value.to_yaml)}'"
+ "'#{quote_string(value.to_yaml)}'"
end
end
end
@@ -67,10 +67,6 @@ def quoted_date(value)
value
end.to_s(:db)
end
-
- def quoted_string_prefix
- ''
- end
end
end
end
View
157 activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -2,26 +2,12 @@
require 'active_support/core_ext/kernel/requires'
require 'active_support/core_ext/object/blank'
-begin
- require_library_or_gem 'pg'
-rescue LoadError => e
- begin
- require_library_or_gem 'postgres'
- class PGresult
- alias_method :nfields, :num_fields unless self.method_defined?(:nfields)
- alias_method :ntuples, :num_tuples unless self.method_defined?(:ntuples)
- alias_method :ftype, :type unless self.method_defined?(:ftype)
- alias_method :cmd_tuples, :cmdtuples unless self.method_defined?(:cmd_tuples)
- end
- rescue LoadError
- raise e
- end
-end
-
module ActiveRecord
class Base
# Establishes a connection to the database that's used by all Active Record objects
def self.postgresql_connection(config) # :nodoc:
+ require 'pg'
+
config = config.symbolize_keys
host = config[:host]
port = config[:port] || 5432
@@ -277,20 +263,12 @@ def supports_primary_key? #:nodoc:
true
end
- # Does PostgreSQL support standard conforming strings?
- def supports_standard_conforming_strings?
- # Temporarily set the client message level above error to prevent unintentional
- # error messages in the logs when working on a PostgreSQL database server that
- # does not support standard conforming strings.
- client_min_messages_old = client_min_messages
- self.client_min_messages = 'panic'
-
- # postgres-pr does not raise an exception when client_min_messages is set higher
- # than error and "SHOW standard_conforming_strings" fails, but returns an empty
- # PGresult instead.
- has_support = query('SHOW standard_conforming_strings')[0][0] rescue false
- self.client_min_messages = client_min_messages_old
- has_support
+ # Enable standard-conforming strings if available.
+ def set_standard_conforming_strings
+ old, self.client_min_messages = client_min_messages, 'panic'
+ execute('SET standard_conforming_strings = on') rescue nil
+ ensure
+ self.client_min_messages = old
end
def supports_insert_with_returning?
@@ -314,85 +292,23 @@ def table_alias_length
# QUOTING ==================================================
# Escapes binary strings for bytea input to the database.
- def escape_bytea(original_value)
- if @connection.respond_to?(:escape_bytea)
- self.class.instance_eval do
- define_method(:escape_bytea) do |value|
- @connection.escape_bytea(value) if value
- end
- end
- elsif PGconn.respond_to?(:escape_bytea)
- self.class.instance_eval do
- define_method(:escape_bytea) do |value|
- PGconn.escape_bytea(value) if value
- end
- end
- else
- self.class.instance_eval do
- define_method(:escape_bytea) do |value|
- if value
- result = ''
- value.each_byte { |c| result << sprintf('\\\\%03o', c) }
- result
- end
- end
- end
- end
- escape_bytea(original_value)
+ def escape_bytea(value)
+ @connection.escape_bytea(value) if value
end
# Unescapes bytea output from a database to the binary string it represents.
# NOTE: This is NOT an inverse of escape_bytea! This is only to be used
# on escaped binary output from database drive.
- def unescape_bytea(original_value)
- # In each case, check if the value actually is escaped PostgreSQL bytea output
- # or an unescaped Active Record attribute that was just written.
- if PGconn.respond_to?(:unescape_bytea)
- self.class.instance_eval do
- define_method(:unescape_bytea) do |value|
- if value =~ /\\\d{3}/
- PGconn.unescape_bytea(value)
- else
- value
- end
- end
- end
- else
- self.class.instance_eval do
- define_method(:unescape_bytea) do |value|
- if value =~ /\\\d{3}/
- result = ''
- i, max = 0, value.size
- while i < max
- char = value[i]
- if char == ?\\
- if value[i+1] == ?\\
- char = ?\\
- i += 1
- else
- char = value[i+1..i+3].oct
- i += 3
- end
- end
- result << char
- i += 1
- end
- result
- else
- value
- end
- end
- end
- end
- unescape_bytea(original_value)
+ def unescape_bytea(value)
+ @connection.unescape_bytea(value) if value
end
# Quotes PostgreSQL-specific data types for SQL input.
def quote(value, column = nil) #:nodoc:
if value.kind_of?(String) && column && column.type == :binary
- "#{quoted_string_prefix}'#{escape_bytea(value)}'"
+ "'#{escape_bytea(value)}'"
elsif value.kind_of?(String) && column && column.sql_type == 'xml'
- "xml E'#{quote_string(value)}'"
+ "xml '#{quote_string(value)}'"
elsif value.kind_of?(Numeric) && column && column.sql_type == 'money'
# Not truly string input, so doesn't require (or allow) escape string syntax.
"'#{value.to_s}'"
@@ -408,28 +324,9 @@ def quote(value, column = nil) #:nodoc:
end
end
- # Quotes strings for use in SQL input in the postgres driver for better performance.
- def quote_string(original_value) #:nodoc:
- if @connection.respond_to?(:escape)
- self.class.instance_eval do
- define_method(:quote_string) do |s|
- @connection.escape(s)
- end
- end
- elsif PGconn.respond_to?(:escape)
- self.class.instance_eval do
- define_method(:quote_string) do |s|
- PGconn.escape(s)
- end
- end
- else
- # There are some incorrectly compiled postgres drivers out there
- # that don't define PGconn.escape.
- self.class.instance_eval do
- remove_method(:quote_string)
- end
- end
- quote_string(original_value)
+ # Quotes strings for use in SQL input.
+ def quote_string(s) #:nodoc:
+ @connection.escape(s)
end
# Checks the following cases:
@@ -1005,22 +902,11 @@ def connect
# Ignore async_exec and async_query when using postgres-pr.
@async = @config[:allow_concurrency] && @connection.respond_to?(:async_exec)
- # Use escape string syntax if available. We cannot do this lazily when encountering
- # the first string, because that could then break any transactions in progress.
- # See: http://www.postgresql.org/docs/current/static/runtime-config-compatible.html
- # If PostgreSQL doesn't know the standard_conforming_strings parameter then it doesn't
- # support escape string syntax. Don't override the inherited quoted_string_prefix.
- if supports_standard_conforming_strings?
- self.class.instance_eval do
- define_method(:quoted_string_prefix) { 'E' }
- end
- end
-
# Money type has a fixed precision of 10 in PostgreSQL 8.2 and below, and as of
# PostgreSQL 8.3 it has a fixed precision of 19. PostgreSQLColumn.extract_precision
# should know about this but can't detect it there, so deal with it here.
- PostgreSQLColumn.money_precision =
- (postgresql_version >= 80300) ? 19 : 10
+ PostgreSQLColumn.money_precision = (postgresql_version >= 80300) ? 19 : 10
+
configure_connection
end
@@ -1036,7 +922,10 @@ def configure_connection
end
self.client_min_messages = @config[:min_messages] if @config[:min_messages]
self.schema_search_path = @config[:schema_search_path] || @config[:schema_order]
-
+
+ # Use standard-conforming strings if available so we don't have to do the E'...' dance.
+ set_standard_conforming_strings
+
# If using ActiveRecord's time zone support configure the connection to return
# TIMESTAMP WITH ZONE types in UTC.
execute("SET time zone 'UTC'") if ActiveRecord::Base.default_timezone == :utc
View
16 activerecord/lib/active_record/fixtures.rb
@@ -3,8 +3,9 @@
require 'csv'
require 'zlib'
require 'active_support/dependencies'
-require 'active_support/core_ext/logger'
+require 'active_support/core_ext/array/wrap'
require 'active_support/core_ext/object/blank'
+require 'active_support/core_ext/logger'
if RUBY_VERSION < '1.9'
module YAML #:nodoc:
@@ -492,6 +493,7 @@ def self.instantiate_all_loaded_fixtures(object, load_instances = true)
def self.create_fixtures(fixtures_directory, table_names, class_names = {})
table_names = [table_names].flatten.map { |n| n.to_s }
+ table_names.each { |n| class_names[n.tr('/', '_').to_sym] = n.classify if n.include?('/') }
connection = block_given? ? yield : ActiveRecord::Base.connection
table_names_to_fetch = table_names.reject { |table_name| fixture_is_cached?(connection, table_name) }
@@ -502,7 +504,7 @@ def self.create_fixtures(fixtures_directory, table_names, class_names = {})
fixtures_map = {}
fixtures = table_names_to_fetch.map do |table_name|
- fixtures_map[table_name] = Fixtures.new(connection, File.split(table_name.to_s).last, class_names[table_name.to_sym], File.join(fixtures_directory, table_name.to_s))
+ fixtures_map[table_name] = Fixtures.new(connection, table_name.tr('/', '_'), class_names[table_name.tr('/', '_').to_sym], File.join(fixtures_directory, table_name))
end
all_loaded_fixtures.update(fixtures_map)
@@ -836,8 +838,8 @@ def set_fixture_class(class_names = {})
def fixtures(*table_names)
if table_names.first == :all
- table_names = Dir["#{fixture_path}/*.yml"] + Dir["#{fixture_path}/*.csv"]
- table_names.map! { |f| File.basename(f).split('.')[0..-2].join('.') }
+ table_names = Dir["#{fixture_path}/**/*.{yml,csv}"]
+ table_names.map! { |f| f[(fixture_path.size + 1)..-5] }
else
table_names = table_names.flatten.map { |n| n.to_s }
end
@@ -868,9 +870,9 @@ def require_fixture_classes(table_names = nil)
end
def setup_fixture_accessors(table_names = nil)
- table_names = [table_names] if table_names && !table_names.respond_to?(:each)
- (table_names || fixture_table_names).each do |table_name|
- table_name = table_name.to_s.tr('.', '_')
+ table_names = Array.wrap(table_names || fixture_table_names)
+ table_names.each do |table_name|
+ table_name = table_name.to_s.tr('./', '_')
define_method(table_name) do |*fixtures|
force_reload = fixtures.pop if fixtures.last == true || fixtures.last == :reload
View
4 activerecord/lib/active_record/railties/databases.rake
@@ -258,8 +258,8 @@ namespace :db do
base_dir = ENV['FIXTURES_PATH'] ? File.join(Rails.root, ENV['FIXTURES_PATH']) : File.join(Rails.root, 'test', 'fixtures')
fixtures_dir = ENV['FIXTURES_DIR'] ? File.join(base_dir, ENV['FIXTURES_DIR']) : base_dir
- (ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/).map {|f| File.join(fixtures_dir, f) } : Dir.glob(File.join(fixtures_dir, '*.{yml,csv}'))).each do |fixture_file|
- Fixtures.create_fixtures(File.dirname(fixture_file), File.basename(fixture_file, '.*'))
+ (ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/).map {|f| File.join(fixtures_dir, f) } : Dir["#{fixtures_dir}/**/*.{yml,csv}"]).each do |fixture_file|
+ Fixtures.create_fixtures(fixtures_dir, fixture_file[(fixtures_dir.size + 1)..-5])
end
end
View
11 activerecord/lib/active_record/serializers/xml_serializer.rb
@@ -182,17 +182,6 @@ def initialize(*args)
options[:except] |= Array.wrap(@serializable.class.inheritance_column)
end
- def serializable_attributes
- serializable_attribute_names.collect { |name| Attribute.new(name, @serializable) }
- end
-
- def serializable_method_attributes
- Array.wrap(options[:methods]).inject([