diff options
127 files changed, 1022 insertions, 784 deletions
diff --git a/.gitignore b/.gitignore index 7236e395a2..bc96284375 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ # Don't put *.swp, *.bak, etc here; those belong in a global ~/.gitignore. -# Check out http://help.github.com/ignore-files/ for how to set that up. +# Check out https://help.github.com/articles/ignoring-files for how to set that up. debug.log .Gemfile @@ -36,7 +36,7 @@ task :smoke do end desc "Install gems for all projects." -task :install => :gem do +task :install => :build do version = File.read("RAILS_VERSION").strip (PROJECTS - ["railties"]).each do |project| puts "INSTALLING #{project}" @@ -78,7 +78,7 @@ task :update_versions do end # -# We have a webhook configured in Github that gets invoked after pushes. +# We have a webhook configured in GitHub that gets invoked after pushes. # This hook triggers the following tasks: # # * updates the local checkout diff --git a/actionpack/lib/action_controller/metal/url_for.rb b/actionpack/lib/action_controller/metal/url_for.rb index 505f3b4e61..754249cbc8 100644 --- a/actionpack/lib/action_controller/metal/url_for.rb +++ b/actionpack/lib/action_controller/metal/url_for.rb @@ -32,7 +32,8 @@ module ActionController if (same_origin = _routes.equal?(env["action_dispatch.routes"])) || (script_name = env["ROUTES_#{_routes.object_id}_SCRIPT_NAME"]) || - (original_script_name = env['SCRIPT_NAME']) + (original_script_name = env['ORIGINAL_SCRIPT_NAME']) + @_url_options.dup.tap do |options| if original_script_name options[:original_script_name] = original_script_name diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb index 41a286f0ed..e5f1ad63c2 100644 --- a/actionpack/lib/action_controller/test_case.rb +++ b/actionpack/lib/action_controller/test_case.rb @@ -558,7 +558,7 @@ module ActionController parameters ||= {} controller_class_name = @controller.class.anonymous? ? "anonymous" : - @controller.class.name.underscore.sub(/_controller$/, '') + @controller.class.controller_path @request.assign_parameters(@routes, controller_class_name, action.to_s, parameters) diff --git a/actionpack/lib/action_dispatch/http/parameters.rb b/actionpack/lib/action_dispatch/http/parameters.rb index 246d9c121a..20c24ddd85 100644 --- a/actionpack/lib/action_dispatch/http/parameters.rb +++ b/actionpack/lib/action_dispatch/http/parameters.rb @@ -65,7 +65,7 @@ module ActionDispatch new_hash = {} params.each do |k, v| - new_key = k.is_a?(String) ? k.dup.force_encoding("UTF-8").encode! : k + new_key = k.is_a?(String) ? k.dup.force_encoding(Encoding::UTF_8).encode! : k new_hash[new_key] = case v when Hash diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/layout.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/layout.erb index 891c87ac27..bc5d03dc10 100644 --- a/actionpack/lib/action_dispatch/middleware/templates/rescues/layout.erb +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/layout.erb @@ -34,6 +34,12 @@ padding: 0.5em 1.5em; } + h1 { + margin: 0.2em 0; + line-height: 1.1em; + font-size: 2em; + } + h2 { color: #C52F24; line-height: 25px; diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb index 693b6bdfcc..3a6f449eb8 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb @@ -155,7 +155,7 @@ module ActionView # ==== Examples # # favicon_link_tag '/myicon.ico' - # # => <link href="/assets/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon" /> + # # => <link href="/assets/myicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon" /> # # Mobile Safari looks for a different <link> tag, pointing to an image that # will be used if you add the page to the home screen of an iPod Touch, iPhone, or iPad. diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb index 719c9c09b5..ad26505086 100644 --- a/actionpack/lib/action_view/helpers/form_options_helper.rb +++ b/actionpack/lib/action_view/helpers/form_options_helper.rb @@ -515,7 +515,6 @@ module ActionView divider = options[:divider] else prompt = options - options = {} message = "Passing the prompt to grouped_options_for_select as an argument is deprecated. " \ "Please use an options hash like `{ prompt: #{prompt.inspect} }`." ActiveSupport::Deprecation.warn message diff --git a/actionpack/lib/action_view/lookup_context.rb b/actionpack/lib/action_view/lookup_context.rb index d61cc0f304..f9d5b97fe3 100644 --- a/actionpack/lib/action_view/lookup_context.rb +++ b/actionpack/lib/action_view/lookup_context.rb @@ -1,5 +1,6 @@ require 'thread_safe' require 'active_support/core_ext/module/remove_method' +require 'active_support/core_ext/module/attribute_accessors' module ActionView # = Action View Lookup Context diff --git a/activemodel/lib/active_model/attribute_methods.rb b/activemodel/lib/active_model/attribute_methods.rb index 5db898b33a..98cde8ba59 100644 --- a/activemodel/lib/active_model/attribute_methods.rb +++ b/activemodel/lib/active_model/attribute_methods.rb @@ -343,7 +343,7 @@ module ActiveModel # significantly (in our case our test suite finishes 10% faster with # this cache). def attribute_method_matchers_cache #:nodoc: - @attribute_method_matchers_cache ||= ThreadSafe::Cache.new(:initial_capacity => 4) + @attribute_method_matchers_cache ||= ThreadSafe::Cache.new(initial_capacity: 4) end def attribute_method_matcher(method_name) #:nodoc: diff --git a/activemodel/lib/active_model/callbacks.rb b/activemodel/lib/active_model/callbacks.rb index b5562dda2e..16188aec6b 100644 --- a/activemodel/lib/active_model/callbacks.rb +++ b/activemodel/lib/active_model/callbacks.rb @@ -100,10 +100,10 @@ module ActiveModel def define_model_callbacks(*callbacks) options = callbacks.extract_options! options = { - :terminator => "result == false", - :skip_after_callbacks_if_terminated => true, - :scope => [:kind, :name], - :only => [:before, :around, :after] + terminator: "result == false", + skip_after_callbacks_if_terminated: true, + scope: [:kind, :name], + only: [:before, :around, :after] }.merge!(options) types = Array(options.delete(:only)) diff --git a/activemodel/lib/active_model/dirty.rb b/activemodel/lib/active_model/dirty.rb index 789bdd74bf..cafdb946c0 100644 --- a/activemodel/lib/active_model/dirty.rb +++ b/activemodel/lib/active_model/dirty.rb @@ -91,7 +91,7 @@ module ActiveModel included do attribute_method_suffix '_changed?', '_change', '_will_change!', '_was' - attribute_method_affix :prefix => 'reset_', :suffix => '!' + attribute_method_affix prefix: 'reset_', suffix: '!' end # Returns +true+ if any attribute have unsaved changes, +false+ otherwise. diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb index b60458b3c6..0d7efab04b 100644 --- a/activemodel/lib/active_model/errors.rb +++ b/activemodel/lib/active_model/errors.rb @@ -231,7 +231,7 @@ module ActiveModel # # <error>name must be specified</error> # # </errors> def to_xml(options={}) - to_a.to_xml({ :root => "errors", :skip_types => true }.merge!(options)) + to_a.to_xml({ root: "errors", skip_types: true }.merge!(options)) end # Returns a Hash that can be used as the JSON representation for this @@ -370,11 +370,11 @@ module ActiveModel def full_message(attribute, message) return message if attribute == :base attr_name = attribute.to_s.tr('.', '_').humanize - attr_name = @base.class.human_attribute_name(attribute, :default => attr_name) + attr_name = @base.class.human_attribute_name(attribute, default: attr_name) I18n.t(:"errors.format", { - :default => "%{attribute} %{message}", - :attribute => attr_name, - :message => message + default: "%{attribute} %{message}", + attribute: attr_name, + message: message }) end @@ -426,10 +426,10 @@ module ActiveModel value = (attribute != :base ? @base.send(:read_attribute_for_validation, attribute) : nil) options = { - :default => defaults, - :model => @base.class.model_name.human, - :attribute => @base.class.human_attribute_name(attribute), - :value => value + default: defaults, + model: @base.class.model_name.human, + attribute: @base.class.human_attribute_name(attribute), + value: value }.merge!(options) I18n.translate(key, options) diff --git a/activemodel/lib/active_model/naming.rb b/activemodel/lib/active_model/naming.rb index 6887f6d781..bc9edf4a56 100644 --- a/activemodel/lib/active_model/naming.rb +++ b/activemodel/lib/active_model/naming.rb @@ -129,7 +129,7 @@ module ActiveModel # # Equivalent to +to_s+. delegate :==, :===, :<=>, :=~, :"!~", :eql?, :to_s, - :to_str, :to => :name + :to_str, to: :name # Returns a new ActiveModel::Name instance. By default, the +namespace+ # and +name+ option will take the namespace and name of the given class @@ -183,7 +183,7 @@ module ActiveModel defaults << options[:default] if options[:default] defaults << @human - options = { :scope => [@klass.i18n_scope, :models], :count => 1, :default => defaults }.merge!(options.except(:default)) + options = { scope: [@klass.i18n_scope, :models], count: 1, default: defaults }.merge!(options.except(:default)) I18n.translate(defaults.shift, options) end diff --git a/activemodel/lib/active_model/secure_password.rb b/activemodel/lib/active_model/secure_password.rb index de8a641924..750fd723a0 100644 --- a/activemodel/lib/active_model/secure_password.rb +++ b/activemodel/lib/active_model/secure_password.rb @@ -57,7 +57,7 @@ module ActiveModel if options.fetch(:validations, true) validates_confirmation_of :password - validates_presence_of :password, :on => :create + validates_presence_of :password, on: :create before_create { raise "Password digest missing on new record" if password_digest.blank? } end diff --git a/activemodel/lib/active_model/serializers/xml.rb b/activemodel/lib/active_model/serializers/xml.rb index 648ae7ce3d..2803f69b6f 100644 --- a/activemodel/lib/active_model/serializers/xml.rb +++ b/activemodel/lib/active_model/serializers/xml.rb @@ -79,7 +79,7 @@ module ActiveModel require 'builder' unless defined? ::Builder options[:indent] ||= 2 - options[:builder] ||= ::Builder::XmlMarkup.new(:indent => options[:indent]) + options[:builder] ||= ::Builder::XmlMarkup.new(indent: options[:indent]) @builder = options[:builder] @builder.instruct! unless options[:skip_instruct] @@ -88,8 +88,8 @@ module ActiveModel root = ActiveSupport::XmlMini.rename_key(root, options) args = [root] - args << {:xmlns => options[:namespace]} if options[:namespace] - args << {:type => options[:type]} if options[:type] && !options[:skip_types] + args << { xmlns: options[:namespace] } if options[:namespace] + args << { type: options[:type] } if options[:type] && !options[:skip_types] @builder.tag!(*args) do add_attributes_and_methods @@ -132,7 +132,7 @@ module ActiveModel records = records.to_ary tag = ActiveSupport::XmlMini.rename_key(association.to_s, options) - type = options[:skip_types] ? { } : {:type => "array"} + type = options[:skip_types] ? { } : { type: "array" } association_name = association.to_s.singularize merged_options[:root] = association_name @@ -145,7 +145,7 @@ module ActiveModel record_type = {} else record_class = (record.class.to_s.underscore == association_name) ? nil : record.class.name - record_type = {:type => record_class} + record_type = { type: record_class } end record.to_xml merged_options.merge(record_type) diff --git a/activemodel/lib/active_model/translation.rb b/activemodel/lib/active_model/translation.rb index 0d098ba93d..8470915abb 100644 --- a/activemodel/lib/active_model/translation.rb +++ b/activemodel/lib/active_model/translation.rb @@ -41,7 +41,7 @@ module ActiveModel # # Specify +options+ with additional translating options. def human_attribute_name(attribute, options = {}) - options = { :count => 1 }.merge!(options) + options = { count: 1 }.merge!(options) parts = attribute.to_s.split(".") attribute = parts.pop namespace = parts.join("/") unless parts.empty? diff --git a/activemodel/lib/active_model/validations.rb b/activemodel/lib/active_model/validations.rb index 714cc95b9a..92206450d2 100644 --- a/activemodel/lib/active_model/validations.rb +++ b/activemodel/lib/active_model/validations.rb @@ -46,7 +46,7 @@ module ActiveModel include HelperMethods attr_accessor :validation_context - define_callbacks :validate, :scope => :name + define_callbacks :validate, scope: :name class_attribute :_validators self._validators = Hash.new { |h,k| h[k] = [] } diff --git a/activemodel/lib/active_model/validations/acceptance.rb b/activemodel/lib/active_model/validations/acceptance.rb index 0935ad0d2a..78e6f67a47 100644 --- a/activemodel/lib/active_model/validations/acceptance.rb +++ b/activemodel/lib/active_model/validations/acceptance.rb @@ -3,7 +3,7 @@ module ActiveModel module Validations class AcceptanceValidator < EachValidator # :nodoc: def initialize(options) - super({ :allow_nil => true, :accept => "1" }.merge!(options)) + super({ allow_nil: true, accept: "1" }.merge!(options)) end def validate_each(record, attribute, value) diff --git a/activemodel/lib/active_model/validations/callbacks.rb b/activemodel/lib/active_model/validations/callbacks.rb index e28ad2841b..8de36b4f8b 100644 --- a/activemodel/lib/active_model/validations/callbacks.rb +++ b/activemodel/lib/active_model/validations/callbacks.rb @@ -22,7 +22,7 @@ module ActiveModel included do include ActiveSupport::Callbacks - define_callbacks :validation, :terminator => "result == false", :skip_after_callbacks_if_terminated => true, :scope => [:kind, :name] + define_callbacks :validation, terminator: "result == false", skip_after_callbacks_if_terminated: true, scope: [:kind, :name] end module ClassMethods diff --git a/activemodel/lib/active_model/validations/confirmation.rb b/activemodel/lib/active_model/validations/confirmation.rb index d14fb4dc53..1d85378892 100644 --- a/activemodel/lib/active_model/validations/confirmation.rb +++ b/activemodel/lib/active_model/validations/confirmation.rb @@ -5,7 +5,7 @@ module ActiveModel def validate_each(record, attribute, value) if (confirmed = record.send("#{attribute}_confirmation")) && (value != confirmed) human_attribute_name = record.class.human_attribute_name(attribute) - record.errors.add(:"#{attribute}_confirmation", :confirmation, options.merge(:attribute => human_attribute_name)) + record.errors.add(:"#{attribute}_confirmation", :confirmation, options.merge(attribute: human_attribute_name)) end end diff --git a/activemodel/lib/active_model/validations/exclusion.rb b/activemodel/lib/active_model/validations/exclusion.rb index b7f38e48f5..48bf5cd802 100644 --- a/activemodel/lib/active_model/validations/exclusion.rb +++ b/activemodel/lib/active_model/validations/exclusion.rb @@ -8,7 +8,7 @@ module ActiveModel def validate_each(record, attribute, value) if include?(record, value) - record.errors.add(attribute, :exclusion, options.except(:in, :within).merge!(:value => value)) + record.errors.add(attribute, :exclusion, options.except(:in, :within).merge!(value: value)) end end end diff --git a/activemodel/lib/active_model/validations/format.rb b/activemodel/lib/active_model/validations/format.rb index 9398b7e66e..be7cae588f 100644 --- a/activemodel/lib/active_model/validations/format.rb +++ b/activemodel/lib/active_model/validations/format.rb @@ -29,7 +29,7 @@ module ActiveModel end def record_error(record, attribute, name, value) - record.errors.add(attribute, :invalid, options.except(name).merge!(:value => value)) + record.errors.add(attribute, :invalid, options.except(name).merge!(value: value)) end def regexp_using_multiline_anchors?(regexp) diff --git a/activemodel/lib/active_model/validations/inclusion.rb b/activemodel/lib/active_model/validations/inclusion.rb index 5e45a04c2c..1cfd86efee 100644 --- a/activemodel/lib/active_model/validations/inclusion.rb +++ b/activemodel/lib/active_model/validations/inclusion.rb @@ -8,7 +8,7 @@ module ActiveModel def validate_each(record, attribute, value) unless include?(record, value) - record.errors.add(attribute, :inclusion, options.except(:in, :within).merge!(:value => value)) + record.errors.add(attribute, :inclusion, options.except(:in, :within).merge!(value: value)) end end end diff --git a/activemodel/lib/active_model/validations/length.rb b/activemodel/lib/active_model/validations/length.rb index 675fb5f1e5..ddfd8a342e 100644 --- a/activemodel/lib/active_model/validations/length.rb +++ b/activemodel/lib/active_model/validations/length.rb @@ -3,8 +3,8 @@ module ActiveModel # == Active \Model Length \Validator module Validations class LengthValidator < EachValidator # :nodoc: - MESSAGES = { :is => :wrong_length, :minimum => :too_short, :maximum => :too_long }.freeze - CHECKS = { :is => :==, :minimum => :>=, :maximum => :<= }.freeze + MESSAGES = { is: :wrong_length, minimum: :too_short, maximum: :too_long }.freeze + CHECKS = { is: :==, minimum: :>=, maximum: :<= }.freeze RESERVED_OPTIONS = [:minimum, :maximum, :within, :is, :tokenizer, :too_short, :too_long] diff --git a/activemodel/lib/active_model/validations/numericality.rb b/activemodel/lib/active_model/validations/numericality.rb index 085532c35b..c6abe45f4a 100644 --- a/activemodel/lib/active_model/validations/numericality.rb +++ b/activemodel/lib/active_model/validations/numericality.rb @@ -2,9 +2,9 @@ module ActiveModel module Validations class NumericalityValidator < EachValidator # :nodoc: - CHECKS = { :greater_than => :>, :greater_than_or_equal_to => :>=, - :equal_to => :==, :less_than => :<, :less_than_or_equal_to => :<=, - :odd => :odd?, :even => :even?, :other_than => :!= }.freeze + CHECKS = { greater_than: :>, greater_than_or_equal_to: :>=, + equal_to: :==, less_than: :<, less_than_or_equal_to: :<=, + odd: :odd?, even: :even?, other_than: :!= }.freeze RESERVED_OPTIONS = CHECKS.keys + [:only_integer] @@ -47,7 +47,7 @@ module ActiveModel option_value = record.send(option_value) if option_value.is_a?(Symbol) unless value.send(CHECKS[option], option_value) - record.errors.add(attr_name, option, filtered_options(value).merge(:count => option_value)) + record.errors.add(attr_name, option, filtered_options(value).merge(count: option_value)) end end end @@ -73,7 +73,7 @@ module ActiveModel end def filtered_options(value) - options.except(*RESERVED_OPTIONS).merge!(:value => value) + options.except(*RESERVED_OPTIONS).merge!(value: value) end end diff --git a/activemodel/lib/active_model/validations/validates.rb b/activemodel/lib/active_model/validations/validates.rb index 1eb0716891..9a1ff2ad39 100644 --- a/activemodel/lib/active_model/validations/validates.rb +++ b/activemodel/lib/active_model/validations/validates.rb @@ -159,9 +159,9 @@ module ActiveModel when Hash options when Range, Array - { :in => options } + { in: options } else - { :with => options } + { with: options } end end end diff --git a/activemodel/test/cases/attribute_methods_test.rb b/activemodel/test/cases/attribute_methods_test.rb index d3ec78157c..25eb4860e3 100644 --- a/activemodel/test/cases/attribute_methods_test.rb +++ b/activemodel/test/cases/attribute_methods_test.rb @@ -10,7 +10,7 @@ class ModelWithAttributes end def attributes - { :foo => 'value of foo', :baz => 'value of baz' } + { foo: 'value of foo', baz: 'value of baz' } end private @@ -80,7 +80,7 @@ class ModelWithRubyKeywordNamedAttributes include ActiveModel::AttributeMethods def attributes - { :begin => 'value of begin', :end => 'value of end' } + { begin: 'value of begin', end: 'value of end' } end private diff --git a/activemodel/test/cases/callbacks_test.rb b/activemodel/test/cases/callbacks_test.rb index c4c34b0be7..5fede098d1 100644 --- a/activemodel/test/cases/callbacks_test.rb +++ b/activemodel/test/cases/callbacks_test.rb @@ -15,9 +15,9 @@ class CallbacksTest < ActiveModel::TestCase extend ActiveModel::Callbacks define_model_callbacks :create - define_model_callbacks :initialize, :only => :after - define_model_callbacks :multiple, :only => [:before, :around] - define_model_callbacks :empty, :only => [] + define_model_callbacks :initialize, only: :after + define_model_callbacks :multiple, only: [:before, :around] + define_model_callbacks :empty, only: [] before_create :before_create around_create CallbackValidator.new diff --git a/activemodel/test/cases/conversion_test.rb b/activemodel/test/cases/conversion_test.rb index a037666cbc..3bb177591d 100644 --- a/activemodel/test/cases/conversion_test.rb +++ b/activemodel/test/cases/conversion_test.rb @@ -13,7 +13,7 @@ class ConversionTest < ActiveModel::TestCase end test "to_key default implementation returns the id in an array for persisted records" do - assert_equal [1], Contact.new(:id => 1).to_key + assert_equal [1], Contact.new(id: 1).to_key end test "to_param default implementation returns nil for new records" do @@ -21,7 +21,7 @@ class ConversionTest < ActiveModel::TestCase end test "to_param default implementation returns a string of ids for persisted records" do - assert_equal "1", Contact.new(:id => 1).to_param + assert_equal "1", Contact.new(id: 1).to_param end test "to_partial_path default implementation returns a string giving a relative path" do diff --git a/activemodel/test/cases/errors_test.rb b/activemodel/test/cases/errors_test.rb index 80ff97d03b..4e07e0e00b 100644 --- a/activemodel/test/cases/errors_test.rb +++ b/activemodel/test/cases/errors_test.rb @@ -271,8 +271,8 @@ class ErrorsTest < ActiveModel::TestCase test "add_on_empty generates message with custom default message" do person = Person.new - person.errors.expects(:generate_message).with(:name, :empty, {:message => 'custom'}) - person.errors.add_on_empty :name, :message => 'custom' + person.errors.expects(:generate_message).with(:name, :empty, { message: 'custom' }) + person.errors.add_on_empty :name, message: 'custom' end test "add_on_empty generates message with empty string value" do @@ -297,7 +297,7 @@ class ErrorsTest < ActiveModel::TestCase test "add_on_blank generates message with custom default message" do person = Person.new - person.errors.expects(:generate_message).with(:name, :blank, {:message => 'custom'}) - person.errors.add_on_blank :name, :message => 'custom' + person.errors.expects(:generate_message).with(:name, :blank, { message: 'custom' }) + person.errors.add_on_blank :name, message: 'custom' end end diff --git a/activemodel/test/cases/model_test.rb b/activemodel/test/cases/model_test.rb index 588d8e661e..24e4ca91c6 100644 --- a/activemodel/test/cases/model_test.rb +++ b/activemodel/test/cases/model_test.rb @@ -13,7 +13,7 @@ class ModelTest < ActiveModel::TestCase end def test_initialize_with_params - object = BasicModel.new(:attr => "value") + object = BasicModel.new(attr: "value") assert_equal object.attr, "value" end @@ -26,7 +26,7 @@ class ModelTest < ActiveModel::TestCase end def test_persisted_is_always_false - object = BasicModel.new(:attr => "value") + object = BasicModel.new(attr: "value") assert object.persisted? == false end end diff --git a/activemodel/test/cases/serialization_test.rb b/activemodel/test/cases/serialization_test.rb index d2ba9fd95d..4ae41aa19c 100644 --- a/activemodel/test/cases/serialization_test.rb +++ b/activemodel/test/cases/serialization_test.rb @@ -49,32 +49,32 @@ class SerializationTest < ActiveModel::TestCase def test_method_serializable_hash_should_work_with_only_option expected = {"name"=>"David"} - assert_equal expected, @user.serializable_hash(:only => [:name]) + assert_equal expected, @user.serializable_hash(only: [:name]) end def test_method_serializable_hash_should_work_with_except_option expected = {"gender"=>"male", "email"=>"david@example.com"} - assert_equal expected, @user.serializable_hash(:except => [:name]) + assert_equal expected, @user.serializable_hash(except: [:name]) end def test_method_serializable_hash_should_work_with_methods_option expected = {"name"=>"David", "gender"=>"male", "foo"=>"i_am_foo", "email"=>"david@example.com"} - assert_equal expected, @user.serializable_hash(:methods => [:foo]) + assert_equal expected, @user.serializable_hash(methods: [:foo]) end def test_method_serializable_hash_should_work_with_only_and_methods expected = {"foo"=>"i_am_foo"} - assert_equal expected, @user.serializable_hash(:only => [], :methods => [:foo]) + assert_equal expected, @user.serializable_hash(only: [], methods: [:foo]) end def test_method_serializable_hash_should_work_with_except_and_methods expected = {"gender"=>"male", "foo"=>"i_am_foo"} - assert_equal expected, @user.serializable_hash(:except => [:name, :email], :methods => [:foo]) + assert_equal expected, @user.serializable_hash(except: [:name, :email], methods: [:foo]) end def test_should_not_call_methods_that_dont_respond expected = {"name"=>"David", "gender"=>"male", "email"=>"david@example.com"} - assert_equal expected, @user.serializable_hash(:methods => [:bar]) + assert_equal expected, @user.serializable_hash(methods: [:bar]) end def test_should_use_read_attribute_for_serialization @@ -83,26 +83,26 @@ class SerializationTest < ActiveModel::TestCase end expected = { "name" => "Jon" } - assert_equal expected, @user.serializable_hash(:only => :name) + assert_equal expected, @user.serializable_hash(only: :name) end def test_include_option_with_singular_association expected = {"name"=>"David", "gender"=>"male", "email"=>"david@example.com", "address"=>{"street"=>"123 Lane", "city"=>"Springfield", "state"=>"CA", "zip"=>11111}} - assert_equal expected, @user.serializable_hash(:include => :address) + assert_equal expected, @user.serializable_hash(include: :address) end def test_include_option_with_plural_association expected = {"email"=>"david@example.com", "gender"=>"male", "name"=>"David", "friends"=>[{"name"=>'Joe', "email"=>'joe@example.com', "gender"=>'male'}, {"name"=>'Sue', "email"=>'sue@example.com', "gender"=>'female'}]} - assert_equal expected, @user.serializable_hash(:include => :friends) + assert_equal expected, @user.serializable_hash(include: :friends) end def test_include_option_with_empty_association @user.friends = [] expected = {"email"=>"david@example.com", "gender"=>"male", "name"=>"David", "friends"=>[]} - assert_equal expected, @user.serializable_hash(:include => :friends) + assert_equal expected, @user.serializable_hash(include: :friends) end class FriendList @@ -120,7 +120,7 @@ class SerializationTest < ActiveModel::TestCase expected = {"email"=>"david@example.com", "gender"=>"male", "name"=>"David", "friends"=>[{"name"=>'Joe', "email"=>'joe@example.com', "gender"=>'male'}, {"name"=>'Sue', "email"=>'sue@example.com', "gender"=>'female'}]} - assert_equal expected, @user.serializable_hash(:include => :friends) + assert_equal expected, @user.serializable_hash(include: :friends) end def test_multiple_includes @@ -128,13 +128,13 @@ class SerializationTest < ActiveModel::TestCase "address"=>{"street"=>"123 Lane", "city"=>"Springfield", "state"=>"CA", "zip"=>11111}, "friends"=>[{"name"=>'Joe', "email"=>'joe@example.com', "gender"=>'male'}, {"name"=>'Sue', "email"=>'sue@example.com', "gender"=>'female'}]} - assert_equal expected, @user.serializable_hash(:include => [:address, :friends]) + assert_equal expected, @user.serializable_hash(include: [:address, :friends]) end def test_include_with_options expected = {"email"=>"david@example.com", "gender"=>"male", "name"=>"David", "address"=>{"street"=>"123 Lane"}} - assert_equal expected, @user.serializable_hash(:include => {:address => {:only => "street"}}) + assert_equal expected, @user.serializable_hash(include: { address: { only: "street" } }) end def test_nested_include @@ -143,19 +143,19 @@ class SerializationTest < ActiveModel::TestCase "friends"=>[{"name"=>'Joe', "email"=>'joe@example.com', "gender"=>'male', "friends"=> [{"email"=>"david@example.com", "gender"=>"male", "name"=>"David"}]}, {"name"=>'Sue', "email"=>'sue@example.com', "gender"=>'female', "friends"=> []}]} - assert_equal expected, @user.serializable_hash(:include => {:friends => {:include => :friends}}) + assert_equal expected, @user.serializable_hash(include: { friends: { include: :friends } }) end def test_only_include expected = {"name"=>"David", "friends" => [{"name" => "Joe"}, {"name" => "Sue"}]} - assert_equal expected, @user.serializable_hash(:only => :name, :include => {:friends => {:only => :name}}) + assert_equal expected, @user.serializable_hash(only: :name, include: { friends: { only: :name } }) end def test_except_include expected = {"name"=>"David", "email"=>"david@example.com", "friends"=> [{"name" => 'Joe', "email" => 'joe@example.com'}, {"name" => "Sue", "email" => 'sue@example.com'}]} - assert_equal expected, @user.serializable_hash(:except => :gender, :include => {:friends => {:except => :gender}}) + assert_equal expected, @user.serializable_hash(except: :gender, include: { friends: { except: :gender } }) end def test_multiple_includes_with_options @@ -163,6 +163,6 @@ class SerializationTest < ActiveModel::TestCase "address"=>{"street"=>"123 Lane"}, "friends"=>[{"name"=>'Joe', "email"=>'joe@example.com', "gender"=>'male'}, {"name"=>'Sue', "email"=>'sue@example.com', "gender"=>'female'}]} - assert_equal expected, @user.serializable_hash(:include => [{:address => {:only => "street"}}, :friends]) + assert_equal expected, @user.serializable_hash(include: [{ address: {only: "street" } }, :friends]) end end diff --git a/activemodel/test/cases/serializers/json_serialization_test.rb b/activemodel/test/cases/serializers/json_serialization_test.rb index 9134c4980c..f0347081ee 100644 --- a/activemodel/test/cases/serializers/json_serialization_test.rb +++ b/activemodel/test/cases/serializers/json_serialization_test.rb @@ -91,7 +91,7 @@ class JsonSerializationTest < ActiveModel::TestCase end test "should allow attribute filtering with only" do - json = @contact.to_json(:only => [:name, :age]) + json = @contact.to_json(only: [:name, :age]) assert_match %r{"name":"Konata Izumi"}, json assert_match %r{"age":16}, json diff --git a/activemodel/test/cases/serializers/xml_serialization_test.rb b/activemodel/test/cases/serializers/xml_serialization_test.rb index 04ecf8a31b..901f42f29b 100644 --- a/activemodel/test/cases/serializers/xml_serialization_test.rb +++ b/activemodel/test/cases/serializers/xml_serialization_test.rb @@ -35,7 +35,7 @@ end class SerializableContact < Contact def serializable_hash(options={}) - super(options.merge(:only => [:name, :age])) + super(options.merge(only: [:name, :age])) end end @@ -70,33 +70,33 @@ class XmlSerializationTest < ActiveModel::TestCase end test "should serialize default root with namespace" do - @xml = @contact.to_xml :namespace => "http://xml.rubyonrails.org/contact" + @xml = @contact.to_xml namespace: "http://xml.rubyonrails.org/contact" assert_match %r{^<contact xmlns="http://xml.rubyonrails.org/contact">}, @xml assert_match %r{</contact>$}, @xml end test "should serialize custom root" do - @xml = @contact.to_xml :root => 'xml_contact' + @xml = @contact.to_xml root: 'xml_contact' assert_match %r{^<xml-contact>}, @xml assert_match %r{</xml-contact>$}, @xml end test "should allow undasherized tags" do - @xml = @contact.to_xml :root => 'xml_contact', :dasherize => false + @xml = @contact.to_xml root: 'xml_contact', dasherize: false assert_match %r{^<xml_contact>}, @xml assert_match %r{</xml_contact>$}, @xml assert_match %r{<created_at}, @xml end test "should allow camelized tags" do - @xml = @contact.to_xml :root => 'xml_contact', :camelize => true + @xml = @contact.to_xml root: 'xml_contact', camelize: true assert_match %r{^<XmlContact>}, @xml assert_match %r{</XmlContact>$}, @xml assert_match %r{<CreatedAt}, @xml end test "should allow lower-camelized tags" do - @xml = @contact.to_xml :root => 'xml_contact', :camelize => :lower + @xml = @contact.to_xml root: 'xml_contact', camelize: :lower assert_match %r{^<xmlContact>}, @xml assert_match %r{</xmlContact>$}, @xml assert_match %r{<createdAt}, @xml @@ -114,7 +114,7 @@ class XmlSerializationTest < ActiveModel::TestCase end test "should allow skipped types" do - @xml = @contact.to_xml :skip_types => true + @xml = @contact.to_xml skip_types: true assert_match %r{<age>25</age>}, @xml end @@ -130,7 +130,7 @@ class XmlSerializationTest < ActiveModel::TestCase end test "should serialize nil" do - assert_match %r{<pseudonyms nil=\"true\"/>}, @contact.to_xml(:methods => :pseudonyms) + assert_match %r{<pseudonyms nil=\"true\"/>}, @contact.to_xml(methods: :pseudonyms) end test "should serialize integer" do @@ -146,11 +146,11 @@ class XmlSerializationTest < ActiveModel::TestCase end test "should serialize array" do - assert_match %r{<social type=\"array\">\s*<social>twitter</social>\s*<social>github</social>\s*</social>}, @contact.to_xml(:methods => :social) + assert_match %r{<social type=\"array\">\s*<social>twitter</social>\s*<social>github</social>\s*</social>}, @contact.to_xml(methods: :social) end test "should serialize hash" do - assert_match %r{<network>\s*<git type=\"symbol\">github</git>\s*</network>}, @contact.to_xml(:methods => :network) + assert_match %r{<network>\s*<git type=\"symbol\">github</git>\s*</network>}, @contact.to_xml(methods: :network) end test "should serialize yaml" do @@ -159,29 +159,29 @@ class XmlSerializationTest < ActiveModel::TestCase test "should call proc on object" do proc = Proc.new { |options| options[:builder].tag!('nationality', 'unknown') } - xml = @contact.to_xml(:procs => [ proc ]) + xml = @contact.to_xml(procs: [ proc ]) assert_match %r{<nationality>unknown</nationality>}, xml end test 'should supply serializable to second proc argument' do proc = Proc.new { |options, record| options[:builder].tag!('name-reverse', record.name.reverse) } - xml = @contact.to_xml(:procs => [ proc ]) + xml = @contact.to_xml(procs: [ proc ]) assert_match %r{<name-reverse>kcats noraa</name-reverse>}, xml end test "should serialize string correctly when type passed" do - xml = @contact.to_xml :type => 'Contact' + xml = @contact.to_xml type: 'Contact' assert_match %r{<contact type="Contact">}, xml assert_match %r{<name>aaron stack</name>}, xml end test "include option with singular association" do - xml = @contact.to_xml :include => :address, :indent => 0 - assert xml.include?(@contact.address.to_xml(:indent => 0, :skip_instruct => true)) + xml = @contact.to_xml include: :address, indent: 0 + assert xml.include?(@contact.address.to_xml(indent: 0, skip_instruct: true)) end test "include option with plural association" do - xml = @contact.to_xml :include => :friends, :indent => 0 + xml = @contact.to_xml include: :friends, indent: 0 assert_match %r{<friends type="array">}, xml assert_match %r{<friend type="Contact">}, xml end @@ -198,60 +198,60 @@ class XmlSerializationTest < ActiveModel::TestCase test "include option with ary" do @contact.friends = FriendList.new(@contact.friends) - xml = @contact.to_xml :include => :friends, :indent => 0 + xml = @contact.to_xml include: :friends, indent: 0 assert_match %r{<friends type="array">}, xml assert_match %r{<friend type="Contact">}, xml end test "multiple includes" do - xml = @contact.to_xml :indent => 0, :skip_instruct => true, :include => [ :address, :friends ] - assert xml.include?(@contact.address.to_xml(:indent => 0, :skip_instruct => true)) + xml = @contact.to_xml indent: 0, skip_instruct: true, include: [ :address, :friends ] + assert xml.include?(@contact.address.to_xml(indent: 0, skip_instruct: true)) assert_match %r{<friends type="array">}, xml assert_match %r{<friend type="Contact">}, xml end test "include with options" do - xml = @contact.to_xml :indent => 0, :skip_instruct => true, :include => { :address => { :only => :city } } + xml = @contact.to_xml indent: 0, skip_instruct: true, include: { address: { only: :city } } assert xml.include?(%(><address><city>Springfield</city></address>)) end test "propagates skip_types option to included associations" do - xml = @contact.to_xml :include => :friends, :indent => 0, :skip_types => true + xml = @contact.to_xml include: :friends, indent: 0, skip_types: true assert_match %r{<friends>}, xml assert_match %r{<friend>}, xml end test "propagates skip-types option to included associations and attributes" do - xml = @contact.to_xml :skip_types => true, :include => :address, :indent => 0 + xml = @contact.to_xml skip_types: true, include: :address, indent: 0 assert_match %r{<address>}, xml assert_match %r{<apt-number>}, xml end test "propagates camelize option to included associations and attributes" do - xml = @contact.to_xml :camelize => true, :include => :address, :indent => 0 + xml = @contact.to_xml camelize: true, include: :address, indent: 0 assert_match %r{<Address>}, xml assert_match %r{<AptNumber type="integer">}, xml end test "propagates dasherize option to included associations and attributes" do - xml = @contact.to_xml :dasherize => false, :include => :address, :indent => 0 + xml = @contact.to_xml dasherize: false, include: :address, indent: 0 assert_match %r{<apt_number type="integer">}, xml end test "don't propagate skip_types if skip_types is defined at the included association level" do - xml = @contact.to_xml :skip_types => true, :include => { :address => { :skip_types => false } }, :indent => 0 + xml = @contact.to_xml skip_types: true, include: { address: { skip_types: false } }, indent: 0 assert_match %r{<address>}, xml assert_match %r{<apt-number type="integer">}, xml end test "don't propagate camelize if camelize is defined at the included association level" do - xml = @contact.to_xml :camelize => true, :include => { :address => { :camelize => false } }, :indent => 0 + xml = @contact.to_xml camelize: true, include: { address: { camelize: false } }, indent: 0 assert_match %r{<address>}, xml assert_match %r{<apt-number type="integer">}, xml end test "don't propagate dasherize if dasherize is defined at the included association level" do - xml = @contact.to_xml :dasherize => false, :include => { :address => { :dasherize => true } }, :indent => 0 + xml = @contact.to_xml dasherize: false, include: { address: { dasherize: true } }, indent: 0 assert_match %r{<address>}, xml assert_match %r{<apt-number type="integer">}, xml end diff --git a/activemodel/test/cases/translation_test.rb b/activemodel/test/cases/translation_test.rb index fd833cdd06..deb4e1ed0a 100644 --- a/activemodel/test/cases/translation_test.rb +++ b/activemodel/test/cases/translation_test.rb @@ -8,22 +8,22 @@ class ActiveModelI18nTests < ActiveModel::TestCase end def test_translated_model_attributes - I18n.backend.store_translations 'en', :activemodel => {:attributes => {:person => {:name => 'person name attribute'} } } + I18n.backend.store_translations 'en', activemodel: { attributes: { person: { name: 'person name attribute' } } } assert_equal 'person name attribute', Person.human_attribute_name('name') end def test_translated_model_attributes_with_default - I18n.backend.store_translations 'en', :attributes => { :name => 'name default attribute' } + I18n.backend.store_translations 'en', attributes: { name: 'name default attribute' } assert_equal 'name default attribute', Person.human_attribute_name('name') end def test_translated_model_attributes_using_default_option - assert_equal 'name default attribute', Person.human_attribute_name('name', :default => "name default attribute") + assert_equal 'name default attribute', Person.human_attribute_name('name', default: "name default attribute") end def test_translated_model_attributes_using_default_option_as_symbol - I18n.backend.store_translations 'en', :default_name => 'name default attribute' - assert_equal 'name default attribute', Person.human_attribute_name('name', :default => :default_name) + I18n.backend.store_translations 'en', default_name: 'name default attribute' + assert_equal 'name default attribute', Person.human_attribute_name('name', default: :default_name) end def test_translated_model_attributes_falling_back_to_default @@ -31,71 +31,74 @@ class ActiveModelI18nTests < ActiveModel::TestCase end def test_translated_model_attributes_using_default_option_as_symbol_and_falling_back_to_default - assert_equal 'Name', Person.human_attribute_name('name', :default => :default_name) + assert_equal 'Name', Person.human_attribute_name('name', default: :default_name) end def test_translated_model_attributes_with_symbols - I18n.backend.store_translations 'en', :activemodel => {:attributes => {:person => {:name => 'person name attribute'} } } + I18n.backend.store_translations 'en', activemodel: { attributes: { person: { name: 'person name attribute'} } } assert_equal 'person name attribute', Person.human_attribute_name(:name) end def test_translated_model_attributes_with_ancestor - I18n.backend.store_translations 'en', :activemodel => {:attributes => {:child => {:name => 'child name attribute'} } } + I18n.backend.store_translations 'en', activemodel: { attributes: { child: { name: 'child name attribute'} } } assert_equal 'child name attribute', Child.human_attribute_name('name') end def test_translated_model_attributes_with_ancestors_fallback - I18n.backend.store_translations 'en', :activemodel => {:attributes => {:person => {:name => 'person name attribute'} } } + I18n.backend.store_translations 'en', activemodel: { attributes: { person: { name: 'person name attribute'} } } assert_equal 'person name attribute', Child.human_attribute_name('name') end def test_translated_model_attributes_with_attribute_matching_namespaced_model_name - I18n.backend.store_translations 'en', :activemodel => {:attributes => {:person => {:gender => 'person gender'}, :"person/gender" => {:attribute => 'person gender attribute'}}} + I18n.backend.store_translations 'en', activemodel: { attributes: { + person: { gender: 'person gender'}, + :"person/gender" => { attribute: 'person gender attribute' } + } } assert_equal 'person gender', Person.human_attribute_name('gender') assert_equal 'person gender attribute', Person::Gender.human_attribute_name('attribute') end def test_translated_deeply_nested_model_attributes - I18n.backend.store_translations 'en', :activemodel => {:attributes => {:"person/contacts/addresses" => {:street => 'Deeply Nested Address Street'}}} + I18n.backend.store_translations 'en', activemodel: { attributes: { :"person/contacts/addresses" => { street: 'Deeply Nested Address Street' } } } assert_equal 'Deeply Nested Address Street', Person.human_attribute_name('contacts.addresses.street') end def test_translated_nested_model_attributes - I18n.backend.store_translations 'en', :activemodel => {:attributes => {:"person/addresses" => {:street => 'Person Address Street'}}} + I18n.backend.store_translations 'en', activemodel: { attributes: { :"person/addresses" => { street: 'Person Address Street' } } } assert_equal 'Person Address Street', Person.human_attribute_name('addresses.street') end def test_translated_nested_model_attributes_with_namespace_fallback - I18n.backend.store_translations 'en', :activemodel => {:attributes => {:addresses => {:street => 'Cool Address Street'}}} + I18n.backend.store_translations 'en', activemodel: { attributes: { addresses: { street: 'Cool Address Street' } } } assert_equal 'Cool Address Street', Person.human_attribute_name('addresses.street') end def test_translated_model_names - I18n.backend.store_translations 'en', :activemodel => {:models => {:person => 'person model'} } + I18n.backend.store_translations 'en', activemodel: { models: { person: 'person model' } } assert_equal 'person model', Person.model_name.human end def test_translated_model_names_with_sti - I18n.backend.store_translations 'en', :activemodel => {:models => {:child => 'child model'} } + I18n.backend.store_translations 'en', activemodel: { models: { child: 'child model' } } assert_equal 'child model', Child.model_name.human end def test_translated_model_names_with_ancestors_fallback - I18n.backend.store_translations 'en', :activemodel => {:models => {:person => 'person model'} } + I18n.backend.store_translations 'en', activemodel: { models: { person: 'person model' } } assert_equal 'person model', Child.model_name.human end def test_human_does_not_modify_options - options = { :default => 'person model' } + options = { default: 'person model' } Person.model_name.human(options) - assert_equal({ :default => 'person model' }, options) + assert_equal({ default: 'person model' }, options) end def test_human_attribute_name_does_not_modify_options - options = { :default => 'Cool gender' } + options = { default: 'Cool gender' } Person.human_attribute_name('gender', options) - assert_equal({ :default => 'Cool gender' }, options) + assert_equal({ default: 'Cool gender' }, options) end end diff --git a/activemodel/test/cases/validations/acceptance_validation_test.rb b/activemodel/test/cases/validations/acceptance_validation_test.rb index de04e11258..dc413bef30 100644 --- a/activemodel/test/cases/validations/acceptance_validation_test.rb +++ b/activemodel/test/cases/validations/acceptance_validation_test.rb @@ -30,7 +30,7 @@ class AcceptanceValidationTest < ActiveModel::TestCase end def test_eula - Topic.validates_acceptance_of(:eula, :message => "must be abided") + Topic.validates_acceptance_of(:eula, message: "must be abided") t = Topic.new("title" => "We should be confirmed","eula" => "") assert t.invalid? @@ -41,7 +41,7 @@ class AcceptanceValidationTest < ActiveModel::TestCase end def test_terms_of_service_agreement_with_accept_value - Topic.validates_acceptance_of(:terms_of_service, :accept => "I agree.") + Topic.validates_acceptance_of(:terms_of_service, accept: "I agree.") t = Topic.new("title" => "We should be confirmed", "terms_of_service" => "") assert t.invalid? diff --git a/activemodel/test/cases/validations/conditional_validation_test.rb b/activemodel/test/cases/validations/conditional_validation_test.rb index e06b04af19..41a4c33727 100644 --- a/activemodel/test/cases/validations/conditional_validation_test.rb +++ b/activemodel/test/cases/validations/conditional_validation_test.rb @@ -11,7 +11,7 @@ class ConditionalValidationTest < ActiveModel::TestCase def test_if_validation_using_method_true # When the method returns true - Topic.validates_length_of( :title, :maximum => 5, :too_long => "hoo %{count}", :if => :condition_is_true ) + Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", if: :condition_is_true) t = Topic.new("title" => "uhohuhoh", "content" => "whatever") assert t.invalid? assert t.errors[:title].any? @@ -20,7 +20,7 @@ class ConditionalValidationTest < ActiveModel::TestCase def test_unless_validation_using_method_true # When the method returns true - Topic.validates_length_of( :title, :maximum => 5, :too_long => "hoo %{count}", :unless => :condition_is_true ) + Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", unless: :condition_is_true) t = Topic.new("title" => "uhohuhoh", "content" => "whatever") assert t.valid? assert t.errors[:title].empty? @@ -28,7 +28,7 @@ class ConditionalValidationTest < ActiveModel::TestCase def test_if_validation_using_method_false # When the method returns false - Topic.validates_length_of( :title, :maximum => 5, :too_long => "hoo %{count}", :if => :condition_is_true_but_its_not ) + Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", if: :condition_is_true_but_its_not) t = Topic.new("title" => "uhohuhoh", "content" => "whatever") assert t.valid? assert t.errors[:title].empty? @@ -36,7 +36,7 @@ class ConditionalValidationTest < ActiveModel::TestCase def test_unless_validation_using_method_false # When the method returns false - Topic.validates_length_of( :title, :maximum => 5, :too_long => "hoo %{count}", :unless => :condition_is_true_but_its_not ) + Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", unless: :condition_is_true_but_its_not) t = Topic.new("title" => "uhohuhoh", "content" => "whatever") assert t.invalid? assert t.errors[:title].any? @@ -45,7 +45,7 @@ class ConditionalValidationTest < ActiveModel::TestCase def test_if_validation_using_string_true # When the evaluated string returns true - Topic.validates_length_of( :title, :maximum => 5, :too_long => "hoo %{count}", :if => "a = 1; a == 1" ) + Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", if: "a = 1; a == 1") t = Topic.new("title" => "uhohuhoh", "content" => "whatever") assert t.invalid? assert t.errors[:title].any? @@ -54,7 +54,7 @@ class ConditionalValidationTest < ActiveModel::TestCase def test_unless_validation_using_string_true # When the evaluated string returns true - Topic.validates_length_of( :title, :maximum => 5, :too_long => "hoo %{count}", :unless => "a = 1; a == 1" ) + Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", unless: "a = 1; a == 1") t = Topic.new("title" => "uhohuhoh", "content" => "whatever") assert t.valid? assert t.errors[:title].empty? @@ -62,7 +62,7 @@ class ConditionalValidationTest < ActiveModel::TestCase def test_if_validation_using_string_false # When the evaluated string returns false - Topic.validates_length_of( :title, :maximum => 5, :too_long => "hoo %{count}", :if => "false") + Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", if: "false") t = Topic.new("title" => "uhohuhoh", "content" => "whatever") assert t.valid? assert t.errors[:title].empty? @@ -70,7 +70,7 @@ class ConditionalValidationTest < ActiveModel::TestCase def test_unless_validation_using_string_false # When the evaluated string returns false - Topic.validates_length_of( :title, :maximum => 5, :too_long => "hoo %{count}", :unless => "false") + Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", unless: "false") t = Topic.new("title" => "uhohuhoh", "content" => "whatever") assert t.invalid? assert t.errors[:title].any? @@ -79,8 +79,8 @@ class ConditionalValidationTest < ActiveModel::TestCase def test_if_validation_using_block_true # When the block returns true - Topic.validates_length_of( :title, :maximum => 5, :too_long => "hoo %{count}", - :if => Proc.new { |r| r.content.size > 4 } ) + Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", + if: Proc.new { |r| r.content.size > 4 }) t = Topic.new("title" => "uhohuhoh", "content" => "whatever") assert t.invalid? assert t.errors[:title].any? @@ -89,8 +89,8 @@ class ConditionalValidationTest < ActiveModel::TestCase def test_unless_validation_using_block_true # When the block returns true - Topic.validates_length_of( :title, :maximum => 5, :too_long => "hoo %{count}", - :unless => Proc.new { |r| r.content.size > 4 } ) + Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", + unless: Proc.new { |r| r.content.size > 4 }) t = Topic.new("title" => "uhohuhoh", "content" => "whatever") assert t.valid? assert t.errors[:title].empty? @@ -98,8 +98,8 @@ class ConditionalValidationTest < ActiveModel::TestCase def test_if_validation_using_block_false # When the block returns false - Topic.validates_length_of( :title, :maximum => 5, :too_long => "hoo %{count}", - :if => Proc.new { |r| r.title != "uhohuhoh"} ) + Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", + if: Proc.new { |r| r.title != "uhohuhoh"}) t = Topic.new("title" => "uhohuhoh", "content" => "whatever") assert t.valid? assert t.errors[:title].empty? @@ -107,8 +107,8 @@ class ConditionalValidationTest < ActiveModel::TestCase def test_unless_validation_using_block_false # When the block returns false - Topic.validates_length_of( :title, :maximum => 5, :too_long => "hoo %{count}", - :unless => Proc.new { |r| r.title != "uhohuhoh"} ) + Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", + unless: Proc.new { |r| r.title != "uhohuhoh"} ) t = Topic.new("title" => "uhohuhoh", "content" => "whatever") assert t.invalid? assert t.errors[:title].any? @@ -120,7 +120,7 @@ class ConditionalValidationTest < ActiveModel::TestCase # ensure that it works correctly def test_validation_with_if_as_string Topic.validates_presence_of(:title) - Topic.validates_presence_of(:author_name, :if => "title.to_s.match('important')") + Topic.validates_presence_of(:author_name, if: "title.to_s.match('important')") t = Topic.new assert t.invalid?, "A topic without a title should not be valid" diff --git a/activemodel/test/cases/validations/confirmation_validation_test.rb b/activemodel/test/cases/validations/confirmation_validation_test.rb index 814eec3f59..f03de2c24a 100644 --- a/activemodel/test/cases/validations/confirmation_validation_test.rb +++ b/activemodel/test/cases/validations/confirmation_validation_test.rb @@ -13,7 +13,7 @@ class ConfirmationValidationTest < ActiveModel::TestCase def test_no_title_confirmation Topic.validates_confirmation_of(:title) - t = Topic.new(:author_name => "Plutarch") + t = Topic.new(author_name: "Plutarch") assert t.valid? t.title_confirmation = "Parallel Lives" @@ -57,8 +57,8 @@ class ConfirmationValidationTest < ActiveModel::TestCase I18n.load_path.clear I18n.backend = I18n::Backend::Simple.new I18n.backend.store_translations('en', { - :errors => {:messages => {:confirmation => "doesn't match %{attribute}"}}, - :activemodel => {:attributes => {:topic => {:title => 'Test Title'}}} + errors: { messages: { confirmation: "doesn't match %{attribute}" } }, + activemodel: { attributes: { topic: { title: 'Test Title'} } } }) Topic.validates_confirmation_of(:title) diff --git a/activemodel/test/cases/validations/exclusion_validation_test.rb b/activemodel/test/cases/validations/exclusion_validation_test.rb index 7d5af27f3d..81455ba519 100644 --- a/activemodel/test/cases/validations/exclusion_validation_test.rb +++ b/activemodel/test/cases/validations/exclusion_validation_test.rb @@ -11,14 +11,14 @@ class ExclusionValidationTest < ActiveModel::TestCase end def test_validates_exclusion_of - Topic.validates_exclusion_of( :title, :in => %w( abe monkey ) ) + Topic.validates_exclusion_of(:title, in: %w( abe monkey )) assert Topic.new("title" => "something", "content" => "abc").valid? assert Topic.new("title" => "monkey", "content" => "abc").invalid? end def test_validates_exclusion_of_with_formatted_message - Topic.validates_exclusion_of( :title, :in => %w( abe monkey ), :message => "option %{value} is restricted" ) + Topic.validates_exclusion_of(:title, in: %w( abe monkey ), message: "option %{value} is restricted") assert Topic.new("title" => "something", "content" => "abc") @@ -29,7 +29,7 @@ class ExclusionValidationTest < ActiveModel::TestCase end def test_validates_exclusion_of_with_within_option - Topic.validates_exclusion_of( :title, :within => %w( abe monkey ) ) + Topic.validates_exclusion_of(:title, within: %w( abe monkey )) assert Topic.new("title" => "something", "content" => "abc") @@ -39,7 +39,7 @@ class ExclusionValidationTest < ActiveModel::TestCase end def test_validates_exclusion_of_for_ruby_class - Person.validates_exclusion_of :karma, :in => %w( abe monkey ) + Person.validates_exclusion_of :karma, in: %w( abe monkey ) p = Person.new p.karma = "abe" @@ -54,7 +54,7 @@ class ExclusionValidationTest < ActiveModel::TestCase end def test_validates_exclusion_of_with_lambda - Topic.validates_exclusion_of :title, :in => lambda{ |topic| topic.author_name == "sikachu" ? %w( monkey elephant ) : %w( abe wasabi ) } + Topic.validates_exclusion_of :title, in: lambda { |topic| topic.author_name == "sikachu" ? %w( monkey elephant ) : %w( abe wasabi ) } t = Topic.new t.title = "elephant" @@ -66,7 +66,7 @@ class ExclusionValidationTest < ActiveModel::TestCase end def test_validates_inclusion_of_with_symbol - Person.validates_exclusion_of :karma, :in => :reserved_karmas + Person.validates_exclusion_of :karma, in: :reserved_karmas p = Person.new p.karma = "abe" diff --git a/activemodel/test/cases/validations/format_validation_test.rb b/activemodel/test/cases/validations/format_validation_test.rb index 308a3c6cef..26e8dbf19c 100644 --- a/activemodel/test/cases/validations/format_validation_test.rb +++ b/activemodel/test/cases/validations/format_validation_test.rb @@ -11,7 +11,7 @@ class PresenceValidationTest < ActiveModel::TestCase end def test_validate_format - Topic.validates_format_of(:title, :content, :with => /\AValidation\smacros \w+!\z/, :message => "is bad data") + Topic.validates_format_of(:title, :content, with: /\AValidation\smacros \w+!\z/, message: "is bad data") t = Topic.new("title" => "i'm incorrect", "content" => "Validation macros rule!") assert t.invalid?, "Shouldn't be valid" @@ -27,7 +27,7 @@ class PresenceValidationTest < ActiveModel::TestCase end def test_validate_format_with_allow_blank - Topic.validates_format_of(:title, :with => /\AValidation\smacros \w+!\z/, :allow_blank => true) + Topic.validates_format_of(:title, with: /\AValidation\smacros \w+!\z/, allow_blank: true) assert Topic.new("title" => "Shouldn't be valid").invalid? assert Topic.new("title" => "").valid? assert Topic.new("title" => nil).valid? @@ -36,7 +36,7 @@ class PresenceValidationTest < ActiveModel::TestCase # testing ticket #3142 def test_validate_format_numeric - Topic.validates_format_of(:title, :content, :with => /\A[1-9][0-9]*\z/, :message => "is bad data") + Topic.validates_format_of(:title, :content, with: /\A[1-9][0-9]*\z/, message: "is bad data") t = Topic.new("title" => "72x", "content" => "6789") assert t.invalid?, "Shouldn't be valid" @@ -63,24 +63,24 @@ class PresenceValidationTest < ActiveModel::TestCase end def test_validate_format_with_formatted_message - Topic.validates_format_of(:title, :with => /\AValid Title\z/, :message => "can't be %{value}") - t = Topic.new(:title => 'Invalid title') + Topic.validates_format_of(:title, with: /\AValid Title\z/, message: "can't be %{value}") + t = Topic.new(title: 'Invalid title') assert t.invalid? assert_equal ["can't be Invalid title"], t.errors[:title] end def test_validate_format_of_with_multiline_regexp_should_raise_error - assert_raise(ArgumentError) { Topic.validates_format_of(:title, :with => /^Valid Title$/) } + assert_raise(ArgumentError) { Topic.validates_format_of(:title, with: /^Valid Title$/) } end def test_validate_format_of_with_multiline_regexp_and_option assert_nothing_raised(ArgumentError) do - Topic.validates_format_of(:title, :with => /^Valid Title$/, :multiline => true) + Topic.validates_format_of(:title, with: /^Valid Title$/, multiline: true) end end def test_validate_format_with_not_option - Topic.validates_format_of(:title, :without => /foo/, :message => "should not contain foo") + Topic.validates_format_of(:title, without: /foo/, message: "should not contain foo") t = Topic.new t.title = "foobar" @@ -97,19 +97,19 @@ class PresenceValidationTest < ActiveModel::TestCase end def test_validates_format_of_with_both_regexps_should_raise_error - assert_raise(ArgumentError) { Topic.validates_format_of(:title, :with => /this/, :without => /that/) } + assert_raise(ArgumentError) { Topic.validates_format_of(:title, with: /this/, without: /that/) } end def test_validates_format_of_when_with_isnt_a_regexp_should_raise_error - assert_raise(ArgumentError) { Topic.validates_format_of(:title, :with => "clearly not a regexp") } + assert_raise(ArgumentError) { Topic.validates_format_of(:title, with: "clearly not a regexp") } end def test_validates_format_of_when_not_isnt_a_regexp_should_raise_error - assert_raise(ArgumentError) { Topic.validates_format_of(:title, :without => "clearly not a regexp") } + assert_raise(ArgumentError) { Topic.validates_format_of(:title, without: "clearly not a regexp") } end def test_validates_format_of_with_lambda - Topic.validates_format_of :content, :with => lambda{ |topic| topic.title == "digit" ? /\A\d+\Z/ : /\A\S+\Z/ } + Topic.validates_format_of :content, with: lambda { |topic| topic.title == "digit" ? /\A\d+\Z/ : /\A\S+\Z/ } t = Topic.new t.title = "digit" @@ -121,7 +121,7 @@ class PresenceValidationTest < ActiveModel::TestCase end def test_validates_format_of_without_lambda - Topic.validates_format_of :content, :without => lambda{ |topic| topic.title == "characters" ? /\A\d+\Z/ : /\A\S+\Z/ } + Topic.validates_format_of :content, without: lambda { |topic| topic.title == "characters" ? /\A\d+\Z/ : /\A\S+\Z/ } t = Topic.new t.title = "characters" @@ -133,7 +133,7 @@ class PresenceValidationTest < ActiveModel::TestCase end def test_validates_format_of_for_ruby_class - Person.validates_format_of :karma, :with => /\A\d+\Z/ + Person.validates_format_of :karma, with: /\A\d+\Z/ p = Person.new p.karma = "Pixies" diff --git a/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb b/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb index 302cbe9761..40a5aee997 100644 --- a/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb +++ b/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb @@ -10,29 +10,29 @@ class I18nGenerateMessageValidationTest < ActiveModel::TestCase # validates_inclusion_of: generate_message(attr_name, :inclusion, message: custom_message, value: value) def test_generate_message_inclusion_with_default_message - assert_equal 'is not included in the list', @person.errors.generate_message(:title, :inclusion, :value => 'title') + assert_equal 'is not included in the list', @person.errors.generate_message(:title, :inclusion, value: 'title') end def test_generate_message_inclusion_with_custom_message - assert_equal 'custom message title', @person.errors.generate_message(:title, :inclusion, :message => 'custom message %{value}', :value => 'title') + assert_equal 'custom message title', @person.errors.generate_message(:title, :inclusion, message: 'custom message %{value}', value: 'title') end # validates_exclusion_of: generate_message(attr_name, :exclusion, message: custom_message, value: value) def test_generate_message_exclusion_with_default_message - assert_equal 'is reserved', @person.errors.generate_message(:title, :exclusion, :value => 'title') + assert_equal 'is reserved', @person.errors.generate_message(:title, :exclusion, value: 'title') end def test_generate_message_exclusion_with_custom_message - assert_equal 'custom message title', @person.errors.generate_message(:title, :exclusion, :message => 'custom message %{value}', :value => 'title') + assert_equal 'custom message title', @person.errors.generate_message(:title, :exclusion, message: 'custom message %{value}', value: 'title') end # validates_format_of: generate_message(attr_name, :invalid, message: custom_message, value: value) def test_generate_message_invalid_with_default_message - assert_equal 'is invalid', @person.errors.generate_message(:title, :invalid, :value => 'title') + assert_equal 'is invalid', @person.errors.generate_message(:title, :invalid, value: 'title') end def test_generate_message_invalid_with_custom_message - assert_equal 'custom message title', @person.errors.generate_message(:title, :invalid, :message => 'custom message %{value}', :value => 'title') + assert_equal 'custom message title', @person.errors.generate_message(:title, :invalid, message: 'custom message %{value}', value: 'title') end # validates_confirmation_of: generate_message(attr_name, :confirmation, message: custom_message) @@ -41,7 +41,7 @@ class I18nGenerateMessageValidationTest < ActiveModel::TestCase end def test_generate_message_confirmation_with_custom_message - assert_equal 'custom message', @person.errors.generate_message(:title, :confirmation, :message => 'custom message') + assert_equal 'custom message', @person.errors.generate_message(:title, :confirmation, message: 'custom message') end # validates_acceptance_of: generate_message(attr_name, :accepted, message: custom_message) @@ -50,7 +50,7 @@ class I18nGenerateMessageValidationTest < ActiveModel::TestCase end def test_generate_message_accepted_with_custom_message - assert_equal 'custom message', @person.errors.generate_message(:title, :accepted, :message => 'custom message') + assert_equal 'custom message', @person.errors.generate_message(:title, :accepted, message: 'custom message') end # add_on_empty: generate_message(attr, :empty, message: custom_message) @@ -59,7 +59,7 @@ class I18nGenerateMessageValidationTest < ActiveModel::TestCase end def test_generate_message_empty_with_custom_message - assert_equal 'custom message', @person.errors.generate_message(:title, :empty, :message => 'custom message') + assert_equal 'custom message', @person.errors.generate_message(:title, :empty, message: 'custom message') end # add_on_blank: generate_message(attr, :blank, message: custom_message) @@ -68,71 +68,71 @@ class I18nGenerateMessageValidationTest < ActiveModel::TestCase end def test_generate_message_blank_with_custom_message - assert_equal 'custom message', @person.errors.generate_message(:title, :blank, :message => 'custom message') + assert_equal 'custom message', @person.errors.generate_message(:title, :blank, message: 'custom message') end # validates_length_of: generate_message(attr, :too_long, message: custom_message, count: option_value.end) def test_generate_message_too_long_with_default_message - assert_equal "is too long (maximum is 10 characters)", @person.errors.generate_message(:title, :too_long, :count => 10) + assert_equal "is too long (maximum is 10 characters)", @person.errors.generate_message(:title, :too_long, count: 10) end def test_generate_message_too_long_with_custom_message - assert_equal 'custom message 10', @person.errors.generate_message(:title, :too_long, :message => 'custom message %{count}', :count => 10) + assert_equal 'custom message 10', @person.errors.generate_message(:title, :too_long, message: 'custom message %{count}', count: 10) end # validates_length_of: generate_message(attr, :too_short, default: custom_message, count: option_value.begin) def test_generate_message_too_short_with_default_message - assert_equal "is too short (minimum is 10 characters)", @person.errors.generate_message(:title, :too_short, :count => 10) + assert_equal "is too short (minimum is 10 characters)", @person.errors.generate_message(:title, :too_short, count: 10) end def test_generate_message_too_short_with_custom_message - assert_equal 'custom message 10', @person.errors.generate_message(:title, :too_short, :message => 'custom message %{count}', :count => 10) + assert_equal 'custom message 10', @person.errors.generate_message(:title, :too_short, message: 'custom message %{count}', count: 10) end # validates_length_of: generate_message(attr, :wrong_length, message: custom_message, count: option_value) def test_generate_message_wrong_length_with_default_message - assert_equal "is the wrong length (should be 10 characters)", @person.errors.generate_message(:title, :wrong_length, :count => 10) + assert_equal "is the wrong length (should be 10 characters)", @person.errors.generate_message(:title, :wrong_length, count: 10) end def test_generate_message_wrong_length_with_custom_message - assert_equal 'custom message 10', @person.errors.generate_message(:title, :wrong_length, :message => 'custom message %{count}', :count => 10) + assert_equal 'custom message 10', @person.errors.generate_message(:title, :wrong_length, message: 'custom message %{count}', count: 10) end # validates_numericality_of: generate_message(attr_name, :not_a_number, value: raw_value, message: custom_message) def test_generate_message_not_a_number_with_default_message - assert_equal "is not a number", @person.errors.generate_message(:title, :not_a_number, :value => 'title') + assert_equal "is not a number", @person.errors.generate_message(:title, :not_a_number, value: 'title') end def test_generate_message_not_a_number_with_custom_message - assert_equal 'custom message title', @person.errors.generate_message(:title, :not_a_number, :message => 'custom message %{value}', :value => 'title') + assert_equal 'custom message title', @person.errors.generate_message(:title, :not_a_number, message: 'custom message %{value}', value: 'title') end # validates_numericality_of: generate_message(attr_name, option, value: raw_value, default: custom_message) def test_generate_message_greater_than_with_default_message - assert_equal "must be greater than 10", @person.errors.generate_message(:title, :greater_than, :value => 'title', :count => 10) + assert_equal "must be greater than 10", @person.errors.generate_message(:title, :greater_than, value: 'title', count: 10) end def test_generate_message_greater_than_or_equal_to_with_default_message - assert_equal "must be greater than or equal to 10", @person.errors.generate_message(:title, :greater_than_or_equal_to, :value => 'title', :count => 10) + assert_equal "must be greater than or equal to 10", @person.errors.generate_message(:title, :greater_than_or_equal_to, value: 'title', count: 10) end def test_generate_message_equal_to_with_default_message - assert_equal "must be equal to 10", @person.errors.generate_message(:title, :equal_to, :value => 'title', :count => 10) + assert_equal "must be equal to 10", @person.errors.generate_message(:title, :equal_to, value: 'title', count: 10) end def test_generate_message_less_than_with_default_message - assert_equal "must be less than 10", @person.errors.generate_message(:title, :less_than, :value => 'title', :count => 10) + assert_equal "must be less than 10", @person.errors.generate_message(:title, :less_than, value: 'title', count: 10) end def test_generate_message_less_than_or_equal_to_with_default_message - assert_equal "must be less than or equal to 10", @person.errors.generate_message(:title, :less_than_or_equal_to, :value => 'title', :count => 10) + assert_equal "must be less than or equal to 10", @person.errors.generate_message(:title, :less_than_or_equal_to, value: 'title', count: 10) end def test_generate_message_odd_with_default_message - assert_equal "must be odd", @person.errors.generate_message(:title, :odd, :value => 'title', :count => 10) + assert_equal "must be odd", @person.errors.generate_message(:title, :odd, value: 'title', count: 10) end def test_generate_message_even_with_default_message - assert_equal "must be even", @person.errors.generate_message(:title, :even, :value => 'title', :count => 10) + assert_equal "must be even", @person.errors.generate_message(:title, :even, value: 'title', count: 10) end end diff --git a/activemodel/test/cases/validations/i18n_validation_test.rb b/activemodel/test/cases/validations/i18n_validation_test.rb index 4c01b47608..e29771d6b7 100644 --- a/activemodel/test/cases/validations/i18n_validation_test.rb +++ b/activemodel/test/cases/validations/i18n_validation_test.rb @@ -12,7 +12,7 @@ class I18nValidationTest < ActiveModel::TestCase @old_load_path, @old_backend = I18n.load_path.dup, I18n.backend I18n.load_path.clear I18n.backend = I18n::Backend::Simple.new - I18n.backend.store_translations('en', :errors => {:messages => {:custom => nil}}) + I18n.backend.store_translations('en', errors: { messages: { custom: nil } }) end def teardown @@ -22,21 +22,21 @@ class I18nValidationTest < ActiveModel::TestCase end def test_full_message_encoding - I18n.backend.store_translations('en', :errors => { - :messages => { :too_short => '猫舌' }}) - Person.validates_length_of :title, :within => 3..5 + I18n.backend.store_translations('en', errors: { + messages: { too_short: '猫舌' } }) + Person.validates_length_of :title, within: 3..5 @person.valid? assert_equal ['Title 猫舌'], @person.errors.full_messages end def test_errors_full_messages_translates_human_attribute_name_for_model_attributes @person.errors.add(:name, 'not found') - Person.expects(:human_attribute_name).with(:name, :default => 'Name').returns("Person's name") + Person.expects(:human_attribute_name).with(:name, default: 'Name').returns("Person's name") assert_equal ["Person's name not found"], @person.errors.full_messages end def test_errors_full_messages_uses_format - I18n.backend.store_translations('en', :errors => {:format => "Field %{attribute} %{message}"}) + I18n.backend.store_translations('en', errors: { format: "Field %{attribute} %{message}" }) @person.errors.add('name', 'empty') assert_equal ["Field Name empty"], @person.errors.full_messages end @@ -49,10 +49,10 @@ class I18nValidationTest < ActiveModel::TestCase COMMON_CASES = [ # [ case, validation_options, generate_message_options] [ "given no options", {}, {}], - [ "given custom message", {:message => "custom"}, {:message => "custom"}], - [ "given if condition", {:if => lambda { true }}, {}], - [ "given unless condition", {:unless => lambda { false }}, {}], - [ "given option that is not reserved", {:format => "jpg"}, {:format => "jpg" }] + [ "given custom message", { message: "custom" }, { message: "custom" }], + [ "given if condition", { if: lambda { true }}, {}], + [ "given unless condition", { unless: lambda { false }}, {}], + [ "given option that is not reserved", { format: "jpg" }, { format: "jpg" }] ] # validates_confirmation_of w/ mocha @@ -61,7 +61,7 @@ class I18nValidationTest < ActiveModel::TestCase test "validates_confirmation_of on generated message #{name}" do Person.validates_confirmation_of :title, validation_options @person.title_confirmation = 'foo' - @person.errors.expects(:generate_message).with(:title_confirmation, :confirmation, generate_message_options.merge(:attribute => 'Title')) + @person.errors.expects(:generate_message).with(:title_confirmation, :confirmation, generate_message_options.merge(attribute: 'Title')) @person.valid? end end @@ -70,7 +70,7 @@ class I18nValidationTest < ActiveModel::TestCase COMMON_CASES.each do |name, validation_options, generate_message_options| test "validates_acceptance_of on generated message #{name}" do - Person.validates_acceptance_of :title, validation_options.merge(:allow_nil => false) + Person.validates_acceptance_of :title, validation_options.merge(allow_nil: false) @person.errors.expects(:generate_message).with(:title, :accepted, generate_message_options) @person.valid? end @@ -90,8 +90,8 @@ class I18nValidationTest < ActiveModel::TestCase COMMON_CASES.each do |name, validation_options, generate_message_options| test "validates_length_of for :withing on generated message when too short #{name}" do - Person.validates_length_of :title, validation_options.merge(:within => 3..5) - @person.errors.expects(:generate_message).with(:title, :too_short, generate_message_options.merge(:count => 3)) + Person.validates_length_of :title, validation_options.merge(within: 3..5) + @person.errors.expects(:generate_message).with(:title, :too_short, generate_message_options.merge(count: 3)) @person.valid? end end @@ -100,9 +100,9 @@ class I18nValidationTest < ActiveModel::TestCase COMMON_CASES.each do |name, validation_options, generate_message_options| test "validates_length_of for :too_long generated message #{name}" do - Person.validates_length_of :title, validation_options.merge(:within => 3..5) + Person.validates_length_of :title, validation_options.merge(within: 3..5) @person.title = 'this title is too long' - @person.errors.expects(:generate_message).with(:title, :too_long, generate_message_options.merge(:count => 5)) + @person.errors.expects(:generate_message).with(:title, :too_long, generate_message_options.merge(count: 5)) @person.valid? end end @@ -111,8 +111,8 @@ class I18nValidationTest < ActiveModel::TestCase COMMON_CASES.each do |name, validation_options, generate_message_options| test "validates_length_of for :is on generated message #{name}" do - Person.validates_length_of :title, validation_options.merge(:is => 5) - @person.errors.expects(:generate_message).with(:title, :wrong_length, generate_message_options.merge(:count => 5)) + Person.validates_length_of :title, validation_options.merge(is: 5) + @person.errors.expects(:generate_message).with(:title, :wrong_length, generate_message_options.merge(count: 5)) @person.valid? end end @@ -121,9 +121,9 @@ class I18nValidationTest < ActiveModel::TestCase COMMON_CASES.each do |name, validation_options, generate_message_options| test "validates_format_of on generated message #{name}" do - Person.validates_format_of :title, validation_options.merge(:with => /\A[1-9][0-9]*\z/) + Person.validates_format_of :title, validation_options.merge(with: /\A[1-9][0-9]*\z/) @person.title = '72x' - @person.errors.expects(:generate_message).with(:title, :invalid, generate_message_options.merge(:value => '72x')) + @person.errors.expects(:generate_message).with(:title, :invalid, generate_message_options.merge(value: '72x')) @person.valid? end end @@ -132,9 +132,9 @@ class I18nValidationTest < ActiveModel::TestCase COMMON_CASES.each do |name, validation_options, generate_message_options| test "validates_inclusion_of on generated message #{name}" do - Person.validates_inclusion_of :title, validation_options.merge(:in => %w(a b c)) + Person.validates_inclusion_of :title, validation_options.merge(in: %w(a b c)) @person.title = 'z' - @person.errors.expects(:generate_message).with(:title, :inclusion, generate_message_options.merge(:value => 'z')) + @person.errors.expects(:generate_message).with(:title, :inclusion, generate_message_options.merge(value: 'z')) @person.valid? end end @@ -143,9 +143,9 @@ class I18nValidationTest < ActiveModel::TestCase COMMON_CASES.each do |name, validation_options, generate_message_options| test "validates_inclusion_of using :within on generated message #{name}" do - Person.validates_inclusion_of :title, validation_options.merge(:within => %w(a b c)) + Person.validates_inclusion_of :title, validation_options.merge(within: %w(a b c)) @person.title = 'z' - @person.errors.expects(:generate_message).with(:title, :inclusion, generate_message_options.merge(:value => 'z')) + @person.errors.expects(:generate_message).with(:title, :inclusion, generate_message_options.merge(value: 'z')) @person.valid? end end @@ -154,9 +154,9 @@ class I18nValidationTest < ActiveModel::TestCase COMMON_CASES.each do |name, validation_options, generate_message_options| test "validates_exclusion_of generated message #{name}" do - Person.validates_exclusion_of :title, validation_options.merge(:in => %w(a b c)) + Person.validates_exclusion_of :title, validation_options.merge(in: %w(a b c)) @person.title = 'a' - @person.errors.expects(:generate_message).with(:title, :exclusion, generate_message_options.merge(:value => 'a')) + @person.errors.expects(:generate_message).with(:title, :exclusion, generate_message_options.merge(value: 'a')) @person.valid? end end @@ -165,9 +165,9 @@ class I18nValidationTest < ActiveModel::TestCase COMMON_CASES.each do |name, validation_options, generate_message_options| test "validates_exclusion_of using :within generated message #{name}" do - Person.validates_exclusion_of :title, validation_options.merge(:within => %w(a b c)) + Person.validates_exclusion_of :title, validation_options.merge(within: %w(a b c)) @person.title = 'a' - @person.errors.expects(:generate_message).with(:title, :exclusion, generate_message_options.merge(:value => 'a')) + @person.errors.expects(:generate_message).with(:title, :exclusion, generate_message_options.merge(value: 'a')) @person.valid? end end @@ -178,7 +178,7 @@ class I18nValidationTest < ActiveModel::TestCase test "validates_numericality_of generated message #{name}" do Person.validates_numericality_of :title, validation_options @person.title = 'a' - @person.errors.expects(:generate_message).with(:title, :not_a_number, generate_message_options.merge(:value => 'a')) + @person.errors.expects(:generate_message).with(:title, :not_a_number, generate_message_options.merge(value: 'a')) @person.valid? end end @@ -187,9 +187,9 @@ class I18nValidationTest < ActiveModel::TestCase COMMON_CASES.each do |name, validation_options, generate_message_options| test "validates_numericality_of for :only_integer on generated message #{name}" do - Person.validates_numericality_of :title, validation_options.merge(:only_integer => true) + Person.validates_numericality_of :title, validation_options.merge(only_integer: true) @person.title = '0.0' - @person.errors.expects(:generate_message).with(:title, :not_an_integer, generate_message_options.merge(:value => '0.0')) + @person.errors.expects(:generate_message).with(:title, :not_an_integer, generate_message_options.merge(value: '0.0')) @person.valid? end end @@ -198,9 +198,9 @@ class I18nValidationTest < ActiveModel::TestCase COMMON_CASES.each do |name, validation_options, generate_message_options| test "validates_numericality_of for :odd on generated message #{name}" do - Person.validates_numericality_of :title, validation_options.merge(:only_integer => true, :odd => true) + Person.validates_numericality_of :title, validation_options.merge(only_integer: true, odd: true) @person.title = 0 - @person.errors.expects(:generate_message).with(:title, :odd, generate_message_options.merge(:value => 0)) + @person.errors.expects(:generate_message).with(:title, :odd, generate_message_options.merge(value: 0)) @person.valid? end end @@ -209,9 +209,9 @@ class I18nValidationTest < ActiveModel::TestCase COMMON_CASES.each do |name, validation_options, generate_message_options| test "validates_numericality_of for :less_than on generated message #{name}" do - Person.validates_numericality_of :title, validation_options.merge(:only_integer => true, :less_than => 0) + Person.validates_numericality_of :title, validation_options.merge(only_integer: true, less_than: 0) @person.title = 1 - @person.errors.expects(:generate_message).with(:title, :less_than, generate_message_options.merge(:value => 1, :count => 0)) + @person.errors.expects(:generate_message).with(:title, :less_than, generate_message_options.merge(value: 1, count: 0)) @person.valid? end end @@ -226,8 +226,8 @@ class I18nValidationTest < ActiveModel::TestCase end # test "validates_confirmation_of finds custom model key translation when blank" test "#{validation} finds custom model key translation when #{error_type}" do - I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {attribute => {error_type => 'custom message'}}}}}} - I18n.backend.store_translations 'en', :errors => {:messages => {error_type => 'global message'}} + I18n.backend.store_translations 'en', activemodel: { errors: { models: { person: { attributes: { attribute => { error_type => 'custom message' } } } } } } + I18n.backend.store_translations 'en', errors: { messages: { error_type => 'global message'}} yield(@person, {}) @person.valid? @@ -236,17 +236,17 @@ class I18nValidationTest < ActiveModel::TestCase # test "validates_confirmation_of finds custom model key translation with interpolation when blank" test "#{validation} finds custom model key translation with interpolation when #{error_type}" do - I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {attribute => {error_type => 'custom message with %{extra}'}}}}}} - I18n.backend.store_translations 'en', :errors => {:messages => {error_type => 'global message'}} + I18n.backend.store_translations 'en', activemodel: { errors: { models: { person: { attributes: { attribute => { error_type => 'custom message with %{extra}' } } } } } } + I18n.backend.store_translations 'en', errors: { messages: {error_type => 'global message'} } - yield(@person, {:extra => "extra information"}) + yield(@person, { extra: "extra information" }) @person.valid? assert_equal ['custom message with extra information'], @person.errors[attribute] end # test "validates_confirmation_of finds global default key translation when blank" test "#{validation} finds global default key translation when #{error_type}" do - I18n.backend.store_translations 'en', :errors => {:messages => {error_type => 'global message'}} + I18n.backend.store_translations 'en', errors: { messages: {error_type => 'global message'} } yield(@person, {}) @person.valid? @@ -264,7 +264,7 @@ class I18nValidationTest < ActiveModel::TestCase # validates_acceptance_of w/o mocha set_expectations_for_validation "validates_acceptance_of", :accepted do |person, options_to_merge| - Person.validates_acceptance_of :title, options_to_merge.merge(:allow_nil => false) + Person.validates_acceptance_of :title, options_to_merge.merge(allow_nil: false) end # validates_presence_of w/o mocha @@ -276,36 +276,36 @@ class I18nValidationTest < ActiveModel::TestCase # validates_length_of :within w/o mocha set_expectations_for_validation "validates_length_of", :too_short do |person, options_to_merge| - Person.validates_length_of :title, options_to_merge.merge(:within => 3..5) + Person.validates_length_of :title, options_to_merge.merge(within: 3..5) end set_expectations_for_validation "validates_length_of", :too_long do |person, options_to_merge| - Person.validates_length_of :title, options_to_merge.merge(:within => 3..5) + Person.validates_length_of :title, options_to_merge.merge(within: 3..5) person.title = "too long" end # validates_length_of :is w/o mocha set_expectations_for_validation "validates_length_of", :wrong_length do |person, options_to_merge| - Person.validates_length_of :title, options_to_merge.merge(:is => 5) + Person.validates_length_of :title, options_to_merge.merge(is: 5) end # validates_format_of w/o mocha set_expectations_for_validation "validates_format_of", :invalid do |person, options_to_merge| - Person.validates_format_of :title, options_to_merge.merge(:with => /\A[1-9][0-9]*\z/) + Person.validates_format_of :title, options_to_merge.merge(with: /\A[1-9][0-9]*\z/) end # validates_inclusion_of w/o mocha set_expectations_for_validation "validates_inclusion_of", :inclusion do |person, options_to_merge| - Person.validates_inclusion_of :title, options_to_merge.merge(:in => %w(a b c)) + Person.validates_inclusion_of :title, options_to_merge.merge(in: %w(a b c)) end # validates_exclusion_of w/o mocha set_expectations_for_validation "validates_exclusion_of", :exclusion do |person, options_to_merge| - Person.validates_exclusion_of :title, options_to_merge.merge(:in => %w(a b c)) + Person.validates_exclusion_of :title, options_to_merge.merge(in: %w(a b c)) person.title = 'a' end @@ -319,55 +319,54 @@ class I18nValidationTest < ActiveModel::TestCase # validates_numericality_of with :only_integer w/o mocha set_expectations_for_validation "validates_numericality_of", :not_an_integer do |person, options_to_merge| - Person.validates_numericality_of :title, options_to_merge.merge(:only_integer => true) + Person.validates_numericality_of :title, options_to_merge.merge(only_integer: true) person.title = '1.0' end # validates_numericality_of :odd w/o mocha set_expectations_for_validation "validates_numericality_of", :odd do |person, options_to_merge| - Person.validates_numericality_of :title, options_to_merge.merge(:only_integer => true, :odd => true) + Person.validates_numericality_of :title, options_to_merge.merge(only_integer: true, odd: true) person.title = 0 end # validates_numericality_of :less_than w/o mocha set_expectations_for_validation "validates_numericality_of", :less_than do |person, options_to_merge| - Person.validates_numericality_of :title, options_to_merge.merge(:only_integer => true, :less_than => 0) + Person.validates_numericality_of :title, options_to_merge.merge(only_integer: true, less_than: 0) person.title = 1 end # test with validates_with def test_validations_with_message_symbol_must_translate - I18n.backend.store_translations 'en', :errors => {:messages => {:custom_error => "I am a custom error"}} - Person.validates_presence_of :title, :message => :custom_error + I18n.backend.store_translations 'en', errors: { messages: { custom_error: "I am a custom error" } } + Person.validates_presence_of :title, message: :custom_error @person.title = nil @person.valid? assert_equal ["I am a custom error"], @person.errors[:title] end def test_validates_with_message_symbol_must_translate_per_attribute - I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:attributes => {:title => {:custom_error => "I am a custom error"}}}}}} - Person.validates_presence_of :title, :message => :custom_error + I18n.backend.store_translations 'en', activemodel: { errors: { models: { person: { attributes: { title: { custom_error: "I am a custom error" } } } } } } + Person.validates_presence_of :title, message: :custom_error @person.title = nil @person.valid? assert_equal ["I am a custom error"], @person.errors[:title] end def test_validates_with_message_symbol_must_translate_per_model - I18n.backend.store_translations 'en', :activemodel => {:errors => {:models => {:person => {:custom_error => "I am a custom error"}}}} - Person.validates_presence_of :title, :message => :custom_error + I18n.backend.store_translations 'en', activemodel: { errors: { models: { person: { custom_error: "I am a custom error" } } } } + Person.validates_presence_of :title, message: :custom_error @person.title = nil @person.valid? assert_equal ["I am a custom error"], @person.errors[:title] end def test_validates_with_message_string - Person.validates_presence_of :title, :message => "I am a custom error" + Person.validates_presence_of :title, message: "I am a custom error" @person.title = nil @person.valid? assert_equal ["I am a custom error"], @person.errors[:title] end - end diff --git a/activemodel/test/cases/validations/inclusion_validation_test.rb b/activemodel/test/cases/validations/inclusion_validation_test.rb index 117e9109fc..ceec9dc256 100644 --- a/activemodel/test/cases/validations/inclusion_validation_test.rb +++ b/activemodel/test/cases/validations/inclusion_validation_test.rb @@ -11,7 +11,7 @@ class InclusionValidationTest < ActiveModel::TestCase end def test_validates_inclusion_of_range - Topic.validates_inclusion_of( :title, :in => 'aaa'..'bbb' ) + Topic.validates_inclusion_of(:title, in: 'aaa'..'bbb') assert Topic.new("title" => "bbc", "content" => "abc").invalid? assert Topic.new("title" => "aa", "content" => "abc").invalid? assert Topic.new("title" => "aaa", "content" => "abc").valid? @@ -20,7 +20,7 @@ class InclusionValidationTest < ActiveModel::TestCase end def test_validates_inclusion_of - Topic.validates_inclusion_of( :title, :in => %w( a b c d e f g ) ) + Topic.validates_inclusion_of(:title, in: %w( a b c d e f g )) assert Topic.new("title" => "a!", "content" => "abc").invalid? assert Topic.new("title" => "a b", "content" => "abc").invalid? @@ -33,16 +33,16 @@ class InclusionValidationTest < ActiveModel::TestCase assert t.errors[:title].any? assert_equal ["is not included in the list"], t.errors[:title] - assert_raise(ArgumentError) { Topic.validates_inclusion_of( :title, :in => nil ) } - assert_raise(ArgumentError) { Topic.validates_inclusion_of( :title, :in => 0) } + assert_raise(ArgumentError) { Topic.validates_inclusion_of(:title, in: nil) } + assert_raise(ArgumentError) { Topic.validates_inclusion_of(:title, in: 0) } - assert_nothing_raised(ArgumentError) { Topic.validates_inclusion_of( :title, :in => "hi!" ) } - assert_nothing_raised(ArgumentError) { Topic.validates_inclusion_of( :title, :in => {} ) } - assert_nothing_raised(ArgumentError) { Topic.validates_inclusion_of( :title, :in => [] ) } + assert_nothing_raised(ArgumentError) { Topic.validates_inclusion_of(:title, in: "hi!") } + assert_nothing_raised(ArgumentError) { Topic.validates_inclusion_of(:title, in: {}) } + assert_nothing_raised(ArgumentError) { Topic.validates_inclusion_of(:title, in: []) } end def test_validates_inclusion_of_with_allow_nil - Topic.validates_inclusion_of( :title, :in => %w( a b c d e f g ), :allow_nil => true ) + Topic.validates_inclusion_of(:title, in: %w( a b c d e f g ), allow_nil: true) assert Topic.new("title" => "a!", "content" => "abc").invalid? assert Topic.new("title" => "", "content" => "abc").invalid? @@ -50,7 +50,7 @@ class InclusionValidationTest < ActiveModel::TestCase end def test_validates_inclusion_of_with_formatted_message - Topic.validates_inclusion_of( :title, :in => %w( a b c d e f g ), :message => "option %{value} is not in the list" ) + Topic.validates_inclusion_of(:title, in: %w( a b c d e f g ), message: "option %{value} is not in the list") assert Topic.new("title" => "a", "content" => "abc").valid? @@ -61,7 +61,7 @@ class InclusionValidationTest < ActiveModel::TestCase end def test_validates_inclusion_of_with_within_option - Topic.validates_inclusion_of( :title, :within => %w( a b c d e f g ) ) + Topic.validates_inclusion_of(:title, within: %w( a b c d e f g )) assert Topic.new("title" => "a", "content" => "abc").valid? @@ -71,7 +71,7 @@ class InclusionValidationTest < ActiveModel::TestCase end def test_validates_inclusion_of_for_ruby_class - Person.validates_inclusion_of :karma, :in => %w( abe monkey ) + Person.validates_inclusion_of :karma, in: %w( abe monkey ) p = Person.new p.karma = "Lifo" @@ -86,7 +86,7 @@ class InclusionValidationTest < ActiveModel::TestCase end def test_validates_inclusion_of_with_lambda - Topic.validates_inclusion_of :title, :in => lambda{ |topic| topic.author_name == "sikachu" ? %w( monkey elephant ) : %w( abe wasabi ) } + Topic.validates_inclusion_of :title, in: lambda{ |topic| topic.author_name == "sikachu" ? %w( monkey elephant ) : %w( abe wasabi ) } t = Topic.new t.title = "wasabi" @@ -98,7 +98,7 @@ class InclusionValidationTest < ActiveModel::TestCase end def test_validates_inclusion_of_with_symbol - Person.validates_inclusion_of :karma, :in => :available_karmas + Person.validates_inclusion_of :karma, in: :available_karmas p = Person.new p.karma = "Lifo" diff --git a/activemodel/test/cases/validations/numericality_validation_test.rb b/activemodel/test/cases/validations/numericality_validation_test.rb index 6742a4bab0..84332ed014 100644 --- a/activemodel/test/cases/validations/numericality_validation_test.rb +++ b/activemodel/test/cases/validations/numericality_validation_test.rb @@ -30,84 +30,84 @@ class NumericalityValidationTest < ActiveModel::TestCase end def test_validates_numericality_of_with_nil_allowed - Topic.validates_numericality_of :approved, :allow_nil => true + Topic.validates_numericality_of :approved, allow_nil: true invalid!(JUNK + BLANK) valid!(NIL + FLOATS + INTEGERS + BIGDECIMAL + INFINITY) end def test_validates_numericality_of_with_integer_only - Topic.validates_numericality_of :approved, :only_integer => true + Topic.validates_numericality_of :approved, only_integer: true invalid!(NIL + BLANK + JUNK + FLOATS + BIGDECIMAL + INFINITY) valid!(INTEGERS) end def test_validates_numericality_of_with_integer_only_and_nil_allowed - Topic.validates_numericality_of :approved, :only_integer => true, :allow_nil => true + Topic.validates_numericality_of :approved, only_integer: true, allow_nil: true invalid!(JUNK + BLANK + FLOATS + BIGDECIMAL + INFINITY) valid!(NIL + INTEGERS) end def test_validates_numericality_with_greater_than - Topic.validates_numericality_of :approved, :greater_than => 10 + Topic.validates_numericality_of :approved, greater_than: 10 invalid!([-10, 10], 'must be greater than 10') valid!([11]) end def test_validates_numericality_with_greater_than_or_equal - Topic.validates_numericality_of :approved, :greater_than_or_equal_to => 10 + Topic.validates_numericality_of :approved, greater_than_or_equal_to: 10 invalid!([-9, 9], 'must be greater than or equal to 10') valid!([10]) end def test_validates_numericality_with_equal_to - Topic.validates_numericality_of :approved, :equal_to => 10 + Topic.validates_numericality_of :approved, equal_to: 10 invalid!([-10, 11] + INFINITY, 'must be equal to 10') valid!([10]) end def test_validates_numericality_with_less_than - Topic.validates_numericality_of :approved, :less_than => 10 + Topic.validates_numericality_of :approved, less_than: 10 invalid!([10], 'must be less than 10') valid!([-9, 9]) end def test_validates_numericality_with_less_than_or_equal_to - Topic.validates_numericality_of :approved, :less_than_or_equal_to => 10 + Topic.validates_numericality_of :approved, less_than_or_equal_to: 10 invalid!([11], 'must be less than or equal to 10') valid!([-10, 10]) end def test_validates_numericality_with_odd - Topic.validates_numericality_of :approved, :odd => true + Topic.validates_numericality_of :approved, odd: true invalid!([-2, 2], 'must be odd') valid!([-1, 1]) end def test_validates_numericality_with_even - Topic.validates_numericality_of :approved, :even => true + Topic.validates_numericality_of :approved, even: true invalid!([-1, 1], 'must be even') valid!([-2, 2]) end def test_validates_numericality_with_greater_than_less_than_and_even - Topic.validates_numericality_of :approved, :greater_than => 1, :less_than => 4, :even => true + Topic.validates_numericality_of :approved, greater_than: 1, less_than: 4, even: true invalid!([1, 3, 4]) valid!([2]) end def test_validates_numericality_with_other_than - Topic.validates_numericality_of :approved, :other_than => 0 + Topic.validates_numericality_of :approved, other_than: 0 invalid!([0, 0.0]) valid!([-1, 42]) @@ -115,7 +115,7 @@ class NumericalityValidationTest < ActiveModel::TestCase def test_validates_numericality_with_proc Topic.send(:define_method, :min_approved, lambda { 5 }) - Topic.validates_numericality_of :approved, :greater_than_or_equal_to => Proc.new {|topic| topic.min_approved } + Topic.validates_numericality_of :approved, greater_than_or_equal_to: Proc.new {|topic| topic.min_approved } invalid!([3, 4]) valid!([5, 6]) @@ -124,7 +124,7 @@ class NumericalityValidationTest < ActiveModel::TestCase def test_validates_numericality_with_symbol Topic.send(:define_method, :max_approved, lambda { 5 }) - Topic.validates_numericality_of :approved, :less_than_or_equal_to => :max_approved + Topic.validates_numericality_of :approved, less_than_or_equal_to: :max_approved invalid!([6]) valid!([4, 5]) @@ -132,13 +132,13 @@ class NumericalityValidationTest < ActiveModel::TestCase end def test_validates_numericality_with_numeric_message - Topic.validates_numericality_of :approved, :less_than => 4, :message => "smaller than %{count}" + Topic.validates_numericality_of :approved, less_than: 4, message: "smaller than %{count}" topic = Topic.new("title" => "numeric test", "approved" => 10) assert !topic.valid? assert_equal ["smaller than 4"], topic.errors[:approved] - Topic.validates_numericality_of :approved, :greater_than => 4, :message => "greater than %{count}" + Topic.validates_numericality_of :approved, greater_than: 4, message: "greater than %{count}" topic = Topic.new("title" => "numeric test", "approved" => 1) assert !topic.valid? @@ -146,7 +146,7 @@ class NumericalityValidationTest < ActiveModel::TestCase end def test_validates_numericality_of_for_ruby_class - Person.validates_numericality_of :karma, :allow_nil => false + Person.validates_numericality_of :karma, allow_nil: false p = Person.new p.karma = "Pix" @@ -161,11 +161,11 @@ class NumericalityValidationTest < ActiveModel::TestCase end def test_validates_numericality_with_invalid_args - assert_raise(ArgumentError){ Topic.validates_numericality_of :approved, :greater_than_or_equal_to => "foo" } - assert_raise(ArgumentError){ Topic.validates_numericality_of :approved, :less_than_or_equal_to => "foo" } - assert_raise(ArgumentError){ Topic.validates_numericality_of :approved, :greater_than => "foo" } - assert_raise(ArgumentError){ Topic.validates_numericality_of :approved, :less_than => "foo" } - assert_raise(ArgumentError){ Topic.validates_numericality_of :approved, :equal_to => "foo" } + assert_raise(ArgumentError){ Topic.validates_numericality_of :approved, greater_than_or_equal_to: "foo" } + assert_raise(ArgumentError){ Topic.validates_numericality_of :approved, less_than_or_equal_to: "foo" } + assert_raise(ArgumentError){ Topic.validates_numericality_of :approved, greater_than: "foo" } + assert_raise(ArgumentError){ Topic.validates_numericality_of :approved, less_than: "foo" } + assert_raise(ArgumentError){ Topic.validates_numericality_of :approved, equal_to: "foo" } end private @@ -185,7 +185,7 @@ class NumericalityValidationTest < ActiveModel::TestCase end def with_each_topic_approved_value(values) - topic = Topic.new(:title => "numeric test", :content => "whatever") + topic = Topic.new(title: "numeric test", content: "whatever") values.each do |value| topic.approved = value yield topic, value diff --git a/activemodel/test/cases/validations/validates_test.rb b/activemodel/test/cases/validations/validates_test.rb index 144532d6f4..c1914b32bc 100644 --- a/activemodel/test/cases/validations/validates_test.rb +++ b/activemodel/test/cases/validations/validates_test.rb @@ -17,20 +17,20 @@ class ValidatesTest < ActiveModel::TestCase end def test_validates_with_messages_empty - Person.validates :title, :presence => {:message => "" } + Person.validates :title, presence: { message: "" } person = Person.new assert !person.valid?, 'person should not be valid.' end def test_validates_with_built_in_validation - Person.validates :title, :numericality => true + Person.validates :title, numericality: true person = Person.new person.valid? assert_equal ['is not a number'], person.errors[:title] end def test_validates_with_attribute_specified_as_string - Person.validates "title", :numericality => true + Person.validates "title", numericality: true person = Person.new person.valid? assert_equal ['is not a number'], person.errors[:title] @@ -41,14 +41,14 @@ class ValidatesTest < ActiveModel::TestCase end def test_validates_with_built_in_validation_and_options - Person.validates :salary, :numericality => { :message => 'my custom message' } + Person.validates :salary, numericality: { message: 'my custom message' } person = Person.new person.valid? assert_equal ['my custom message'], person.errors[:salary] end def test_validates_with_validator_class - Person.validates :karma, :email => true + Person.validates :karma, email: true person = Person.new person.valid? assert_equal ['is not an email'], person.errors[:karma] @@ -62,33 +62,33 @@ class ValidatesTest < ActiveModel::TestCase end def test_validates_with_if_as_local_conditions - Person.validates :karma, :presence => true, :email => { :unless => :condition_is_true } + Person.validates :karma, presence: true, email: { unless: :condition_is_true } person = Person.new person.valid? assert_equal ["can't be blank"], person.errors[:karma] end def test_validates_with_if_as_shared_conditions - Person.validates :karma, :presence => true, :email => true, :if => :condition_is_true + Person.validates :karma, presence: true, email: true, if: :condition_is_true person = Person.new person.valid? assert_equal ["can't be blank", "is not an email"], person.errors[:karma].sort end def test_validates_with_unless_shared_conditions - Person.validates :karma, :presence => true, :email => true, :unless => :condition_is_true + Person.validates :karma, presence: true, email: true, unless: :condition_is_true person = Person.new assert person.valid? end def test_validates_with_allow_nil_shared_conditions - Person.validates :karma, :length => { :minimum => 20 }, :email => true, :allow_nil => true + Person.validates :karma, length: { minimum: 20 }, email: true, allow_nil: true person = Person.new assert person.valid? end def test_validates_with_regexp - Person.validates :karma, :format => /positive|negative/ + Person.validates :karma, format: /positive|negative/ person = Person.new assert person.invalid? assert_equal ['is invalid'], person.errors[:karma] @@ -97,7 +97,7 @@ class ValidatesTest < ActiveModel::TestCase end def test_validates_with_array - Person.validates :gender, :inclusion => %w(m f) + Person.validates :gender, inclusion: %w(m f) person = Person.new assert person.invalid? assert_equal ['is not included in the list'], person.errors[:gender] @@ -106,7 +106,7 @@ class ValidatesTest < ActiveModel::TestCase end def test_validates_with_range - Person.validates :karma, :length => 6..20 + Person.validates :karma, length: 6..20 person = Person.new assert person.invalid? assert_equal ['is too short (minimum is 6 characters)'], person.errors[:karma] @@ -115,25 +115,25 @@ class ValidatesTest < ActiveModel::TestCase end def test_validates_with_validator_class_and_options - Person.validates :karma, :email => { :message => 'my custom message' } + Person.validates :karma, email: { message: 'my custom message' } person = Person.new person.valid? assert_equal ['my custom message'], person.errors[:karma] end def test_validates_with_unknown_validator - assert_raise(ArgumentError) { Person.validates :karma, :unknown => true } + assert_raise(ArgumentError) { Person.validates :karma, unknown: true } end def test_validates_with_included_validator - PersonWithValidator.validates :title, :presence => true + PersonWithValidator.validates :title, presence: true person = PersonWithValidator.new person.valid? assert_equal ['Local validator'], person.errors[:title] end def test_validates_with_included_validator_and_options - PersonWithValidator.validates :title, :presence => { :custom => ' please' } + PersonWithValidator.validates :title, presence: { custom: ' please' } person = PersonWithValidator.new person.valid? assert_equal ['Local validator please'], person.errors[:title] @@ -141,7 +141,7 @@ class ValidatesTest < ActiveModel::TestCase def test_validates_with_included_validator_and_wildcard_shortcut # Shortcut for PersonWithValidator.validates :title, like: { with: "Mr." } - PersonWithValidator.validates :title, :like => "Mr." + PersonWithValidator.validates :title, like: "Mr." person = PersonWithValidator.new person.title = "Ms. Pacman" person.valid? @@ -149,7 +149,7 @@ class ValidatesTest < ActiveModel::TestCase end def test_defining_extra_default_keys_for_validates - Topic.validates :title, :confirmation => true, :message => 'Y U NO CONFIRM' + Topic.validates :title, confirmation: true, message: 'Y U NO CONFIRM' topic = Topic.new topic.title = "What's happening" topic.title_confirmation = "Not this" diff --git a/activemodel/test/cases/validations/validations_context_test.rb b/activemodel/test/cases/validations/validations_context_test.rb index b795861f95..5f99b320a6 100644 --- a/activemodel/test/cases/validations/validations_context_test.rb +++ b/activemodel/test/cases/validations/validations_context_test.rb @@ -19,21 +19,21 @@ class ValidationsContextTest < ActiveModel::TestCase end test "with a class that adds errors on create and validating a new model with no arguments" do - Topic.validates_with(ValidatorThatAddsErrors, :on => :create) + Topic.validates_with(ValidatorThatAddsErrors, on: :create) topic = Topic.new assert topic.valid?, "Validation doesn't run on valid? if 'on' is set to create" end test "with a class that adds errors on update and validating a new model" do - Topic.validates_with(ValidatorThatAddsErrors, :on => :update) + Topic.validates_with(ValidatorThatAddsErrors, on: :update) topic = Topic.new assert topic.valid?(:create), "Validation doesn't run on create if 'on' is set to update" end test "with a class that adds errors on create and validating a new model" do - Topic.validates_with(ValidatorThatAddsErrors, :on => :create) + Topic.validates_with(ValidatorThatAddsErrors, on: :create) topic = Topic.new assert topic.invalid?(:create), "Validation does run on create if 'on' is set to create" assert topic.errors[:base].include?(ERROR_MESSAGE) end -end
\ No newline at end of file +end diff --git a/activemodel/test/cases/validations/with_validation_test.rb b/activemodel/test/cases/validations/with_validation_test.rb index daa7a8d5c4..efe16d9aa9 100644 --- a/activemodel/test/cases/validations/with_validation_test.rb +++ b/activemodel/test/cases/validations/with_validation_test.rb @@ -72,26 +72,26 @@ class ValidatesWithTest < ActiveModel::TestCase end test "with if statements that return false" do - Topic.validates_with(ValidatorThatAddsErrors, :if => "1 == 2") + Topic.validates_with(ValidatorThatAddsErrors, if: "1 == 2") topic = Topic.new assert topic.valid? end test "with if statements that return true" do - Topic.validates_with(ValidatorThatAddsErrors, :if => "1 == 1") + Topic.validates_with(ValidatorThatAddsErrors, if: "1 == 1") topic = Topic.new assert topic.invalid? assert topic.errors[:base].include?(ERROR_MESSAGE) end test "with unless statements that return true" do - Topic.validates_with(ValidatorThatAddsErrors, :unless => "1 == 1") + Topic.validates_with(ValidatorThatAddsErrors, unless: "1 == 1") topic = Topic.new assert topic.valid? end test "with unless statements that returns false" do - Topic.validates_with(ValidatorThatAddsErrors, :unless => "1 == 2") + Topic.validates_with(ValidatorThatAddsErrors, unless: "1 == 2") topic = Topic.new assert topic.invalid? assert topic.errors[:base].include?(ERROR_MESSAGE) @@ -100,10 +100,10 @@ class ValidatesWithTest < ActiveModel::TestCase test "passes all configuration options to the validator class" do topic = Topic.new validator = mock() - validator.expects(:new).with(:foo => :bar, :if => "1 == 1").returns(validator) + validator.expects(:new).with(foo: :bar, if: "1 == 1").returns(validator) validator.expects(:validate).with(topic) - Topic.validates_with(validator, :if => "1 == 1", :foo => :bar) + Topic.validates_with(validator, if: "1 == 1", foo: :bar) assert topic.valid? end @@ -130,15 +130,15 @@ class ValidatesWithTest < ActiveModel::TestCase end test "validates_with with options" do - Topic.validates_with(ValidatorThatValidatesOptions, :field => :first_name) + Topic.validates_with(ValidatorThatValidatesOptions, field: :first_name) topic = Topic.new assert topic.invalid? assert topic.errors[:base].include?(ERROR_MESSAGE) end test "validates_with each validator" do - Topic.validates_with(ValidatorPerEachAttribute, :attributes => [:title, :content]) - topic = Topic.new :title => "Title", :content => "Content" + Topic.validates_with(ValidatorPerEachAttribute, attributes: [:title, :content]) + topic = Topic.new title: "Title", content: "Content" assert topic.invalid? assert_equal ["Value is Title"], topic.errors[:title] assert_equal ["Value is Content"], topic.errors[:content] @@ -146,7 +146,7 @@ class ValidatesWithTest < ActiveModel::TestCase test "each validator checks validity" do assert_raise RuntimeError do - Topic.validates_with(ValidatorCheckValidity, :attributes => [:title]) + Topic.validates_with(ValidatorCheckValidity, attributes: [:title]) end end @@ -157,25 +157,25 @@ class ValidatesWithTest < ActiveModel::TestCase end test "each validator skip nil values if :allow_nil is set to true" do - Topic.validates_with(ValidatorPerEachAttribute, :attributes => [:title, :content], :allow_nil => true) - topic = Topic.new :content => "" + Topic.validates_with(ValidatorPerEachAttribute, attributes: [:title, :content], allow_nil: true) + topic = Topic.new content: "" assert topic.invalid? assert topic.errors[:title].empty? assert_equal ["Value is "], topic.errors[:content] end test "each validator skip blank values if :allow_blank is set to true" do - Topic.validates_with(ValidatorPerEachAttribute, :attributes => [:title, :content], :allow_blank => true) - topic = Topic.new :content => "" + Topic.validates_with(ValidatorPerEachAttribute, attributes: [:title, :content], allow_blank: true) + topic = Topic.new content: "" assert topic.valid? assert topic.errors[:title].empty? assert topic.errors[:content].empty? end test "validates_with can validate with an instance method" do - Topic.validates :title, :with => :my_validation + Topic.validates :title, with: :my_validation - topic = Topic.new :title => "foo" + topic = Topic.new title: "foo" assert topic.valid? assert topic.errors[:title].empty? @@ -185,9 +185,9 @@ class ValidatesWithTest < ActiveModel::TestCase end test "optionally pass in the attribute being validated when validating with an instance method" do - Topic.validates :title, :content, :with => :my_validation_with_arg + Topic.validates :title, :content, with: :my_validation_with_arg - topic = Topic.new :title => "foo" + topic = Topic.new title: "foo" assert !topic.valid? assert topic.errors[:title].empty? assert_equal ['is missing'], topic.errors[:content] diff --git a/activemodel/test/cases/validations_test.rb b/activemodel/test/cases/validations_test.rb index 2934e70c2f..3241a03b53 100644 --- a/activemodel/test/cases/validations_test.rb +++ b/activemodel/test/cases/validations_test.rb @@ -190,16 +190,16 @@ class ValidationsTest < ActiveModel::TestCase def test_validation_order Topic.validates_presence_of :title - Topic.validates_length_of :title, :minimum => 2 + Topic.validates_length_of :title, minimum: 2 t = Topic.new("title" => "") assert t.invalid? assert_equal "can't be blank", t.errors["title"].first Topic.validates_presence_of :title, :author_name Topic.validate {errors.add('author_email_address', 'will never be valid')} - Topic.validates_length_of :title, :content, :minimum => 2 + Topic.validates_length_of :title, :content, minimum: 2 - t = Topic.new :title => '' + t = Topic.new title: '' assert t.invalid? assert_equal :title, key = t.errors.keys[0] @@ -214,9 +214,9 @@ class ValidationsTest < ActiveModel::TestCase end def test_validation_with_if_and_on - Topic.validates_presence_of :title, :if => Proc.new{|x| x.author_name = "bad"; true }, :on => :update + Topic.validates_presence_of :title, if: Proc.new{|x| x.author_name = "bad"; true }, on: :update - t = Topic.new(:title => "") + t = Topic.new(title: "") # If block should not fire assert t.valid? @@ -239,7 +239,7 @@ class ValidationsTest < ActiveModel::TestCase end def test_validation_with_message_as_proc - Topic.validates_presence_of(:title, :message => proc { "no blanks here".upcase }) + Topic.validates_presence_of(:title, message: proc { "no blanks here".upcase }) t = Topic.new assert t.invalid? @@ -248,7 +248,7 @@ class ValidationsTest < ActiveModel::TestCase def test_list_of_validators_for_model Topic.validates_presence_of :title - Topic.validates_length_of :title, :minimum => 2 + Topic.validates_length_of :title, minimum: 2 assert_equal 2, Topic.validators.count assert_equal [:presence, :length], Topic.validators.map(&:kind) @@ -256,7 +256,7 @@ class ValidationsTest < ActiveModel::TestCase def test_list_of_validators_on_an_attribute Topic.validates_presence_of :title, :content - Topic.validates_length_of :title, :minimum => 2 + Topic.validates_length_of :title, minimum: 2 assert_equal 2, Topic.validators_on(:title).count assert_equal [:presence, :length], Topic.validators_on(:title).map(&:kind) @@ -265,13 +265,13 @@ class ValidationsTest < ActiveModel::TestCase end def test_accessing_instance_of_validator_on_an_attribute - Topic.validates_length_of :title, :minimum => 10 + Topic.validates_length_of :title, minimum: 10 assert_equal 10, Topic.validators_on(:title).first.options[:minimum] end def test_list_of_validators_on_multiple_attributes - Topic.validates :title, :length => { :minimum => 10 } - Topic.validates :author_name, :presence => true, :format => /a/ + Topic.validates :title, length: { minimum: 10 } + Topic.validates :author_name, presence: true, format: /a/ validators = Topic.validators_on(:title, :author_name) @@ -283,7 +283,7 @@ class ValidationsTest < ActiveModel::TestCase end def test_list_of_validators_will_be_empty_when_empty - Topic.validates :title, :length => { :minimum => 10 } + Topic.validates :title, length: { minimum: 10 } assert_equal [], Topic.validators_on(:author_name) end @@ -300,52 +300,52 @@ class ValidationsTest < ActiveModel::TestCase end def test_strict_validation_in_validates - Topic.validates :title, :strict => true, :presence => true + Topic.validates :title, strict: true, presence: true assert_raises ActiveModel::StrictValidationFailed do Topic.new.valid? end end def test_strict_validation_not_fails - Topic.validates :title, :strict => true, :presence => true - assert Topic.new(:title => "hello").valid? + Topic.validates :title, strict: true, presence: true + assert Topic.new(title: "hello").valid? end def test_strict_validation_particular_validator - Topic.validates :title, :presence => { :strict => true } + Topic.validates :title, presence: { strict: true } assert_raises ActiveModel::StrictValidationFailed do Topic.new.valid? end end def test_strict_validation_in_custom_validator_helper - Topic.validates_presence_of :title, :strict => true + Topic.validates_presence_of :title, strict: true assert_raises ActiveModel::StrictValidationFailed do Topic.new.valid? end end def test_strict_validation_custom_exception - Topic.validates_presence_of :title, :strict => CustomStrictValidationException + Topic.validates_presence_of :title, strict: CustomStrictValidationException assert_raises CustomStrictValidationException do Topic.new.valid? end end def test_validates_with_bang - Topic.validates! :title, :presence => true + Topic.validates! :title, presence: true assert_raises ActiveModel::StrictValidationFailed do Topic.new.valid? end end def test_validates_with_false_hash_value - Topic.validates :title, :presence => false + Topic.validates :title, presence: false assert Topic.new.valid? end def test_strict_validation_error_message - Topic.validates :title, :strict => true, :presence => true + Topic.validates :title, strict: true, presence: true exception = assert_raises(ActiveModel::StrictValidationFailed) do Topic.new.valid? @@ -354,9 +354,9 @@ class ValidationsTest < ActiveModel::TestCase end def test_does_not_modify_options_argument - options = { :presence => true } + options = { presence: true } Topic.validates :title, options - assert_equal({ :presence => true }, options) + assert_equal({ presence: true }, options) end def test_dup_validity_is_independent diff --git a/activemodel/test/models/automobile.rb b/activemodel/test/models/automobile.rb index 021ea61c80..ece644c40c 100644 --- a/activemodel/test/models/automobile.rb +++ b/activemodel/test/models/automobile.rb @@ -7,6 +7,6 @@ class Automobile def validations validates_presence_of :make - validates_length_of :model, :within => 2..10 + validates_length_of :model, within: 2..10 end -end
\ No newline at end of file +end diff --git a/activemodel/test/models/contact.rb b/activemodel/test/models/contact.rb index 7bfc542afb..c25be28e1d 100644 --- a/activemodel/test/models/contact.rb +++ b/activemodel/test/models/contact.rb @@ -9,7 +9,7 @@ class Contact end def network - {:git => :github} + { git: :github } end def initialize(options = {}) diff --git a/activemodel/test/models/reply.rb b/activemodel/test/models/reply.rb index ec1efeac19..b77910e671 100644 --- a/activemodel/test/models/reply.rb +++ b/activemodel/test/models/reply.rb @@ -2,11 +2,11 @@ require 'models/topic' class Reply < Topic validate :errors_on_empty_content - validate :title_is_wrong_create, :on => :create + validate :title_is_wrong_create, on: :create validate :check_empty_title - validate :check_content_mismatch, :on => :create - validate :check_wrong_update, :on => :update + validate :check_content_mismatch, on: :create + validate :check_wrong_update, on: :update def check_empty_title errors[:title] << "is Empty" unless title && title.size > 0 diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 27de322201..c25880630a 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -2,6 +2,82 @@ *Ben Tucker* +* Fixed a bug in ActiveRecord#sanitize_sql_hash_for_conditions in which + `self.class` is an argument to PredicateBuilder#build_from_hash + causing PredicateBuilder to call non-existant method + Class#reflect_on_association. + + *Zach Ohlgren* + +* While removing index if column option is missing then raise IrreversibleMigration exception. + + Following code should raise `IrreversibleMigration`. But the code was + failing since options is an array and not a hash. + + def change + change_table :users do |t| + t.remove_index [:name, :email] + end + end + + Fix was to check if the options is a Hash before operating on it. + + Fixes #10419. + + *Neeraj Singh* + +* Do not overwrite manually built records during one-to-one nested attribute assignment + + For one-to-one nested associations, if you build the new (in-memory) + child object yourself before assignment, then the NestedAttributes + module will not overwrite it, e.g.: + + class Member < ActiveRecord::Base + has_one :avatar + accepts_nested_attributes_for :avatar + + def avatar + super || build_avatar(width: 200) + end + end + + member = Member.new + member.avatar_attributes = {icon: 'sad'} + member.avatar.width # => 200 + + *Olek Janiszewski* + +* fixes bug introduced by #3329. Now, when autosaving associations, + deletions happen before inserts and saves. This prevents a 'duplicate + unique value' database error that would occur if a record being created had + the same value on a unique indexed field as that of a record being destroyed. + + *Johnny Holton* + +* Handle aliased attributes in ActiveRecord::Relation. + + When using symbol keys, ActiveRecord will now translate aliased attribute names to the actual column name used in the database: + + With the model + + class Topic + alias_attribute :heading, :title + end + + The call + + Topic.where(heading: 'The First Topic') + + should yield the same result as + + Topic.where(title: 'The First Topic') + + This also applies to ActiveRecord::Relation::Calculations calls such as `Model.sum(:aliased)` and `Model.pluck(:aliased)`. + + This will not work with SQL fragment strings like `Model.sum('DISTINCT aliased')`. + + *Godfrey Chan* + * Mute `psql` output when running rake db:schema:load. *Godfrey Chan* @@ -16,4 +92,8 @@ *kennyj* +* rake:db:test:prepare falls back to original environment after execution. + + *Slava Markevich* + Please check [4-0-stable](https://github.com/rails/rails/blob/4-0-stable/activerecord/CHANGELOG.md) for previous changes. diff --git a/activerecord/lib/active_record/associations/association.rb b/activerecord/lib/active_record/associations/association.rb index db0553ea76..710babe024 100644 --- a/activerecord/lib/active_record/associations/association.rb +++ b/activerecord/lib/active_record/associations/association.rb @@ -164,6 +164,13 @@ module ActiveRecord @reflection = @owner.class.reflect_on_association(reflection_name) end + def initialize_attributes(record) #:nodoc: + skip_assign = [reflection.foreign_key, reflection.type].compact + attributes = create_scope.except(*(record.changed - skip_assign)) + record.assign_attributes(attributes) + set_inverse_instance(record) + end + private def find_target? @@ -233,10 +240,7 @@ module ActiveRecord def build_record(attributes) reflection.build_association(attributes) do |record| - skip_assign = [reflection.foreign_key, reflection.type].compact - attributes = create_scope.except(*(record.changed - skip_assign)) - record.assign_attributes(attributes) - set_inverse_instance(record) + initialize_attributes(record) end end end diff --git a/activerecord/lib/active_record/autosave_association.rb b/activerecord/lib/active_record/autosave_association.rb index b0bd78ad46..87d4daa6d9 100644 --- a/activerecord/lib/active_record/autosave_association.rb +++ b/activerecord/lib/active_record/autosave_association.rb @@ -335,15 +335,18 @@ module ActiveRecord autosave = reflection.options[:autosave] if records = associated_records_to_validate_or_save(association, @new_record_before_save, autosave) - records_to_destroy = [] + + if autosave + records_to_destroy = records.select(&:marked_for_destruction?) + records_to_destroy.each { |record| association.destroy(record) } + records -= records_to_destroy + end + records.each do |record| - next if record.destroyed? saved = true - if autosave && record.marked_for_destruction? - records_to_destroy << record - elsif autosave != false && (@new_record_before_save || record.new_record?) + if autosave != false && (@new_record_before_save || record.new_record?) if autosave saved = association.insert_record(record, false) else @@ -355,10 +358,6 @@ module ActiveRecord raise ActiveRecord::Rollback unless saved end - - records_to_destroy.each do |record| - association.destroy(record) - end end # reconstruct the scope now that we know the owner's id diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb index d9b807bba4..98916b06a5 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb @@ -321,6 +321,7 @@ module ActiveRecord result = query(<<-end_sql, 'SCHEMA')[0] SELECT attr.attname, CASE + WHEN pg_get_expr(def.adbin, def.adrelid) !~* 'nextval' THEN NULL WHEN split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2) ~ '.' THEN substr(split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2), strpos(split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2), '.')+1) @@ -332,7 +333,7 @@ module ActiveRecord JOIN pg_constraint cons ON (conrelid = adrelid AND adnum = conkey[1]) WHERE t.oid = '#{quote_table_name(table)}'::regclass AND cons.contype = 'p' - AND pg_get_expr(def.adbin, def.adrelid) ~* 'nextval' + AND pg_get_expr(def.adbin, def.adrelid) ~* 'nextval|uuid_generate' end_sql end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index bf403c3ae0..88b09e7999 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -20,8 +20,8 @@ module ActiveRecord VALID_CONN_PARAMS = [:host, :hostaddr, :port, :dbname, :user, :password, :connect_timeout, :client_encoding, :options, :application_name, :fallback_application_name, :keepalives, :keepalives_idle, :keepalives_interval, :keepalives_count, - :tty, :sslmode, :requiressl, :sslcert, :sslkey, :sslrootcert, :sslcrl, - :requirepeer, :krbsrvname, :gsslib, :service] + :tty, :sslmode, :requiressl, :sslcompression, :sslcert, :sslkey, + :sslrootcert, :sslcrl, :requirepeer, :krbsrvname, :gsslib, :service] # Establishes a connection to the database that's used by all Active Record objects def postgresql_connection(config) @@ -330,9 +330,37 @@ module ActiveRecord class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition include ColumnMethods + # Defines the primary key field. + # Use of the native PostgreSQL UUID type is supported, and can be used + # by defining your tables as such: + # + # create_table :stuffs, id: :uuid do |t| + # t.string :content + # t.timestamps + # end + # + # By default, this will use the +uuid_generate_v4()+ function from the + # +uuid-ossp+ extension, which MUST be enabled on your database. To enable + # the +uuid-ossp+ extension, you can use the +enable_extension+ method in your + # migrations. To use a UUID primary key without +uuid-ossp+ enabled, you can + # set the +:default+ option to +nil+: + # + # create_table :stuffs, id: false do |t| + # t.primary_key :id, :uuid, default: nil + # t.uuid :foo_id + # t.timestamps + # end + # + # You may also pass a different UUID generation function from +uuid-ossp+ + # or another library. + # + # Note that setting the UUID primary key default value to +nil+ will + # require you to assure that you always provide a UUID value before saving + # a record (as primary keys cannot be +nil+). This might be done via the + # +SecureRandom.uuid+ method and a +before_save+ callback, for instance. def primary_key(name, type = :primary_key, options = {}) return super unless type == :uuid - options[:default] ||= 'uuid_generate_v4()' + options[:default] = options.fetch(:default, 'uuid_generate_v4()') options[:primary_key] = true column name, type, options end @@ -740,7 +768,7 @@ module ActiveRecord end def exec_cache(sql, binds) - stmt_key = prepare_statement sql + stmt_key = prepare_statement(sql) # Clear the queue @connection.get_last_result diff --git a/activerecord/lib/active_record/migration/command_recorder.rb b/activerecord/lib/active_record/migration/command_recorder.rb index 79c55045ba..9782a48055 100644 --- a/activerecord/lib/active_record/migration/command_recorder.rb +++ b/activerecord/lib/active_record/migration/command_recorder.rb @@ -144,7 +144,10 @@ module ActiveRecord def invert_remove_index(args) table, options = *args - raise ActiveRecord::IrreversibleMigration, "remove_index is only reversible if given a :column option." unless options && options[:column] + + unless options && options.is_a?(Hash) && options[:column] + raise ActiveRecord::IrreversibleMigration, "remove_index is only reversible if given a :column option." + end options = options.dup [:add_index, [table, options.delete(:column), options]] diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb index d607f49e2b..021832de46 100644 --- a/activerecord/lib/active_record/nested_attributes.rb +++ b/activerecord/lib/active_record/nested_attributes.rb @@ -229,6 +229,23 @@ module ActiveRecord # belongs_to :member, inverse_of: :posts # validates_presence_of :member # end + # + # For one-to-one nested associations, if you build the new (in-memory) + # child object yourself before assignment, then this module will not + # overwrite it, e.g.: + # + # class Member < ActiveRecord::Base + # has_one :avatar + # accepts_nested_attributes_for :avatar + # + # def avatar + # super || build_avatar(width: 200) + # end + # end + # + # member = Member.new + # member.avatar_attributes = {icon: 'sad'} + # member.avatar.width # => 200 module ClassMethods REJECT_ALL_BLANK_PROC = proc { |attributes| attributes.all? { |key, value| key == '_destroy' || value.blank? } } @@ -356,20 +373,28 @@ module ActiveRecord def assign_nested_attributes_for_one_to_one_association(association_name, attributes) options = self.nested_attributes_options[association_name] attributes = attributes.with_indifferent_access + existing_record = send(association_name) - if (options[:update_only] || !attributes['id'].blank?) && (record = send(association_name)) && - (options[:update_only] || record.id.to_s == attributes['id'].to_s) - assign_to_or_mark_for_destruction(record, attributes, options[:allow_destroy]) unless call_reject_if(association_name, attributes) + if (options[:update_only] || !attributes['id'].blank?) && existing_record && + (options[:update_only] || existing_record.id.to_s == attributes['id'].to_s) + assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy]) unless call_reject_if(association_name, attributes) elsif attributes['id'].present? raise_nested_attributes_record_not_found!(association_name, attributes['id']) elsif !reject_new_record?(association_name, attributes) - method = "build_#{association_name}" - if respond_to?(method) - send(method, attributes.except(*UNASSIGNABLE_KEYS)) + assignable_attributes = attributes.except(*UNASSIGNABLE_KEYS) + + if existing_record && existing_record.new_record? + existing_record.assign_attributes(assignable_attributes) + association(association_name).initialize_attributes(existing_record) else - raise ArgumentError, "Cannot build association `#{association_name}'. Are you trying to build a polymorphic one-to-one association?" + method = "build_#{association_name}" + if respond_to?(method) + send(method, assignable_attributes) + else + raise ArgumentError, "Cannot build association `#{association_name}'. Are you trying to build a polymorphic one-to-one association?" + end end end end diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index 92bef09ff5..434af3c5f8 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -319,9 +319,13 @@ db_namespace = namespace :db do # desc "Recreate the test database from an existent schema.rb file" task :load_schema => 'db:test:purge' do - ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test']) - ActiveRecord::Schema.verbose = false - db_namespace["schema:load"].invoke + begin + ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test']) + ActiveRecord::Schema.verbose = false + db_namespace["schema:load"].invoke + ensure + ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations[Rails.env]) + end end # desc "Recreate the test database from an existent structure.sql file" diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb index 64e1ff9a6a..7239270c4d 100644 --- a/activerecord/lib/active_record/relation/calculations.rb +++ b/activerecord/lib/active_record/relation/calculations.rb @@ -27,7 +27,7 @@ module ActiveRecord # Calculates the average value on a given column. Returns +nil+ if there's # no row. See +calculate+ for examples with options. # - # Person.average('age') # => 35.8 + # Person.average(:age) # => 35.8 def average(column_name, options = {}) calculate(:average, column_name, options) end @@ -36,7 +36,7 @@ module ActiveRecord # with the same data type of the column, or +nil+ if there's no row. See # +calculate+ for examples with options. # - # Person.minimum('age') # => 7 + # Person.minimum(:age) # => 7 def minimum(column_name, options = {}) calculate(:minimum, column_name, options) end @@ -45,7 +45,7 @@ module ActiveRecord # with the same data type of the column, or +nil+ if there's no row. See # +calculate+ for examples with options. # - # Person.maximum('age') # => 93 + # Person.maximum(:age) # => 93 def maximum(column_name, options = {}) calculate(:maximum, column_name, options) end @@ -54,7 +54,7 @@ module ActiveRecord # with the same data type of the column, 0 if there's no row. See # +calculate+ for examples with options. # - # Person.sum('age') # => 4562 + # Person.sum(:age) # => 4562 def sum(*args) if block_given? ActiveSupport::Deprecation.warn( @@ -101,6 +101,10 @@ module ActiveRecord def calculate(operation, column_name, options = {}) relation = with_default_scope + if column_name.is_a?(Symbol) && attribute_aliases.key?(column_name.to_s) + column_name = attribute_aliases[column_name.to_s].to_sym + end + if relation.equal?(self) if has_include?(column_name) construct_relation_for_association_calculations.calculate(operation, column_name, options) @@ -149,11 +153,17 @@ module ActiveRecord # def pluck(*column_names) column_names.map! do |column_name| - if column_name.is_a?(Symbol) && self.column_names.include?(column_name.to_s) - "#{connection.quote_table_name(table_name)}.#{connection.quote_column_name(column_name)}" - else - column_name + if column_name.is_a?(Symbol) + if attribute_aliases.key?(column_name.to_s) + column_name = attribute_aliases[column_name.to_s].to_sym + end + + if self.columns_hash.key?(column_name.to_s) + column_name = "#{connection.quote_table_name(table_name)}.#{connection.quote_column_name(column_name)}" + end end + + column_name end if has_include?(column_names.first) diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb index f44d46d15b..b7609c97b5 100644 --- a/activerecord/lib/active_record/relation/predicate_builder.rb +++ b/activerecord/lib/active_record/relation/predicate_builder.rb @@ -6,6 +6,10 @@ module ActiveRecord attributes.each do |column, value| table = default_table + if column.is_a?(Symbol) && klass.attribute_aliases.key?(column.to_s) + column = klass.attribute_aliases[column.to_s] + end + if value.is_a?(Hash) if value.empty? queries << '1=0' diff --git a/activerecord/lib/active_record/sanitization.rb b/activerecord/lib/active_record/sanitization.rb index 3c5b871e99..0ed97b66d6 100644 --- a/activerecord/lib/active_record/sanitization.rb +++ b/activerecord/lib/active_record/sanitization.rb @@ -89,7 +89,7 @@ module ActiveRecord attrs = expand_hash_conditions_for_aggregates(attrs) table = Arel::Table.new(table_name, arel_engine).alias(default_table_name) - PredicateBuilder.build_from_hash(self.class, attrs, table).map { |b| + PredicateBuilder.build_from_hash(self, attrs, table).map { |b| connection.visitor.accept b }.join(' AND ') end diff --git a/activerecord/lib/active_record/schema_dumper.rb b/activerecord/lib/active_record/schema_dumper.rb index 10c6d272cd..1181cc739e 100644 --- a/activerecord/lib/active_record/schema_dumper.rb +++ b/activerecord/lib/active_record/schema_dumper.rb @@ -106,9 +106,12 @@ HEADER end tbl.print " create_table #{remove_prefix_and_suffix(table).inspect}" - if columns.detect { |c| c.name == pk } + pkcol = columns.detect { |c| c.name == pk } + if pkcol if pk != 'id' tbl.print %Q(, primary_key: "#{pk}") + elsif pkcol.sql_type == 'uuid' + tbl.print ", id: :uuid" end else tbl.print ", id: false" diff --git a/activerecord/test/cases/adapters/mysql/active_schema_test.rb b/activerecord/test/cases/adapters/mysql/active_schema_test.rb index e6d0183b11..0878925a6c 100644 --- a/activerecord/test/cases/adapters/mysql/active_schema_test.rb +++ b/activerecord/test/cases/adapters/mysql/active_schema_test.rb @@ -2,25 +2,24 @@ require "cases/helper" class ActiveSchemaTest < ActiveRecord::TestCase def setup - ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter.class_eval do + @connection = ActiveRecord::Base.remove_connection + ActiveRecord::Base.establish_connection(@connection) + + ActiveRecord::Base.connection.singleton_class.class_eval do alias_method :execute_without_stub, :execute - remove_method :execute def execute(sql, name = nil) return sql end end end def teardown - ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter.class_eval do - remove_method :execute - alias_method :execute, :execute_without_stub - end + ActiveRecord::Base.remove_connection + ActiveRecord::Base.establish_connection(@connection) end def test_add_index # add_index calls index_name_exists? which can't work since execute is stubbed - ActiveRecord::ConnectionAdapters::MysqlAdapter.send(:define_method, :index_name_exists?) do |*| - false - end + def (ActiveRecord::Base.connection).index_name_exists?(*); false; end + expected = "CREATE INDEX `index_people_on_last_name` ON `people` (`last_name`) " assert_equal expected, add_index(:people, :last_name, :length => nil) @@ -58,8 +57,6 @@ class ActiveSchemaTest < ActiveRecord::TestCase expected = "CREATE INDEX `index_people_on_last_name_and_first_name` USING btree ON `people` (`last_name`(15), `first_name`(15)) " assert_equal expected, add_index(:people, [:last_name, :first_name], :length => 15, :using => :btree) - - ActiveRecord::ConnectionAdapters::MysqlAdapter.send(:remove_method, :index_name_exists?) end def test_drop_table @@ -121,22 +118,20 @@ class ActiveSchemaTest < ActiveRecord::TestCase private def with_real_execute - #we need to actually modify some data, so we make execute point to the original method - ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter.class_eval do + ActiveRecord::Base.connection.singleton_class.class_eval do alias_method :execute_with_stub, :execute remove_method :execute alias_method :execute, :execute_without_stub end + yield ensure - #before finishing, we restore the alias to the mock-up method - ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter.class_eval do + ActiveRecord::Base.connection.singleton_class.class_eval do remove_method :execute alias_method :execute, :execute_with_stub end end - def method_missing(method_symbol, *arguments) ActiveRecord::Base.connection.send(method_symbol, *arguments) end diff --git a/activerecord/test/cases/adapters/mysql2/active_schema_test.rb b/activerecord/test/cases/adapters/mysql2/active_schema_test.rb index 8a2a7ef269..4ccf568406 100644 --- a/activerecord/test/cases/adapters/mysql2/active_schema_test.rb +++ b/activerecord/test/cases/adapters/mysql2/active_schema_test.rb @@ -2,25 +2,24 @@ require "cases/helper" class ActiveSchemaTest < ActiveRecord::TestCase def setup - ActiveRecord::ConnectionAdapters::Mysql2Adapter.class_eval do + @connection = ActiveRecord::Base.remove_connection + ActiveRecord::Base.establish_connection(@connection) + + ActiveRecord::Base.connection.singleton_class.class_eval do alias_method :execute_without_stub, :execute - remove_method :execute def execute(sql, name = nil) return sql end end end def teardown - ActiveRecord::ConnectionAdapters::Mysql2Adapter.class_eval do - remove_method :execute - alias_method :execute, :execute_without_stub - end + ActiveRecord::Base.remove_connection + ActiveRecord::Base.establish_connection(@connection) end def test_add_index # add_index calls index_name_exists? which can't work since execute is stubbed - ActiveRecord::ConnectionAdapters::Mysql2Adapter.send(:define_method, :index_name_exists?) do |*| - false - end + def (ActiveRecord::Base.connection).index_name_exists?(*); false; end + expected = "CREATE INDEX `index_people_on_last_name` ON `people` (`last_name`) " assert_equal expected, add_index(:people, :last_name, :length => nil) @@ -58,8 +57,6 @@ class ActiveSchemaTest < ActiveRecord::TestCase expected = "CREATE INDEX `index_people_on_last_name_and_first_name` USING btree ON `people` (`last_name`(15), `first_name`(15)) " assert_equal expected, add_index(:people, [:last_name, :first_name], :length => 15, :using => :btree) - - ActiveRecord::ConnectionAdapters::Mysql2Adapter.send(:remove_method, :index_name_exists?) end def test_drop_table @@ -121,22 +118,20 @@ class ActiveSchemaTest < ActiveRecord::TestCase private def with_real_execute - #we need to actually modify some data, so we make execute point to the original method - ActiveRecord::ConnectionAdapters::Mysql2Adapter.class_eval do + ActiveRecord::Base.connection.singleton_class.class_eval do alias_method :execute_with_stub, :execute remove_method :execute alias_method :execute, :execute_without_stub end + yield ensure - #before finishing, we restore the alias to the mock-up method - ActiveRecord::ConnectionAdapters::Mysql2Adapter.class_eval do + ActiveRecord::Base.connection.singleton_class.class_eval do remove_method :execute alias_method :execute, :execute_with_stub end end - def method_missing(method_symbol, *arguments) ActiveRecord::Base.connection.send(method_symbol, *arguments) end diff --git a/activerecord/test/cases/adapters/postgresql/datatype_test.rb b/activerecord/test/cases/adapters/postgresql/datatype_test.rb index 8c17372286..b5d7ea603e 100644 --- a/activerecord/test/cases/adapters/postgresql/datatype_test.rb +++ b/activerecord/test/cases/adapters/postgresql/datatype_test.rb @@ -281,7 +281,6 @@ _SQL tz = ::ActiveRecord::Base.default_timezone assert_equal Time.send(tz, 2010, 1, 1, 14, 30, 0)..Time.send(tz, 2011, 1, 1, 14, 30, 0), @first_range.ts_range assert_equal Time.send(tz, 2010, 1, 1, 14, 30, 0)...Time.send(tz, 2011, 1, 1, 14, 30, 0), @second_range.ts_range - assert_equal Time.send(tz, 2010, 1, 1, 14, 30, 0)...Float::INFINITY, @third_range.ts_range assert_equal(-Float::INFINITY...Float::INFINITY, @fourth_range.ts_range) assert_equal nil, @empty_range.ts_range end @@ -290,7 +289,6 @@ _SQL skip "PostgreSQL 9.2 required for range datatypes" unless @connection.supports_ranges? assert_equal Time.parse('2010-01-01 09:30:00 UTC')..Time.parse('2011-01-01 17:30:00 UTC'), @first_range.tstz_range assert_equal Time.parse('2010-01-01 09:30:00 UTC')...Time.parse('2011-01-01 17:30:00 UTC'), @second_range.tstz_range - assert_equal Time.parse('2010-01-01 09:30:00 UTC')...Float::INFINITY, @third_range.tstz_range assert_equal(-Float::INFINITY...Float::INFINITY, @fourth_range.tstz_range) assert_equal nil, @empty_range.tstz_range end diff --git a/activerecord/test/cases/adapters/postgresql/uuid_test.rb b/activerecord/test/cases/adapters/postgresql/uuid_test.rb index c0c0e8898c..b573d48807 100644 --- a/activerecord/test/cases/adapters/postgresql/uuid_test.rb +++ b/activerecord/test/cases/adapters/postgresql/uuid_test.rb @@ -50,4 +50,46 @@ class PostgresqlUUIDTest < ActiveRecord::TestCase u.reload assert_not_nil u.other_uuid end + + def test_pk_and_sequence_for_uuid_primary_key + pk, seq = @connection.pk_and_sequence_for('pg_uuids') + assert_equal 'id', pk + assert_equal nil, seq + end + + def test_schema_dumper_for_uuid_primary_key + schema = StringIO.new + ActiveRecord::SchemaDumper.dump(@connection, schema) + assert_match(/\bcreate_table "pg_uuids", id: :uuid\b/, schema.string) + end +end + +class PostgresqlUUIDTestNilDefault < ActiveRecord::TestCase + class UUID < ActiveRecord::Base + self.table_name = 'pg_uuids' + end + + def setup + @connection = ActiveRecord::Base.connection + @connection.reconnect! + + @connection.transaction do + @connection.create_table('pg_uuids', id: false) do |t| + t.primary_key :id, :uuid, default: nil + t.string 'name' + end + end + end + + def teardown + @connection.execute 'drop table if exists pg_uuids' + end + + def test_id_allows_default_override_via_nil + col_desc = @connection.execute("SELECT pg_get_expr(d.adbin, d.adrelid) as default + FROM pg_attribute a + LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum + WHERE a.attname='id' AND a.attrelid = 'pg_uuids'::regclass").first + assert_nil col_desc["default"] + end end diff --git a/activerecord/test/cases/autosave_association_test.rb b/activerecord/test/cases/autosave_association_test.rb index 536ff4882c..580aa96ecd 100644 --- a/activerecord/test/cases/autosave_association_test.rb +++ b/activerecord/test/cases/autosave_association_test.rb @@ -566,7 +566,7 @@ class TestDefaultAutosaveAssociationOnNewRecord < ActiveRecord::TestCase end class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase - self.use_transactional_fixtures = false unless supports_savepoints? + self.use_transactional_fixtures = false def setup super @@ -764,6 +764,20 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase assert_equal 2, @pirate.birds.reload.length end + def test_should_save_new_record_that_has_same_value_as_existing_record_marked_for_destruction_on_field_that_has_unique_index + Bird.connection.add_index :birds, :name, unique: true + + 3.times { |i| @pirate.birds.create(name: "unique_birds_#{i}") } + + @pirate.birds[0].mark_for_destruction + @pirate.birds.build(name: @pirate.birds[0].name) + @pirate.save! + + assert_equal 3, @pirate.birds.reload.length + ensure + Bird.connection.remove_index :birds, column: :name + end + # Add and remove callbacks tests for association collections. %w{ method proc }.each do |callback_type| define_method("test_should_run_add_callback_#{callback_type}s_for_has_many") do @@ -846,8 +860,10 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase @pirate.parrots.each { |parrot| parrot.mark_for_destruction } assert @pirate.save - assert_queries(0) do - assert @pirate.save + Pirate.transaction do + assert_queries(0) do + assert @pirate.save + end end end diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index bd568af06a..d20ccaa5ca 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -1228,16 +1228,6 @@ class BasicsTest < ActiveRecord::TestCase assert_no_queries { assert true } end - def test_to_param_should_return_string - assert_kind_of String, Client.first.to_param - end - - def test_to_param_returns_id_even_if_not_persisted - client = Client.new - client.id = 1 - assert_equal "1", client.to_param - end - def test_inspect_class assert_equal 'ActiveRecord::Base', ActiveRecord::Base.inspect assert_equal 'LoosePerson(abstract)', LoosePerson.inspect @@ -1431,62 +1421,6 @@ class BasicsTest < ActiveRecord::TestCase assert_equal [], AbstractCompany.attribute_names end - def test_cache_key_for_existing_record_is_not_timezone_dependent - ActiveRecord::Base.time_zone_aware_attributes = true - - Time.zone = "UTC" - utc_key = Developer.first.cache_key - - Time.zone = "EST" - est_key = Developer.first.cache_key - - assert_equal utc_key, est_key - end - - def test_cache_key_format_for_existing_record_with_updated_at - dev = Developer.first - assert_equal "developers/#{dev.id}-#{dev.updated_at.utc.to_s(:nsec)}", dev.cache_key - end - - def test_cache_key_format_for_existing_record_with_updated_at_and_custom_cache_timestamp_format - dev = CachedDeveloper.first - assert_equal "cached_developers/#{dev.id}-#{dev.updated_at.utc.to_s(:number)}", dev.cache_key - end - - def test_cache_key_changes_when_child_touched - car = Car.create - Bulb.create(car: car) - - key = car.cache_key - car.bulb.touch - car.reload - assert_not_equal key, car.cache_key - end - - def test_cache_key_format_for_existing_record_with_nil_updated_timestamps - dev = Developer.first - dev.update_columns(updated_at: nil, updated_on: nil) - assert_match(/\/#{dev.id}$/, dev.cache_key) - end - - def test_cache_key_for_updated_on - dev = Developer.first - dev.updated_at = nil - assert_equal "developers/#{dev.id}-#{dev.updated_on.utc.to_s(:nsec)}", dev.cache_key - end - - def test_cache_key_for_newer_updated_at - dev = Developer.first - dev.updated_at += 3600 - assert_equal "developers/#{dev.id}-#{dev.updated_at.utc.to_s(:nsec)}", dev.cache_key - end - - def test_cache_key_for_newer_updated_on - dev = Developer.first - dev.updated_on += 3600 - assert_equal "developers/#{dev.id}-#{dev.updated_on.utc.to_s(:nsec)}", dev.cache_key - end - def test_touch_should_raise_error_on_a_new_object company = Company.new(:rating => 1, :name => "37signals", :firm_name => "37signals") assert_raises(ActiveRecord::ActiveRecordError) do @@ -1494,13 +1428,6 @@ class BasicsTest < ActiveRecord::TestCase end end - def test_cache_key_format_is_precise_enough - dev = Developer.first - key = dev.cache_key - dev.touch - assert_not_equal key, dev.cache_key - end - def test_uniq_delegates_to_scoped scope = stub Bird.stubs(:all).returns(mock(:uniq => scope)) diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb index b0b647cbf7..f49bef2346 100644 --- a/activerecord/test/cases/calculations_test.rb +++ b/activerecord/test/cases/calculations_test.rb @@ -28,6 +28,10 @@ class CalculationsTest < ActiveRecord::TestCase assert_equal 53.0, value end + def test_should_resolve_aliased_attributes + assert_equal 318, Account.sum(:available_credit) + end + def test_should_return_decimal_average_of_integer_field value = Account.average(:id) assert_equal 3.5, value @@ -352,6 +356,10 @@ class CalculationsTest < ActiveRecord::TestCase assert_equal 4, Account.select(:credit_limit).uniq.count end + def test_count_with_aliased_attribute + assert_equal 6, Account.count(:available_credit) + end + def test_count_with_column_and_options_parameter assert_equal 2, Account.where("credit_limit = 50 AND firm_id IS NOT NULL").count(:firm_id) end @@ -488,6 +496,10 @@ class CalculationsTest < ActiveRecord::TestCase assert_equal [contract.id], company.contracts.pluck(:id) end + def test_pluck_on_aliased_attribute + assert_equal 'The First Topic', Topic.order(:id).pluck(:heading).first + end + def test_pluck_with_serialization t = Topic.create!(:content => { :foo => :bar }) assert_equal [{:foo => :bar}], Topic.where(:id => t.id).pluck(:content) diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb index 557cc7e7a0..7db9aef218 100644 --- a/activerecord/test/cases/finder_test.rb +++ b/activerecord/test/cases/finder_test.rb @@ -47,7 +47,8 @@ class FinderTest < ActiveRecord::TestCase def test_exists assert Topic.exists?(1) assert Topic.exists?("1") - assert Topic.exists?(:author_name => "David") + assert Topic.exists?(title: "The First Topic") + assert Topic.exists?(heading: "The First Topic") assert Topic.exists?(:author_name => "Mary", :approved => true) assert Topic.exists?(["parent_id = ?", 1]) assert !Topic.exists?(45) diff --git a/activerecord/test/cases/integration_test.rb b/activerecord/test/cases/integration_test.rb new file mode 100644 index 0000000000..b0a7cda2f3 --- /dev/null +++ b/activerecord/test/cases/integration_test.rb @@ -0,0 +1,87 @@ +require 'cases/helper' +require 'models/company' +require 'models/developer' +require 'models/car' +require 'models/bulb' + +class IntegrationTest < ActiveRecord::TestCase + fixtures :companies, :developers + + def test_to_param_should_return_string + assert_kind_of String, Client.first.to_param + end + + def test_to_param_returns_nil_if_not_persisted + client = Client.new + assert_equal nil, client.to_param + end + + def test_to_param_returns_id_if_not_persisted_but_id_is_set + client = Client.new + client.id = 1 + assert_equal '1', client.to_param + end + + def test_cache_key_for_existing_record_is_not_timezone_dependent + ActiveRecord::Base.time_zone_aware_attributes = true + + Time.zone = 'UTC' + utc_key = Developer.first.cache_key + + Time.zone = 'EST' + est_key = Developer.first.cache_key + + assert_equal utc_key, est_key + end + + def test_cache_key_format_for_existing_record_with_updated_at + dev = Developer.first + assert_equal "developers/#{dev.id}-#{dev.updated_at.utc.to_s(:nsec)}", dev.cache_key + end + + def test_cache_key_format_for_existing_record_with_updated_at_and_custom_cache_timestamp_format + dev = CachedDeveloper.first + assert_equal "cached_developers/#{dev.id}-#{dev.updated_at.utc.to_s(:number)}", dev.cache_key + end + + def test_cache_key_changes_when_child_touched + car = Car.create + Bulb.create(car: car) + + key = car.cache_key + car.bulb.touch + car.reload + assert_not_equal key, car.cache_key + end + + def test_cache_key_format_for_existing_record_with_nil_updated_timestamps + dev = Developer.first + dev.update_columns(updated_at: nil, updated_on: nil) + assert_match(/\/#{dev.id}$/, dev.cache_key) + end + + def test_cache_key_for_updated_on + dev = Developer.first + dev.updated_at = nil + assert_equal "developers/#{dev.id}-#{dev.updated_on.utc.to_s(:nsec)}", dev.cache_key + end + + def test_cache_key_for_newer_updated_at + dev = Developer.first + dev.updated_at += 3600 + assert_equal "developers/#{dev.id}-#{dev.updated_at.utc.to_s(:nsec)}", dev.cache_key + end + + def test_cache_key_for_newer_updated_on + dev = Developer.first + dev.updated_on += 3600 + assert_equal "developers/#{dev.id}-#{dev.updated_on.utc.to_s(:nsec)}", dev.cache_key + end + + def test_cache_key_format_is_precise_enough + dev = Developer.first + key = dev.cache_key + dev.touch + assert_not_equal key, dev.cache_key + end +end diff --git a/activerecord/test/cases/invertible_migration_test.rb b/activerecord/test/cases/invertible_migration_test.rb index be59ffc4ab..428145d00b 100644 --- a/activerecord/test/cases/invertible_migration_test.rb +++ b/activerecord/test/cases/invertible_migration_test.rb @@ -58,6 +58,24 @@ module ActiveRecord end end + class RemoveIndexMigration1 < SilentMigration + def self.up + create_table("horses") do |t| + t.column :name, :string + t.column :color, :string + t.index [:name, :color] + end + end + end + + class RemoveIndexMigration2 < SilentMigration + def change + change_table("horses") do |t| + t.remove_index [:name, :color] + end + end + end + class LegacyMigration < ActiveRecord::Migration def self.up create_table("horses") do |t| @@ -104,6 +122,16 @@ module ActiveRecord end end + def test_exception_on_removing_index_without_column_option + RemoveIndexMigration1.new.migrate(:up) + migration = RemoveIndexMigration2.new + migration.migrate(:up) + + assert_raises(IrreversibleMigration) do + migration.migrate(:down) + end + end + def test_migrate_up migration = InvertibleMigration.new migration.migrate(:up) diff --git a/activerecord/test/cases/nested_attributes_test.rb b/activerecord/test/cases/nested_attributes_test.rb index b6e140b912..165b7454b7 100644 --- a/activerecord/test/cases/nested_attributes_test.rb +++ b/activerecord/test/cases/nested_attributes_test.rb @@ -131,6 +131,20 @@ class TestNestedAttributesInGeneral < ActiveRecord::TestCase assert_equal 's1', ship.reload.name end + def test_reuse_already_built_new_record + pirate = Pirate.new + ship_built_first = pirate.build_ship + pirate.ship_attributes = { name: 'Ship 1' } + assert_equal ship_built_first.object_id, pirate.ship.object_id + end + + def test_do_not_allow_assigning_foreign_key_when_reusing_existing_new_record + pirate = Pirate.create!(catchphrase: "Don' botharrr talkin' like one, savvy?") + pirate.build_ship + pirate.ship_attributes = { name: 'Ship 1', pirate_id: pirate.id + 1 } + assert_equal pirate.id, pirate.ship.pirate_id + end + def test_reject_if_with_a_proc_which_returns_true_always_for_has_many Man.accepts_nested_attributes_for :interests, :reject_if => proc {|attributes| true } man = Man.create(name: "John") diff --git a/activerecord/test/cases/relation/where_test.rb b/activerecord/test/cases/relation/where_test.rb index c43c7601a2..d333be3560 100644 --- a/activerecord/test/cases/relation/where_test.rb +++ b/activerecord/test/cases/relation/where_test.rb @@ -5,6 +5,7 @@ require 'models/treasure' require 'models/post' require 'models/comment' require 'models/edge' +require 'models/topic' module ActiveRecord class WhereTest < ActiveRecord::TestCase @@ -80,6 +81,13 @@ module ActiveRecord assert_equal expected.to_sql, actual.to_sql end + def test_aliased_attribute + expected = Topic.where(heading: 'The First Topic') + actual = Topic.where(title: 'The First Topic') + + assert_equal expected.to_sql, actual.to_sql + end + def test_where_error assert_raises(ActiveRecord::StatementInvalid) do Post.where(:id => { 'posts.author_id' => 10 }).first diff --git a/activerecord/test/cases/sanitize_test.rb b/activerecord/test/cases/sanitize_test.rb index 817897ceac..f061c28e88 100644 --- a/activerecord/test/cases/sanitize_test.rb +++ b/activerecord/test/cases/sanitize_test.rb @@ -5,6 +5,16 @@ class SanitizeTest < ActiveRecord::TestCase def setup end + def test_sanitize_sql_hash_handles_associations + if current_adapter?(:MysqlAdapter, :Mysql2Adapter) + expected_value = "`adorable_animals`.`name` = 'Bambi'" + else + expected_value = "\"adorable_animals\".\"name\" = 'Bambi'" + end + + assert_equal expected_value, Binary.send(:sanitize_sql_hash, {adorable_animals: {name: 'Bambi'}}) + end + def test_sanitize_sql_array_handles_string_interpolation quoted_bambi = ActiveRecord::Base.connection.quote_string("Bambi") assert_equal "name=#{quoted_bambi}", Binary.send(:sanitize_sql_array, ["name=%s", "Bambi"]) diff --git a/activerecord/test/models/company.rb b/activerecord/test/models/company.rb index 3ca8f69646..dcda62e71d 100644 --- a/activerecord/test/models/company.rb +++ b/activerecord/test/models/company.rb @@ -206,6 +206,8 @@ class Account < ActiveRecord::Base belongs_to :firm, :class_name => 'Company' belongs_to :unautosaved_firm, :foreign_key => "firm_id", :class_name => "Firm", :autosave => false + alias_attribute :available_credit, :credit_limit + def self.destroyed_account_ids @destroyed_account_ids ||= Hash.new { |h,k| h[k] = [] } end diff --git a/activesupport/lib/active_support/core_ext/array/grouping.rb b/activesupport/lib/active_support/core_ext/array/grouping.rb index 640e6e9328..dbddc7a7b4 100644 --- a/activesupport/lib/active_support/core_ext/array/grouping.rb +++ b/activesupport/lib/active_support/core_ext/array/grouping.rb @@ -25,7 +25,7 @@ class Array # subtracting from number gives how many to add; # modulo number ensures we don't add group of just fill. padding = (number - size % number) % number - collection = dup.concat([fill_with] * padding) + collection = dup.concat(Array.new(padding, fill_with)) end if block_given? diff --git a/activesupport/lib/active_support/core_ext/date.rb b/activesupport/lib/active_support/core_ext/date.rb index 5f13f5f70f..465fedda80 100644 --- a/activesupport/lib/active_support/core_ext/date.rb +++ b/activesupport/lib/active_support/core_ext/date.rb @@ -2,5 +2,4 @@ require 'active_support/core_ext/date/acts_like' require 'active_support/core_ext/date/calculations' require 'active_support/core_ext/date/conversions' require 'active_support/core_ext/date/zones' -require 'active_support/core_ext/date/infinite_comparable' diff --git a/activesupport/lib/active_support/core_ext/date/infinite_comparable.rb b/activesupport/lib/active_support/core_ext/date/infinite_comparable.rb deleted file mode 100644 index ca5d793942..0000000000 --- a/activesupport/lib/active_support/core_ext/date/infinite_comparable.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'active_support/core_ext/infinite_comparable' - -class Date - include InfiniteComparable -end diff --git a/activesupport/lib/active_support/core_ext/date_time.rb b/activesupport/lib/active_support/core_ext/date_time.rb index 024af91738..e8a27b9f38 100644 --- a/activesupport/lib/active_support/core_ext/date_time.rb +++ b/activesupport/lib/active_support/core_ext/date_time.rb @@ -2,4 +2,3 @@ require 'active_support/core_ext/date_time/acts_like' require 'active_support/core_ext/date_time/calculations' require 'active_support/core_ext/date_time/conversions' require 'active_support/core_ext/date_time/zones' -require 'active_support/core_ext/date_time/infinite_comparable' diff --git a/activesupport/lib/active_support/core_ext/date_time/calculations.rb b/activesupport/lib/active_support/core_ext/date_time/calculations.rb index 9f0864d9bb..937567440b 100644 --- a/activesupport/lib/active_support/core_ext/date_time/calculations.rb +++ b/activesupport/lib/active_support/core_ext/date_time/calculations.rb @@ -1,3 +1,4 @@ +require 'date' require 'active_support/deprecation' class DateTime @@ -154,4 +155,11 @@ class DateTime def utc_offset (offset * 86400).to_i end + + # Layers additional behavior on DateTime#<=> so that Time and + # ActiveSupport::TimeWithZone instances can be compared with a DateTime. + def <=>(other) + super other.to_datetime + end + end diff --git a/activesupport/lib/active_support/core_ext/date_time/conversions.rb b/activesupport/lib/active_support/core_ext/date_time/conversions.rb index b7d8414a9d..df07917d19 100644 --- a/activesupport/lib/active_support/core_ext/date_time/conversions.rb +++ b/activesupport/lib/active_support/core_ext/date_time/conversions.rb @@ -1,3 +1,4 @@ +require 'date' require 'active_support/inflector/methods' require 'active_support/core_ext/time/conversions' require 'active_support/core_ext/date_time/calculations' diff --git a/activesupport/lib/active_support/core_ext/date_time/infinite_comparable.rb b/activesupport/lib/active_support/core_ext/date_time/infinite_comparable.rb deleted file mode 100644 index 8a282b19f2..0000000000 --- a/activesupport/lib/active_support/core_ext/date_time/infinite_comparable.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'active_support/core_ext/infinite_comparable' - -class DateTime - include InfiniteComparable -end diff --git a/activesupport/lib/active_support/core_ext/date_time/zones.rb b/activesupport/lib/active_support/core_ext/date_time/zones.rb index 6457ffbaf6..01a627f8af 100644 --- a/activesupport/lib/active_support/core_ext/date_time/zones.rb +++ b/activesupport/lib/active_support/core_ext/date_time/zones.rb @@ -1,3 +1,4 @@ +require 'date' require 'active_support/core_ext/time/zones' class DateTime diff --git a/activesupport/lib/active_support/core_ext/infinite_comparable.rb b/activesupport/lib/active_support/core_ext/infinite_comparable.rb deleted file mode 100644 index b78b2deaad..0000000000 --- a/activesupport/lib/active_support/core_ext/infinite_comparable.rb +++ /dev/null @@ -1,35 +0,0 @@ -require 'active_support/concern' -require 'active_support/core_ext/module/aliasing' -require 'active_support/core_ext/object/try' - -module InfiniteComparable - extend ActiveSupport::Concern - - included do - alias_method_chain :<=>, :infinity - end - - define_method :'<=>_with_infinity' do |other| - if other.class == self.class - public_send :'<=>_without_infinity', other - else - infinite = try(:infinite?) - other_infinite = other.try(:infinite?) - - # inf <=> inf - if infinite && other_infinite - infinite <=> other_infinite - # not_inf <=> inf - elsif other_infinite - -other_infinite - # inf <=> not_inf - elsif infinite - infinite - else - conversion = "to_#{self.class.name.downcase}" - other = other.public_send(conversion) if other.respond_to?(conversion) - public_send :'<=>_without_infinity', other - end - end - end -end diff --git a/activesupport/lib/active_support/core_ext/numeric.rb b/activesupport/lib/active_support/core_ext/numeric.rb index d5cfc2ece4..a6bc0624be 100644 --- a/activesupport/lib/active_support/core_ext/numeric.rb +++ b/activesupport/lib/active_support/core_ext/numeric.rb @@ -1,4 +1,3 @@ require 'active_support/core_ext/numeric/bytes' require 'active_support/core_ext/numeric/time' require 'active_support/core_ext/numeric/conversions' -require 'active_support/core_ext/numeric/infinite_comparable' diff --git a/activesupport/lib/active_support/core_ext/numeric/infinite_comparable.rb b/activesupport/lib/active_support/core_ext/numeric/infinite_comparable.rb deleted file mode 100644 index b5f1b0487b..0000000000 --- a/activesupport/lib/active_support/core_ext/numeric/infinite_comparable.rb +++ /dev/null @@ -1,9 +0,0 @@ -require 'active_support/core_ext/infinite_comparable' - -class Float - include InfiniteComparable -end - -class BigDecimal - include InfiniteComparable -end diff --git a/activesupport/lib/active_support/core_ext/object/to_param.rb b/activesupport/lib/active_support/core_ext/object/to_param.rb index 0d5f3501e5..3b137ce6ae 100644 --- a/activesupport/lib/active_support/core_ext/object/to_param.rb +++ b/activesupport/lib/active_support/core_ext/object/to_param.rb @@ -53,6 +53,6 @@ class Hash def to_param(namespace = nil) collect do |key, value| value.to_query(namespace ? "#{namespace}[#{key}]" : key) - end.sort * '&' + end.sort! * '&' end end diff --git a/activesupport/lib/active_support/core_ext/time.rb b/activesupport/lib/active_support/core_ext/time.rb index af6b589b71..32cffe237d 100644 --- a/activesupport/lib/active_support/core_ext/time.rb +++ b/activesupport/lib/active_support/core_ext/time.rb @@ -3,4 +3,3 @@ require 'active_support/core_ext/time/calculations' require 'active_support/core_ext/time/conversions' require 'active_support/core_ext/time/marshal' require 'active_support/core_ext/time/zones' -require 'active_support/core_ext/time/infinite_comparable' diff --git a/activesupport/lib/active_support/core_ext/time/infinite_comparable.rb b/activesupport/lib/active_support/core_ext/time/infinite_comparable.rb deleted file mode 100644 index 63795885f5..0000000000 --- a/activesupport/lib/active_support/core_ext/time/infinite_comparable.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'active_support/core_ext/infinite_comparable' - -class Time - include InfiniteComparable -end diff --git a/activesupport/lib/active_support/testing/isolation.rb b/activesupport/lib/active_support/testing/isolation.rb index d70d971538..e16b73a036 100644 --- a/activesupport/lib/active_support/testing/isolation.rb +++ b/activesupport/lib/active_support/testing/isolation.rb @@ -40,6 +40,10 @@ module ActiveSupport def method_missing(name, *args) @calls << [name, args] end + + def info_signal + Signal.list['INFO'] + end end module Isolation diff --git a/activesupport/test/callbacks_test.rb b/activesupport/test/callbacks_test.rb index 5afc2094e8..edc8edd8a6 100644 --- a/activesupport/test/callbacks_test.rb +++ b/activesupport/test/callbacks_test.rb @@ -752,7 +752,7 @@ module CallbacksTest class PerKeyOptionDeprecationTest < ActiveSupport::TestCase - def test_per_key_option_deprecaton + def test_per_key_option_deprecation assert_raise NotImplementedError do Phone.class_eval do set_callback :save, :before, :before_save1, :per_key => {:if => "true"} diff --git a/activesupport/test/core_ext/date_ext_test.rb b/activesupport/test/core_ext/date_ext_test.rb index f3fa96ec6f..b1adf6d396 100644 --- a/activesupport/test/core_ext/date_ext_test.rb +++ b/activesupport/test/core_ext/date_ext_test.rb @@ -357,11 +357,6 @@ class DateExtBehaviorTest < ActiveSupport::TestCase Date.today.freeze.freeze end end - - def test_compare_with_infinity - assert_equal(-1, Date.today <=> Float::INFINITY) - assert_equal(1, Date.today <=> -Float::INFINITY) - end end class DateExtConversionsTest < ActiveSupport::TestCase diff --git a/activesupport/test/core_ext/date_time_ext_test.rb b/activesupport/test/core_ext/date_time_ext_test.rb index 7be578599b..3e76b8a9b1 100644 --- a/activesupport/test/core_ext/date_time_ext_test.rb +++ b/activesupport/test/core_ext/date_time_ext_test.rb @@ -335,10 +335,3 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ') end end - -class DateTimeExtBehaviorTest < ActiveSupport::TestCase - def test_compare_with_infinity - assert_equal(-1, DateTime.now <=> Float::INFINITY) - assert_equal(1, DateTime.now <=> -Float::INFINITY) - end -end diff --git a/activesupport/test/core_ext/numeric_ext_test.rb b/activesupport/test/core_ext/numeric_ext_test.rb index 3744d50864..f22ae3ccac 100644 --- a/activesupport/test/core_ext/numeric_ext_test.rb +++ b/activesupport/test/core_ext/numeric_ext_test.rb @@ -441,57 +441,3 @@ class NumericExtFormattingTest < ActiveSupport::TestCase assert_equal '1 Million', BigDecimal("1000010").to_s(:human) end end - -class NumericExtBehaviorTest < ActiveSupport::TestCase - def setup - @inf = BigDecimal.new('Infinity') - end - - def test_compare_infinity_with_date - assert_equal(-1, -Float::INFINITY <=> Date.today) - assert_equal(1, Float::INFINITY <=> Date.today) - assert_equal(-1, -@inf <=> Date.today) - assert_equal(1, @inf <=> Date.today) - end - - def test_compare_infinty_with_infinty - assert_equal(-1, -Float::INFINITY <=> Float::INFINITY) - assert_equal(1, Float::INFINITY <=> -Float::INFINITY) - assert_equal(0, Float::INFINITY <=> Float::INFINITY) - assert_equal(0, -Float::INFINITY <=> -Float::INFINITY) - - assert_equal(-1, -Float::INFINITY <=> BigDecimal::INFINITY) - assert_equal(1, Float::INFINITY <=> -BigDecimal::INFINITY) - assert_equal(0, Float::INFINITY <=> BigDecimal::INFINITY) - assert_equal(0, -Float::INFINITY <=> -BigDecimal::INFINITY) - - assert_equal(-1, -BigDecimal::INFINITY <=> Float::INFINITY) - assert_equal(1, BigDecimal::INFINITY <=> -Float::INFINITY) - assert_equal(0, BigDecimal::INFINITY <=> Float::INFINITY) - assert_equal(0, -BigDecimal::INFINITY <=> -Float::INFINITY) - end - - def test_compare_infinity_with_time - assert_equal(-1, -Float::INFINITY <=> Time.now) - assert_equal(1, Float::INFINITY <=> Time.now) - assert_equal(-1, -@inf <=> Time.now) - assert_equal(1, @inf <=> Time.now) - end - - def test_compare_infinity_with_datetime - assert_equal(-1, -Float::INFINITY <=> DateTime.now) - assert_equal(1, Float::INFINITY <=> DateTime.now) - assert_equal(-1, -@inf <=> DateTime.now) - assert_equal(1, @inf <=> DateTime.now) - end - - def test_compare_infinity_with_twz - time_zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - twz = ActiveSupport::TimeWithZone.new(Time.now, time_zone) - - assert_equal(-1, -Float::INFINITY <=> twz) - assert_equal(1, Float::INFINITY <=> twz) - assert_equal(-1, -@inf <=> twz) - assert_equal(1, @inf <=> twz) - end -end diff --git a/activesupport/test/core_ext/range_ext_test.rb b/activesupport/test/core_ext/range_ext_test.rb index 6e94d5e10d..3e2355ae23 100644 --- a/activesupport/test/core_ext/range_ext_test.rb +++ b/activesupport/test/core_ext/range_ext_test.rb @@ -1,7 +1,6 @@ require 'abstract_unit' require 'active_support/time' require 'active_support/core_ext/range' -require 'active_support/core_ext/numeric' class RangeTest < ActiveSupport::TestCase def test_to_s_from_dates @@ -17,7 +16,6 @@ class RangeTest < ActiveSupport::TestCase def test_date_range assert_instance_of Range, DateTime.new..DateTime.new assert_instance_of Range, DateTime::Infinity.new..DateTime::Infinity.new - assert_instance_of Range, DateTime.new..DateTime::Infinity.new end def test_overlaps_last_inclusive @@ -92,28 +90,4 @@ class RangeTest < ActiveSupport::TestCase time_range_2 = Time.utc(2005, 12, 10, 17, 31)..Time.utc(2005, 12, 10, 18, 00) assert !time_range_1.overlaps?(time_range_2) end - - def test_infinite_bounds - time_zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - - time = Time.now - date = Date.today - datetime = DateTime.now - twz = ActiveSupport::TimeWithZone.new(time, time_zone) - - infinity1 = Float::INFINITY - infinity2 = BigDecimal.new('Infinity') - - [infinity1, infinity2].each do |infinity| - [time, date, datetime, twz].each do |bound| - [time, date, datetime, twz].each do |value| - assert Range.new(bound, infinity).include?(value + 10.years) - assert Range.new(-infinity, bound).include?(value - 10.years) - - assert !Range.new(bound, infinity).include?(value - 10.years) - assert !Range.new(-infinity, bound).include?(value + 10.years) - end - end - end - end end diff --git a/activesupport/test/core_ext/time_ext_test.rb b/activesupport/test/core_ext/time_ext_test.rb index 2864d7a57f..4e53aff00b 100644 --- a/activesupport/test/core_ext/time_ext_test.rb +++ b/activesupport/test/core_ext/time_ext_test.rb @@ -855,10 +855,3 @@ class TimeExtMarshalingTest < ActiveSupport::TestCase assert_equal Time.local(2004, 2, 29), Time.local(2004, 5, 31).last_quarter end end - -class TimeExtBehaviorTest < ActiveSupport::TestCase - def test_compare_with_infinity - assert_equal(-1, Time.now <=> Float::INFINITY) - assert_equal(1, Time.now <=> -Float::INFINITY) - end -end diff --git a/activesupport/test/core_ext/time_with_zone_test.rb b/activesupport/test/core_ext/time_with_zone_test.rb index 98a87ab9e6..3ce3297874 100644 --- a/activesupport/test/core_ext/time_with_zone_test.rb +++ b/activesupport/test/core_ext/time_with_zone_test.rb @@ -1118,13 +1118,3 @@ class TimeWithZoneMethodsForString < ActiveSupport::TestCase Time.zone = old_tz end end - -class TimeWithZoneExtBehaviorTest < ActiveSupport::TestCase - def test_compare_with_infinity - time_zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] - twz = ActiveSupport::TimeWithZone.new(Time.now, time_zone) - - assert_equal(-1, twz <=> Float::INFINITY) - assert_equal(1, twz <=> -Float::INFINITY) - end -end diff --git a/activesupport/test/json/decoding_test.rb b/activesupport/test/json/decoding_test.rb index d1454902e5..a2d1d0dc39 100644 --- a/activesupport/test/json/decoding_test.rb +++ b/activesupport/test/json/decoding_test.rb @@ -62,21 +62,25 @@ class TestJSONDecoding < ActiveSupport::TestCase backends.each do |backend| TESTS.each do |json, expected| test "json decodes #{json} with the #{backend} backend" do + prev = ActiveSupport.parse_json_times ActiveSupport.parse_json_times = true silence_warnings do ActiveSupport::JSON.with_backend backend do assert_equal expected, ActiveSupport::JSON.decode(json) end end + ActiveSupport.parse_json_times = prev end end test "json decodes time json with time parsing disabled with the #{backend} backend" do + prev = ActiveSupport.parse_json_times ActiveSupport.parse_json_times = false expected = {"a" => "2007-01-01 01:12:34 Z"} ActiveSupport::JSON.with_backend backend do assert_equal expected, ActiveSupport::JSON.decode(%({"a": "2007-01-01 01:12:34 Z"})) end + ActiveSupport.parse_json_times = prev end end diff --git a/activesupport/test/json/encoding_test.rb b/activesupport/test/json/encoding_test.rb index 12ce250eb3..8686dcf929 100644 --- a/activesupport/test/json/encoding_test.rb +++ b/activesupport/test/json/encoding_test.rb @@ -82,6 +82,8 @@ class TestJSONEncoding < ActiveSupport::TestCase constants.grep(/Tests$/).each do |class_tests| define_method("test_#{class_tests[0..-6].underscore}") do begin + prev = ActiveSupport.use_standard_json_time_format + ActiveSupport.escape_html_entities_in_json = class_tests !~ /^Standard/ ActiveSupport.use_standard_json_time_format = class_tests =~ /^Standard/ self.class.const_get(class_tests).each do |pair| @@ -89,7 +91,7 @@ class TestJSONEncoding < ActiveSupport::TestCase end ensure ActiveSupport.escape_html_entities_in_json = false - ActiveSupport.use_standard_json_time_format = false + ActiveSupport.use_standard_json_time_format = prev end end end @@ -172,16 +174,21 @@ class TestJSONEncoding < ActiveSupport::TestCase end def test_time_to_json_includes_local_offset + prev = ActiveSupport.use_standard_json_time_format ActiveSupport.use_standard_json_time_format = true with_env_tz 'US/Eastern' do assert_equal %("2005-02-01T15:15:10-05:00"), ActiveSupport::JSON.encode(Time.local(2005,2,1,15,15,10)) end ensure - ActiveSupport.use_standard_json_time_format = false + ActiveSupport.use_standard_json_time_format = prev end def test_hash_with_time_to_json + prev = ActiveSupport.use_standard_json_time_format + ActiveSupport.use_standard_json_time_format = false assert_equal '{"time":"2009/01/01 00:00:00 +0000"}', { :time => Time.utc(2009) }.to_json + ensure + ActiveSupport.use_standard_json_time_format = prev end def test_nested_hash_with_float @@ -302,12 +309,12 @@ class TestJSONEncoding < ActiveSupport::TestCase assert_equal({"name" => "David", "sub" => { "name" => "David", - "date" => "2010/01/01" }}, JSON.parse(json_custom)) + "date" => "2010-01-01" }}, JSON.parse(json_custom)) assert_equal({"name" => "David", "email" => "sample@example.com"}, JSON.parse(json_strings)) - assert_equal({"name" => "David", "date" => "2010/01/01"}, + assert_equal({"name" => "David", "date" => "2010-01-01"}, JSON.parse(json_string_and_date)) end diff --git a/activesupport/test/message_encryptor_test.rb b/activesupport/test/message_encryptor_test.rb index 06c7e8a1a7..509c453b5c 100644 --- a/activesupport/test/message_encryptor_test.rb +++ b/activesupport/test/message_encryptor_test.rb @@ -56,9 +56,14 @@ class MessageEncryptorTest < ActiveSupport::TestCase end def test_alternative_serialization_method + prev = ActiveSupport.use_standard_json_time_format + ActiveSupport.use_standard_json_time_format = true encryptor = ActiveSupport::MessageEncryptor.new(SecureRandom.hex(64), SecureRandom.hex(64), :serializer => JSONSerializer.new) message = encryptor.encrypt_and_sign({ :foo => 123, 'bar' => Time.utc(2010) }) - assert_equal encryptor.decrypt_and_verify(message), { "foo" => 123, "bar" => "2010-01-01T00:00:00Z" } + exp = { "foo" => 123, "bar" => "2010-01-01T00:00:00Z" } + assert_equal exp, encryptor.decrypt_and_verify(message) + ensure + ActiveSupport.use_standard_json_time_format = prev end private diff --git a/activesupport/test/message_verifier_test.rb b/activesupport/test/message_verifier_test.rb index 5adff41653..a8633f7299 100644 --- a/activesupport/test/message_verifier_test.rb +++ b/activesupport/test/message_verifier_test.rb @@ -45,9 +45,14 @@ class MessageVerifierTest < ActiveSupport::TestCase end def test_alternative_serialization_method + prev = ActiveSupport.use_standard_json_time_format + ActiveSupport.use_standard_json_time_format = true verifier = ActiveSupport::MessageVerifier.new("Hey, I'm a secret!", :serializer => JSONSerializer.new) message = verifier.generate({ :foo => 123, 'bar' => Time.utc(2010) }) - assert_equal verifier.verify(message), { "foo" => 123, "bar" => "2010-01-01T00:00:00Z" } + exp = { "foo" => 123, "bar" => "2010-01-01T00:00:00Z" } + assert_equal exp, verifier.verify(message) + ensure + ActiveSupport.use_standard_json_time_format = prev end def assert_not_verified(message) diff --git a/activesupport/test/test_case_test.rb b/activesupport/test/test_case_test.rb index dfe9f3c11c..a1bdcf2396 100644 --- a/activesupport/test/test_case_test.rb +++ b/activesupport/test/test_case_test.rb @@ -19,6 +19,9 @@ module ActiveSupport def record(*args) end + + def info_signal + end end def test_standard_error_raised_within_setup_callback_is_puked diff --git a/activesupport/test/xml_mini/nokogirisax_engine_test.rb b/activesupport/test/xml_mini/nokogirisax_engine_test.rb index d4f63f6bd0..84a5c44a87 100644 --- a/activesupport/test/xml_mini/nokogirisax_engine_test.rb +++ b/activesupport/test/xml_mini/nokogirisax_engine_test.rb @@ -56,9 +56,9 @@ class NokogiriSAXEngineTest < ActiveSupport::TestCase end end - def test_setting_nokogiri_as_backend - XmlMini.backend = 'Nokogiri' - assert_equal XmlMini_Nokogiri, XmlMini.backend + def test_setting_nokogirisax_as_backend + XmlMini.backend = 'NokogiriSAX' + assert_equal XmlMini_NokogiriSAX, XmlMini.backend end def test_blank_returns_empty_hash diff --git a/guides/code/getting_started/.gitignore b/guides/code/getting_started/.gitignore index 25a742dff0..6a502e997f 100644 --- a/guides/code/getting_started/.gitignore +++ b/guides/code/getting_started/.gitignore @@ -1,4 +1,4 @@ -# See http://help.github.com/ignore-files/ for more about ignoring files. +# See https://help.github.com/articles/ignoring-files for more about ignoring files. # # If you find yourself ignoring temporary files generated by your text editor # or operating system, you probably want to add a global ignore instead: diff --git a/guides/code/getting_started/Gemfile.lock b/guides/code/getting_started/Gemfile.lock index 823fac5ff7..888a6b30e2 100644 --- a/guides/code/getting_started/Gemfile.lock +++ b/guides/code/getting_started/Gemfile.lock @@ -92,7 +92,7 @@ GEM multi_json (~> 1.0) hike (1.2.1) i18n (0.6.1) - jbuilder (1.0.2) + jbuilder (1.3.0) activesupport (>= 3.0.0) jquery-rails (2.2.0) railties (>= 3.0, < 5.0) diff --git a/guides/source/4_0_release_notes.md b/guides/source/4_0_release_notes.md index 50a3c6fabc..5f2d994dd2 100644 --- a/guides/source/4_0_release_notes.md +++ b/guides/source/4_0_release_notes.md @@ -59,15 +59,15 @@ Extraction of features to gems In Rails 4.0, several features have been extracted into gems. You can simply add the extracted gems to your `Gemfile` to bring the functionality back. -* Hash-based & Dynamic finder methods ([Github](https://github.com/rails/activerecord-deprecated_finders)) -* Mass assignment protection in Active Record models ([Github](https://github.com/rails/protected_attributes), [Pull Request](https://github.com/rails/rails/pull/7251)) -* ActiveRecord::SessionStore ([Github](https://github.com/rails/activerecord-session_store), [Pull Request](https://github.com/rails/rails/pull/7436)) -* Active Record Observers ([Github](https://github.com/rails/rails-observers), [Commit](https://github.com/rails/rails/commit/39e85b3b90c58449164673909a6f1893cba290b2)) -* Active Resource ([Github](https://github.com/rails/activeresource), [Pull Request](https://github.com/rails/rails/pull/572), [Blog](http://yetimedia.tumblr.com/post/35233051627/activeresource-is-dead-long-live-activeresource)) -* Action Caching ([Github](https://github.com/rails/actionpack-action_caching), [Pull Request](https://github.com/rails/rails/pull/7833)) -* Page Caching ([Github](https://github.com/rails/actionpack-page_caching), [Pull Request](https://github.com/rails/rails/pull/7833)) -* Sprockets ([Github](https://github.com/rails/sprockets-rails)) -* Performance tests ([Github](https://github.com/rails/rails-perftest), [Pull Request](https://github.com/rails/rails/pull/8876)) +* Hash-based & Dynamic finder methods ([GitHub](https://github.com/rails/activerecord-deprecated_finders)) +* Mass assignment protection in Active Record models ([GitHub](https://github.com/rails/protected_attributes), [Pull Request](https://github.com/rails/rails/pull/7251)) +* ActiveRecord::SessionStore ([GitHub](https://github.com/rails/activerecord-session_store), [Pull Request](https://github.com/rails/rails/pull/7436)) +* Active Record Observers ([GitHub](https://github.com/rails/rails-observers), [Commit](https://github.com/rails/rails/commit/39e85b3b90c58449164673909a6f1893cba290b2)) +* Active Resource ([GitHub](https://github.com/rails/activeresource), [Pull Request](https://github.com/rails/rails/pull/572), [Blog](http://yetimedia.tumblr.com/post/35233051627/activeresource-is-dead-long-live-activeresource)) +* Action Caching ([GitHub](https://github.com/rails/actionpack-action_caching), [Pull Request](https://github.com/rails/rails/pull/7833)) +* Page Caching ([GitHub](https://github.com/rails/actionpack-page_caching), [Pull Request](https://github.com/rails/rails/pull/7833)) +* Sprockets ([GitHub](https://github.com/rails/sprockets-rails)) +* Performance tests ([GitHub](https://github.com/rails/rails-perftest), [Pull Request](https://github.com/rails/rails/pull/8876)) Documentation ------------- diff --git a/guides/source/credits.html.erb b/guides/source/credits.html.erb index 34be07ef81..74ae7216e1 100644 --- a/guides/source/credits.html.erb +++ b/guides/source/credits.html.erb @@ -32,7 +32,7 @@ Ruby on Rails Guides: Credits <% end %> <%= author('Oscar Del Ben', 'oscardelben', 'oscardelben.jpg') do %> -Oscar Del Ben is a software engineer at <a href="http://www.wildfireapp.com/">Wildfire</a>. He's a regular open source contributor (<a href="https://github.com/oscardelben">Github account</a>) and tweets regularly at <a href="https://twitter.com/oscardelben">@oscardelben</a>. +Oscar Del Ben is a software engineer at <a href="http://www.wildfireapp.com/">Wildfire</a>. He's a regular open source contributor (<a href="https://github.com/oscardelben">GitHub account</a>) and tweets regularly at <a href="https://twitter.com/oscardelben">@oscardelben</a>. <% end %> <%= author('Frederick Cheung', 'fcheung') do %> diff --git a/guides/source/i18n.md b/guides/source/i18n.md index 3c4c1e2cb3..65a85efa69 100644 --- a/guides/source/i18n.md +++ b/guides/source/i18n.md @@ -417,7 +417,7 @@ So that would give you:  -TIP: Right now you might need to add some more date/time formats in order to make the I18n backend work as expected (at least for the 'pirate' locale). Of course, there's a great chance that somebody already did all the work by **translating Rails' defaults for your locale**. See the [rails-i18n repository at Github](https://github.com/svenfuchs/rails-i18n/tree/master/rails/locale) for an archive of various locale files. When you put such file(s) in `config/locales/` directory, they will automatically be ready for use. +TIP: Right now you might need to add some more date/time formats in order to make the I18n backend work as expected (at least for the 'pirate' locale). Of course, there's a great chance that somebody already did all the work by **translating Rails' defaults for your locale**. See the [rails-i18n repository at GitHub](https://github.com/svenfuchs/rails-i18n/tree/master/rails/locale) for an archive of various locale files. When you put such file(s) in `config/locales/` directory, they will automatically be ready for use. ### Inflection Rules For Other Locales @@ -980,8 +980,8 @@ Resources * [rails-i18n.org](http://rails-i18n.org) - Homepage of the rails-i18n project. You can find lots of useful resources on the [wiki](http://rails-i18n.org/wiki). * [Google group: rails-i18n](http://groups.google.com/group/rails-i18n) - The project's mailing list. -* [Github: rails-i18n](https://github.com/svenfuchs/rails-i18n/tree/master) - Code repository for the rails-i18n project. Most importantly you can find lots of [example translations](https://github.com/svenfuchs/rails-i18n/tree/master/rails/locale) for Rails that should work for your application in most cases. -* [Github: i18n](https://github.com/svenfuchs/i18n/tree/master) - Code repository for the i18n gem. +* [GitHub: rails-i18n](https://github.com/svenfuchs/rails-i18n/tree/master) - Code repository for the rails-i18n project. Most importantly you can find lots of [example translations](https://github.com/svenfuchs/rails-i18n/tree/master/rails/locale) for Rails that should work for your application in most cases. +* [GitHub: i18n](https://github.com/svenfuchs/i18n/tree/master) - Code repository for the i18n gem. * [Lighthouse: rails-i18n](http://i18n.lighthouseapp.com/projects/14948-rails-i18n/overview) - Issue tracker for the rails-i18n project. * [Lighthouse: i18n](http://i18n.lighthouseapp.com/projects/14947-ruby-i18n/overview) - Issue tracker for the i18n gem. diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index e1b98eda55..04cdbec428 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -1,3 +1,8 @@ +* Fixes bug with scaffold generator with `--assets=false --resource-route=false`. + Fixes #9525. + + *Arun Agrawal* + * Rails::Railtie no longer forces the Rails::Configurable module on everything that subclassess it. Instead, the methods from Rails::Configurable have been moved to class methods in Railtie and the Railtie has been made abstract. diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index 2d5aa9d952..914e4393c4 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -93,6 +93,7 @@ module Rails # dispatches the request to the underlying middleware stack. def call(env) env["ORIGINAL_FULLPATH"] = build_original_fullpath(env) + env["ORIGINAL_SCRIPT_NAME"] = env["SCRIPT_NAME"] super(env) end diff --git a/railties/lib/rails/commands.rb b/railties/lib/rails/commands.rb index 0d1286031c..e8c42b149b 100644 --- a/railties/lib/rails/commands.rb +++ b/railties/lib/rails/commands.rb @@ -66,7 +66,7 @@ when 'console' Rails::Console.start(Rails.application, options) when 'server' - # Change to the application's path if there is no config.ru file in current dir. + # Change to the application's path if there is no config.ru file in current directory. # This allows us to run `rails server` from other directories, but still get # the main config.ru and properly set the tmp directory. Dir.chdir(File.expand_path('../../', APP_PATH)) unless File.exists?(File.expand_path("config.ru")) diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index b2d1be9b51..5877579fc4 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -56,6 +56,7 @@ module Rails def app directory 'app' + keep_file 'app/assets/images' keep_file 'app/mailers' keep_file 'app/models' diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile index ace804ffe6..243e7e9da8 100644 --- a/railties/lib/rails/generators/rails/app/templates/Gemfile +++ b/railties/lib/rails/generators/rails/app/templates/Gemfile @@ -10,7 +10,7 @@ source 'https://rubygems.org' <%= javascript_gemfile_entry -%> # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder -gem 'jbuilder', '~> 1.0.1' +gem 'jbuilder', '~> 1.2' group :doc do # bundle exec rake doc:rails generates the API under doc/api. diff --git a/railties/lib/rails/generators/rails/app/templates/app/assets/images/.keep b/railties/lib/rails/generators/rails/app/templates/app/assets/images/.keep deleted file mode 100644 index e69de29bb2..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/app/assets/images/.keep +++ /dev/null diff --git a/railties/lib/rails/generators/rails/app/templates/gitignore b/railties/lib/rails/generators/rails/app/templates/gitignore index 25a742dff0..6a502e997f 100644 --- a/railties/lib/rails/generators/rails/app/templates/gitignore +++ b/railties/lib/rails/generators/rails/app/templates/gitignore @@ -1,4 +1,4 @@ -# See http://help.github.com/ignore-files/ for more about ignoring files. +# See https://help.github.com/articles/ignoring-files for more about ignoring files. # # If you find yourself ignoring temporary files generated by your text editor # or operating system, you probably want to add a global ignore instead: diff --git a/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb index 2a0522e81c..e89789e72b 100644 --- a/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb +++ b/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb @@ -8,6 +8,8 @@ module Rails class_option :stylesheets, type: :boolean, desc: "Generate Stylesheets" class_option :stylesheet_engine, desc: "Engine for Stylesheets" + class_option :assets, type: :boolean + class_option :resource_route, type: :boolean def handle_skip @options = @options.merge(stylesheets: false) unless options[:assets] diff --git a/railties/lib/rails/tasks/documentation.rake b/railties/lib/rails/tasks/documentation.rake index f89d6b12e1..d45e892424 100644 --- a/railties/lib/rails/tasks/documentation.rake +++ b/railties/lib/rails/tasks/documentation.rake @@ -1,61 +1,72 @@ -require 'rdoc/task' -require 'rails/api/task' +begin + require 'rdoc/task' +rescue LoadError + # Rubinius installs RDoc as a gem, and for this interpreter "rdoc/task" is + # available only if the application bundle includes "rdoc" (normally as a + # dependency of the "sdoc" gem.) + # + # If RDoc is not available it is fine that we do not generate the tasks that + # depend on it. Just be robust to this gotcha and go on. +else + require 'rails/api/task' -# Monkey-patch to remove redoc'ing and clobber descriptions to cut down on rake -T noise -class RDocTaskWithoutDescriptions < RDoc::Task - include ::Rake::DSL + # Monkey-patch to remove redoc'ing and clobber descriptions to cut down on rake -T noise + class RDocTaskWithoutDescriptions < RDoc::Task + include ::Rake::DSL - def define - task rdoc_task_name + def define + task rdoc_task_name - task rerdoc_task_name => [clobber_task_name, rdoc_task_name] + task rerdoc_task_name => [clobber_task_name, rdoc_task_name] - task clobber_task_name do - rm_r rdoc_dir rescue nil - end + task clobber_task_name do + rm_r rdoc_dir rescue nil + end - task :clobber => [clobber_task_name] + task :clobber => [clobber_task_name] - directory @rdoc_dir - task rdoc_task_name => [rdoc_target] - file rdoc_target => @rdoc_files + [Rake.application.rakefile] do - rm_r @rdoc_dir rescue nil - @before_running_rdoc.call if @before_running_rdoc - args = option_list + @rdoc_files - if @external - argstring = args.join(' ') - sh %{ruby -Ivendor vendor/rd #{argstring}} - else - require 'rdoc/rdoc' - RDoc::RDoc.new.document(args) + directory @rdoc_dir + task rdoc_task_name => [rdoc_target] + file rdoc_target => @rdoc_files + [Rake.application.rakefile] do + rm_r @rdoc_dir rescue nil + @before_running_rdoc.call if @before_running_rdoc + args = option_list + @rdoc_files + if @external + argstring = args.join(' ') + sh %{ruby -Ivendor vendor/rd #{argstring}} + else + require 'rdoc/rdoc' + RDoc::RDoc.new.document(args) + end end + self end - self end -end -namespace :doc do - def gem_path(gem_name) - path = $LOAD_PATH.grep(/#{gem_name}[\w.-]*\/lib$/).first - yield File.dirname(path) if path - end + namespace :doc do + def gem_path(gem_name) + path = $LOAD_PATH.grep(/#{gem_name}[\w.-]*\/lib$/).first + yield File.dirname(path) if path + end - RDocTaskWithoutDescriptions.new("app") { |rdoc| - rdoc.rdoc_dir = 'doc/app' - rdoc.template = ENV['template'] if ENV['template'] - rdoc.title = ENV['title'] || "Rails Application Documentation" - rdoc.options << '--line-numbers' - rdoc.options << '--charset' << 'utf-8' - rdoc.rdoc_files.include('README.rdoc') - rdoc.rdoc_files.include('app/**/*.rb') - rdoc.rdoc_files.include('lib/**/*.rb') - } - Rake::Task['doc:app'].comment = "Generate docs for the app -- also available doc:rails, doc:guides (options: TEMPLATE=/rdoc-template.rb, TITLE=\"Custom Title\")" + RDocTaskWithoutDescriptions.new("app") { |rdoc| + rdoc.rdoc_dir = 'doc/app' + rdoc.template = ENV['template'] if ENV['template'] + rdoc.title = ENV['title'] || "Rails Application Documentation" + rdoc.options << '--line-numbers' + rdoc.options << '--charset' << 'utf-8' + rdoc.rdoc_files.include('README.rdoc') + rdoc.rdoc_files.include('app/**/*.rb') + rdoc.rdoc_files.include('lib/**/*.rb') + } + Rake::Task['doc:app'].comment = "Generate docs for the app -- also available doc:rails, doc:guides (options: TEMPLATE=/rdoc-template.rb, TITLE=\"Custom Title\")" - # desc 'Generate documentation for the Rails framework.' - Rails::API::AppTask.new('rails') + # desc 'Generate documentation for the Rails framework.' + Rails::API::AppTask.new('rails') + end +end - # desc "Generate Rails Guides" +namespace :doc do task :guides do rails_gem_dir = Gem::Specification.find_by_name("rails").gem_dir require File.expand_path(File.join(rails_gem_dir, "/guides/rails_guides")) diff --git a/railties/lib/rails/test_unit/testing.rake b/railties/lib/rails/test_unit/testing.rake index 877dd6d254..9263b9b81d 100644 --- a/railties/lib/rails/test_unit/testing.rake +++ b/railties/lib/rails/test_unit/testing.rake @@ -121,31 +121,17 @@ namespace :test do Rails::TestTask.new(single: "test:prepare") - Rails::TestTask.new(models: "test:prepare") do |t| - t.pattern = 'test/models/**/*_test.rb' - end - - Rails::TestTask.new(helpers: "test:prepare") do |t| - t.pattern = 'test/helpers/**/*_test.rb' + ["models", "helpers", "controllers", "mailers", "integration"].each do |name| + Rails::TestTask.new(name => "test:prepare") do |t| + t.pattern = "test/#{name}/**/*_test.rb" + end end Rails::TestTask.new(units: "test:prepare") do |t| t.pattern = 'test/{models,helpers,unit}/**/*_test.rb' end - Rails::TestTask.new(controllers: "test:prepare") do |t| - t.pattern = 'test/controllers/**/*_test.rb' - end - - Rails::TestTask.new(mailers: "test:prepare") do |t| - t.pattern = 'test/mailers/**/*_test.rb' - end - Rails::TestTask.new(functionals: "test:prepare") do |t| t.pattern = 'test/{controllers,mailers,functional}/**/*_test.rb' end - - Rails::TestTask.new(integration: "test:prepare") do |t| - t.pattern = 'test/integration/**/*_test.rb' - end end diff --git a/railties/lib/rails/version.rb b/railties/lib/rails/version.rb index dcbf57a4df..5a6d8d0983 100644 --- a/railties/lib/rails/version.rb +++ b/railties/lib/rails/version.rb @@ -1,9 +1,9 @@ module Rails module VERSION MAJOR = 4 - MINOR = 0 + MINOR = 1 TINY = 0 - PRE = "rc1" + PRE = "beta" STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index f70c90bffa..0ffb615764 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -260,6 +260,11 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_file 'test' end + def test_creation_of_app_assets_images_directory + run_generator + assert_file "app/assets/images" + end + def test_creation_of_vendor_assets_javascripts_directory run_generator assert_file "vendor/assets/javascripts" diff --git a/railties/test/generators/scaffold_generator_test.rb b/railties/test/generators/scaffold_generator_test.rb index 25f299118c..d5ad978986 100644 --- a/railties/test/generators/scaffold_generator_test.rb +++ b/railties/test/generators/scaffold_generator_test.rb @@ -239,13 +239,27 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase assert_file "config/routes.rb", /\.routes\.draw do\s*\|map\|\s*$/ end - def test_scaffold_generator_no_assets + def test_scaffold_generator_no_assets_with_switch_no_assets run_generator [ "posts", "--no-assets" ] assert_no_file "app/assets/stylesheets/scaffold.css" assert_no_file "app/assets/javascripts/posts.js" assert_no_file "app/assets/stylesheets/posts.css" end + def test_scaffold_generator_no_assets_with_switch_assets_false + run_generator [ "posts", "--assets=false" ] + assert_no_file "app/assets/stylesheets/scaffold.css" + assert_no_file "app/assets/javascripts/posts.js" + assert_no_file "app/assets/stylesheets/posts.css" + end + + def test_scaffold_generator_no_assets_with_switch_resource_route_false + run_generator [ "posts", "--resource-route=false" ] + assert_file "config/routes.rb" do |route| + assert_no_match(/resources :posts$/, route) + end + end + def test_scaffold_generator_no_stylesheets run_generator [ "posts", "--no-stylesheets" ] assert_no_file "app/assets/stylesheets/scaffold.css" diff --git a/railties/test/initializable_test.rb b/railties/test/initializable_test.rb index 16e259be5d..ed9573453b 100644 --- a/railties/test/initializable_test.rb +++ b/railties/test/initializable_test.rb @@ -20,14 +20,6 @@ module InitializableTests end end - module Word - include Rails::Initializable - - initializer :word do - $word = "bird" - end - end - class Parent include Rails::Initializable @@ -235,4 +227,4 @@ module InitializableTests assert_equal [1, 2, 3, 4], $arr end end -end
\ No newline at end of file +end diff --git a/railties/test/rails_info_test.rb b/railties/test/rails_info_test.rb index 5b9088cb64..44a5fd1904 100644 --- a/railties/test/rails_info_test.rb +++ b/railties/test/rails_info_test.rb @@ -37,6 +37,11 @@ class InfoTest < ActiveSupport::TestCase assert_property 'Goodbye', 'World' end + def test_rails_version + assert_property 'Rails version', + File.read(File.realpath('../../../RAILS_VERSION', __FILE__)).chomp + end + def test_framework_version assert_property 'Active Support version', ActiveSupport.version.to_s end diff --git a/railties/test/railties/mounted_engine_test.rb b/railties/test/railties/mounted_engine_test.rb index 80559a6e36..c94937f964 100644 --- a/railties/test/railties/mounted_engine_test.rb +++ b/railties/test/railties/mounted_engine_test.rb @@ -13,6 +13,7 @@ module ApplicationTests @simple_plugin = engine "weblog" @plugin = engine "blog" + @metrics_plugin = engine "metrics" app_file 'config/routes.rb', <<-RUBY AppTemplate::Application.routes.draw do @@ -28,6 +29,7 @@ module ApplicationTests scope "/:user", :user => "anonymous" do mount Blog::Engine => "/blog" end + mount Metrics::Engine => "/metrics" root :to => 'main#index' end RUBY @@ -54,6 +56,34 @@ module ApplicationTests end RUBY + @metrics_plugin.write "lib/metrics.rb", <<-RUBY + module Metrics + class Engine < ::Rails::Engine + isolate_namespace(Metrics) + end + end + RUBY + + @metrics_plugin.write "config/routes.rb", <<-RUBY + Metrics::Engine.routes.draw do + get '/generate_blog_route', to: 'generating#generate_blog_route' + get '/generate_blog_route_in_view', to: 'generating#generate_blog_route_in_view' + end + RUBY + + @metrics_plugin.write "app/controllers/metrics/generating_controller.rb", <<-RUBY + module Metrics + class GeneratingController < ActionController::Base + def generate_blog_route + render text: blog.post_path(1) + end + + def generate_blog_route_in_view + render inline: "<%= blog.post_path(1) -%>" + end + end + end + RUBY @plugin.write "app/models/blog/post.rb", <<-RUBY module Blog @@ -201,6 +231,21 @@ module ApplicationTests get "/somone/blog/application_route_in_view" assert_equal "/", last_response.body + # test generating engine's route from other engine + get "/metrics/generate_blog_route" + assert_equal '/anonymous/blog/posts/1', last_response.body + + get "/metrics/generate_blog_route_in_view" + assert_equal '/anonymous/blog/posts/1', last_response.body + + # test generating engine's route from other engine with default_url_options + get "/metrics/generate_blog_route", {}, 'SCRIPT_NAME' => '/foo' + assert_equal '/foo/anonymous/blog/posts/1', last_response.body + + get "/metrics/generate_blog_route_in_view", {}, 'SCRIPT_NAME' => '/foo' + assert_equal '/foo/anonymous/blog/posts/1', last_response.body + + # test generating application's route from engine with default_url_options get "/someone/blog/generate_application_route", {}, 'SCRIPT_NAME' => '/foo' assert_equal "/foo/", last_response.body |