diff options
13 files changed, 123 insertions, 26 deletions
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb index 0c5bafa666..823f5d25b6 100644 --- a/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb @@ -12,8 +12,8 @@ request_dump = clean_params.empty? ? 'None' : clean_params.inspect.gsub(',', ",\n") - def debug_hash(hash) - hash.sort_by { |k, v| k.to_s }.map { |k, v| "#{k}: #{v.inspect rescue $!.message}" }.join("\n") + def debug_hash(object) + object.to_hash.sort_by { |k, v| k.to_s }.map { |k, v| "#{k}: #{v.inspect rescue $!.message}" }.join("\n") end unless self.class.method_defined?(:debug_hash) %> diff --git a/actionpack/lib/action_view/helpers/tags/collection_helpers.rb b/actionpack/lib/action_view/helpers/tags/collection_helpers.rb index 6a1479069f..4e33e79a36 100644 --- a/actionpack/lib/action_view/helpers/tags/collection_helpers.rb +++ b/actionpack/lib/action_view/helpers/tags/collection_helpers.rb @@ -49,7 +49,7 @@ module ActionView accept = if current_value.respond_to?(:call) current_value.call(item) else - Array(current_value).include?(value) + Array(current_value).map(&:to_s).include?(value.to_s) end if accept diff --git a/actionpack/test/template/form_collections_helper_test.rb b/actionpack/test/template/form_collections_helper_test.rb index 4d878635ef..c73e80ed88 100644 --- a/actionpack/test/template/form_collections_helper_test.rb +++ b/actionpack/test/template/form_collections_helper_test.rb @@ -195,6 +195,15 @@ class FormCollectionsHelperTest < ActionView::TestCase assert_no_select 'input[type=checkbox][value=2][checked=checked]' end + test 'collection check boxes accepts selected string values as :checked option' do + collection = (1..3).map{|i| [i, "Category #{i}"] } + with_collection_check_boxes :user, :category_ids, collection, :first, :last, :checked => ['1', '3'] + + assert_select 'input[type=checkbox][value=1][checked=checked]' + assert_select 'input[type=checkbox][value=3][checked=checked]' + assert_no_select 'input[type=checkbox][value=2][checked=checked]' + end + test 'collection check boxes accepts a single checked value' do collection = (1..3).map{|i| [i, "Category #{i}"] } with_collection_check_boxes :user, :category_ids, collection, :first, :last, :checked => 3 diff --git a/activerecord/lib/active_record/connection_adapters/column.rb b/activerecord/lib/active_record/connection_adapters/column.rb index 9af8e46120..1933ce2b46 100644 --- a/activerecord/lib/active_record/connection_adapters/column.rb +++ b/activerecord/lib/active_record/connection_adapters/column.rb @@ -158,7 +158,7 @@ module ActiveRecord def value_to_date(value) if value.is_a?(String) - return nil if value.empty? + return nil if value.blank? fast_string_to_date(value) || fallback_string_to_date(value) elsif value.respond_to?(:to_date) value.to_date @@ -169,14 +169,14 @@ module ActiveRecord def string_to_time(string) return string unless string.is_a?(String) - return nil if string.empty? + return nil if string.blank? fast_string_to_time(string) || fallback_string_to_time(string) end def string_to_dummy_time(string) return string unless string.is_a?(String) - return nil if string.empty? + return nil if string.blank? string_to_time "2000-01-01 #{string}" end diff --git a/activerecord/test/cases/column_test.rb b/activerecord/test/cases/column_test.rb index 4fcf8a33a4..4111a5f808 100644 --- a/activerecord/test/cases/column_test.rb +++ b/activerecord/test/cases/column_test.rb @@ -48,6 +48,34 @@ module ActiveRecord column.type_cast(false) end end + + def test_type_cast_time + column = Column.new("field", nil, "time") + assert_equal nil, column.type_cast('') + assert_equal nil, column.type_cast(' ') + + time_string = Time.now.utc.strftime("%T") + assert_equal time_string, column.type_cast(time_string).strftime("%T") + end + + def test_type_cast_datetime_and_timestamp + [Column.new("field", nil, "datetime"), Column.new("field", nil, "timestamp")].each do |column| + assert_equal nil, column.type_cast('') + assert_equal nil, column.type_cast(' ') + + datetime_string = Time.now.utc.strftime("%FT%T") + assert_equal datetime_string, column.type_cast(datetime_string).strftime("%FT%T") + end + end + + def test_type_cast_date + column = Column.new("field", nil, "date") + assert_equal nil, column.type_cast('') + assert_equal nil, column.type_cast(' ') + + date_string = Time.now.utc.strftime("%F") + assert_equal date_string, column.type_cast(date_string).strftime("%F") + end end end end diff --git a/activesupport/lib/active_support/multibyte/chars.rb b/activesupport/lib/active_support/multibyte/chars.rb index 9a748dfa60..b20c980f36 100644 --- a/activesupport/lib/active_support/multibyte/chars.rb +++ b/activesupport/lib/active_support/multibyte/chars.rb @@ -62,8 +62,8 @@ module ActiveSupport #:nodoc: # Returns +true+ if _obj_ responds to the given method. Private methods are included in the search # only if the optional second parameter evaluates to +true+. - def respond_to?(method, include_private=false) - super || @wrapped_string.respond_to?(method, include_private) + def respond_to_missing?(method, include_private) + @wrapped_string.respond_to?(method, include_private) end # Returns +true+ when the proxy class can handle the string. Returns +false+ otherwise. diff --git a/activesupport/lib/active_support/ordered_options.rb b/activesupport/lib/active_support/ordered_options.rb index 538e41e0eb..60e6cd55ad 100644 --- a/activesupport/lib/active_support/ordered_options.rb +++ b/activesupport/lib/active_support/ordered_options.rb @@ -36,7 +36,7 @@ module ActiveSupport #:nodoc: end end - def respond_to?(name) + def respond_to_missing?(name, include_private) true end end diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb index 1cb71012ef..120b2a4c28 100644 --- a/activesupport/lib/active_support/time_with_zone.rb +++ b/activesupport/lib/active_support/time_with_zone.rb @@ -311,10 +311,10 @@ module ActiveSupport end # Ensure proxy class responds to all methods that underlying time instance responds to. - def respond_to?(sym, include_priv = false) + def respond_to_missing?(sym, include_priv) # consistently respond false to acts_like?(:date), regardless of whether #time is a Time or DateTime - return false if sym.to_s == 'acts_like_date?' - super || time.respond_to?(sym, include_priv) + return false if sym.to_sym == :acts_like_date? + time.respond_to?(sym, include_priv) end # Send the missing method to +time+ instance, and wrap result in a new TimeWithZone with the existing +time_zone+. diff --git a/activesupport/test/core_ext/time_with_zone_test.rb b/activesupport/test/core_ext/time_with_zone_test.rb index bc6ebbb765..b62337e31b 100644 --- a/activesupport/test/core_ext/time_with_zone_test.rb +++ b/activesupport/test/core_ext/time_with_zone_test.rb @@ -450,6 +450,7 @@ class TimeWithZoneTest < ActiveSupport::TestCase def test_ruby_19_weekday_name_query_methods %w(sunday? monday? tuesday? wednesday? thursday? friday? saturday?).each do |name| assert_respond_to @twz, name + assert_equal @twz.send(name), @twz.method(name).call end end diff --git a/activesupport/test/multibyte_chars_test.rb b/activesupport/test/multibyte_chars_test.rb index 90aa13b3e6..a8d69d0ec3 100644 --- a/activesupport/test/multibyte_chars_test.rb +++ b/activesupport/test/multibyte_chars_test.rb @@ -458,6 +458,15 @@ class MultibyteCharsUTF8BehaviourTest < ActiveSupport::TestCase assert !''.mb_chars.respond_to?(:undefined_method) # Not defined end + def test_method_works_for_proxyed_methods + assert_equal 'll', 'hello'.mb_chars.method(:slice).call(2..3) # Defined on Chars + chars = 'hello'.mb_chars + assert_equal 'Hello', chars.method(:capitalize!).call # Defined on Chars + assert_equal 'Hello', chars + assert_equal 'jello', 'hello'.mb_chars.method(:gsub).call(/h/, 'j') # Defined on String + assert_raise(NameError){ ''.mb_chars.method(:undefined_method) } # Not defined + end + def test_acts_like_string assert 'Bambi'.mb_chars.acts_like_string? end diff --git a/activesupport/test/ordered_options_test.rb b/activesupport/test/ordered_options_test.rb index 3526c7a366..f60f9a58e3 100644 --- a/activesupport/test/ordered_options_test.rb +++ b/activesupport/test/ordered_options_test.rb @@ -77,4 +77,12 @@ class OrderedOptionsTest < ActiveSupport::TestCase assert copy.kind_of?(original.class) assert_not_equal copy.object_id, original.object_id end + + def test_introspection + a = ActiveSupport::OrderedOptions.new + assert a.respond_to?(:blah) + assert a.respond_to?(:blah=) + assert_equal 42, a.method(:blah=).call(42) + assert_equal 42, a.method(:blah).call + end end diff --git a/guides/rails_guides/textile_extensions.rb b/guides/rails_guides/textile_extensions.rb index 4677fae504..0a002a785f 100644 --- a/guides/rails_guides/textile_extensions.rb +++ b/guides/rails_guides/textile_extensions.rb @@ -1,5 +1,11 @@ require 'active_support/core_ext/object/inclusion' +module RedCloth::Formatters::HTML + def emdash(opts) + "--" + end +end + module RailsGuides module TextileExtensions def notestuff(body) diff --git a/guides/source/active_record_querying.textile b/guides/source/active_record_querying.textile index f9dbaa1125..a9cb424eaa 100644 --- a/guides/source/active_record_querying.textile +++ b/guides/source/active_record_querying.textile @@ -99,9 +99,28 @@ SELECT * FROM clients WHERE (clients.id = 10) LIMIT 1 <tt>Model.find(primary_key)</tt> will raise an +ActiveRecord::RecordNotFound+ exception if no matching record is found. +h5. +take+ + +<tt>Model.take</tt> retrieves a record without any implicit ordering. For example: + +<ruby> +client = Client.take +# => #<Client id: 1, first_name: "Lifo"> +</ruby> + +The SQL equivalent of the above is: + +<sql> +SELECT * FROM clients LIMIT 1 +</sql> + +<tt>Model.take</tt> returns +nil+ if no record is found and no exception will be raised. + +TIP: The retrieved record may vary depending on the database engine. + h5. +first+ -<tt>Model.first</tt> finds the first record matched by the supplied options, if any. For example: +<tt>Model.first</tt> finds the first record ordered by the primary key. For example: <ruby> client = Client.first @@ -111,14 +130,14 @@ client = Client.first The SQL equivalent of the above is: <sql> -SELECT * FROM clients LIMIT 1 +SELECT * FROM clients ORDER BY clients.id ASC LIMIT 1 </sql> -<tt>Model.first</tt> returns +nil+ if no matching record is found. No exception will be raised. +<tt>Model.first</tt> returns +nil+ if no matching record is found and no exception will be raised. h5. +last+ -<tt>Model.last</tt> finds the last record matched by the supplied options. For example: +<tt>Model.last</tt> finds the last record ordered by the primary key. For example: <ruby> client = Client.last @@ -131,7 +150,7 @@ The SQL equivalent of the above is: SELECT * FROM clients ORDER BY clients.id DESC LIMIT 1 </sql> -<tt>Model.last</tt> returns +nil+ if no matching record is found. No exception will be raised. +<tt>Model.last</tt> returns +nil+ if no matching record is found and no exception will be raised. h5. +find_by+ @@ -148,12 +167,29 @@ Client.find_by first_name: 'Jon' It is equivalent to writing: <ruby> -Client.where(first_name: 'Lifo').first +Client.where(first_name: 'Lifo').take </ruby> +h5(#take_1). +take!+ + +<tt>Model.take!</tt> retrieves a record without any implicit ordering. For example: + +<ruby> +client = Client.take! +# => #<Client id: 1, first_name: "Lifo"> +</ruby> + +The SQL equivalent of the above is: + +<sql> +SELECT * FROM clients LIMIT 1 +</sql> + +<tt>Model.take!</tt> raises +ActiveRecord::RecordNotFound+ if no matching record is found. + h5(#first_1). +first!+ -<tt>Model.first!</tt> finds the first record. For example: +<tt>Model.first!</tt> finds the first record ordered by the primary key. For example: <ruby> client = Client.first! @@ -163,14 +199,14 @@ client = Client.first! The SQL equivalent of the above is: <sql> -SELECT * FROM clients LIMIT 1 +SELECT * FROM clients ORDER BY clients.id ASC LIMIT 1 </sql> -<tt>Model.first!</tt> raises +RecordNotFound+ if no matching record is found. +<tt>Model.first!</tt> raises +ActiveRecord::RecordNotFound+ if no matching record is found. h5(#last_1). +last!+ -<tt>Model.last!</tt> finds the last record. For example: +<tt>Model.last!</tt> finds the last record ordered by the primary key. For example: <ruby> client = Client.last! @@ -183,24 +219,24 @@ The SQL equivalent of the above is: SELECT * FROM clients ORDER BY clients.id DESC LIMIT 1 </sql> -<tt>Model.last!</tt> raises +RecordNotFound+ if no matching record is found. +<tt>Model.last!</tt> raises +ActiveRecord::RecordNotFound+ if no matching record is found. h5(#find_by_1). +find_by!+ -<tt>Model.find_by!</tt> finds the first record matching some conditions. It raises +RecordNotFound+ if no matching record is found. For example: +<tt>Model.find_by!</tt> finds the first record matching some conditions. It raises +ActiveRecord::RecordNotFound+ if no matching record is found. For example: <ruby> Client.find_by! first_name: 'Lifo' # => #<Client id: 1, first_name: "Lifo"> Client.find_by! first_name: 'Jon' -# => RecordNotFound +# => ActiveRecord::RecordNotFound </ruby> It is equivalent to writing: <ruby> -Client.where(first_name: 'Lifo').first! +Client.where(first_name: 'Lifo').take! </ruby> h4. Retrieving Multiple Objects |