diff options
25 files changed, 83 insertions, 46 deletions
diff --git a/RELEASING_RAILS.rdoc b/RELEASING_RAILS.rdoc index f8c40f0b02..c80a5816a7 100644 --- a/RELEASING_RAILS.rdoc +++ b/RELEASING_RAILS.rdoc @@ -28,7 +28,7 @@ Do not release with Red AWDwR tests. === Are the supported plugins working? If not, make it work. Some Rails plugins are important and need to be supported until Rails 5. -As these plugins are outside the Rails repository it is easy to break then without knowing +As these plugins are outside the Rails repository it is easy to break them without knowing after some refactoring or bug fix, so it is important to check if the following plugins are working with the versions that will be released: @@ -54,7 +54,7 @@ addressed, and that can impact your release date. Ruby implementors have high stakes in making sure Rails works. Be kind and give them a heads up that Rails will be released soonish. -This only needs done for major and minor releases, bugfix releases aren't a +This only need to be done for major and minor releases, bugfix releases aren't a big enough deal, and are supposed to be backwards compatible. Send an email just giving a heads up about the upcoming release to these diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb index 097019144c..30eae41f60 100644 --- a/actionpack/lib/action_controller/test_case.rb +++ b/actionpack/lib/action_controller/test_case.rb @@ -679,10 +679,6 @@ module ActionController klass.new end - def document_root_element - html_document - end - included do include ActionController::TemplateAssertions include ActionDispatch::Assertions @@ -692,6 +688,10 @@ module ActionController private + def document_root_element + html_document.root + end + def check_required_ivars # Sanity check for required instance variables so we can give an # understandable error message. diff --git a/actionpack/lib/action_dispatch/testing/assertions.rb b/actionpack/lib/action_dispatch/testing/assertions.rb index 41d00b5e2b..f325c35b57 100644 --- a/actionpack/lib/action_dispatch/testing/assertions.rb +++ b/actionpack/lib/action_dispatch/testing/assertions.rb @@ -15,7 +15,7 @@ module ActionDispatch @html_document ||= if @response.content_type =~ /xml$/ Nokogiri::XML::Document.parse(@response.body) else - Nokogiri::HTML::DocumentFragment.parse(@response.body) + Nokogiri::HTML::Document.parse(@response.body) end end end diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb index 731305227d..a9a1576fed 100644 --- a/actionpack/lib/action_dispatch/testing/integration.rb +++ b/actionpack/lib/action_dispatch/testing/integration.rb @@ -505,7 +505,7 @@ module ActionDispatch end def document_root_element - html_document + html_document.root end end end diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb index 27b30536b0..d6219b7626 100644 --- a/actionpack/test/controller/integration_test.rb +++ b/actionpack/test/controller/integration_test.rb @@ -292,7 +292,7 @@ class IntegrationProcessTest < ActionDispatch::IntegrationTest assert_equal({}, cookies.to_hash) assert_equal "OK", body assert_equal "OK", response.body - assert_kind_of Nokogiri::HTML::DocumentFragment, html_document + assert_kind_of Nokogiri::HTML::Document, html_document assert_equal 1, request_count end end @@ -308,7 +308,7 @@ class IntegrationProcessTest < ActionDispatch::IntegrationTest assert_equal({}, cookies.to_hash) assert_equal "Created", body assert_equal "Created", response.body - assert_kind_of Nokogiri::HTML::DocumentFragment, html_document + assert_kind_of Nokogiri::HTML::Document, html_document assert_equal 1, request_count end end @@ -368,7 +368,7 @@ class IntegrationProcessTest < ActionDispatch::IntegrationTest assert_response :redirect assert_response :found assert_equal "<html><body>You are being <a href=\"http://www.example.com/get\">redirected</a>.</body></html>", response.body - assert_kind_of Nokogiri::HTML::DocumentFragment, html_document + assert_kind_of Nokogiri::HTML::Document, html_document assert_equal 1, request_count follow_redirect! diff --git a/actionpack/test/controller/test_case_test.rb b/actionpack/test/controller/test_case_test.rb index 957c0a5288..475af90032 100644 --- a/actionpack/test/controller/test_case_test.rb +++ b/actionpack/test/controller/test_case_test.rb @@ -132,6 +132,14 @@ XML render :nothing => true end + def test_without_body + render html: '<div class="foo"></div>'.html_safe + end + + def test_with_body + render html: '<body class="foo"></body>'.html_safe + end + private def generate_url(opts) @@ -179,6 +187,19 @@ XML end end + def test_assert_select_without_body + get :test_without_body + + assert_select 'body', 0 + assert_select 'div.foo' + end + + def test_assert_select_with_body + get :test_with_body + + assert_select 'body.foo' + end + def test_url_options_reset @controller = DefaultUrlOptionsCachingController.new get :test_url_options_reset diff --git a/actionview/lib/action_view/helpers/date_helper.rb b/actionview/lib/action_view/helpers/date_helper.rb index 01a9747035..bd7b36c352 100644 --- a/actionview/lib/action_view/helpers/date_helper.rb +++ b/actionview/lib/action_view/helpers/date_helper.rb @@ -177,7 +177,7 @@ module ActionView # and +:name+ (string). A format string would be something like "%{name} (%<number>02d)" for example. # See <tt>Kernel.sprintf</tt> for documentation on format sequences. # * <tt>:date_separator</tt> - Specifies a string to separate the date fields. Default is "" (i.e. nothing). - # * <tt>:start_year</tt> - Set the start year for the year select. Default is <tt>Date.today.year - 5</tt>if + # * <tt>:start_year</tt> - Set the start year for the year select. Default is <tt>Date.today.year - 5</tt> if # you are creating new record. While editing existing record, <tt>:start_year</tt> defaults to # the current selected year minus 5. # * <tt>:end_year</tt> - Set the end year for the year select. Default is <tt>Date.today.year + 5</tt> if diff --git a/actionview/lib/action_view/test_case.rb b/actionview/lib/action_view/test_case.rb index 5cffddcd4f..812b011bd7 100644 --- a/actionview/lib/action_view/test_case.rb +++ b/actionview/lib/action_view/test_case.rb @@ -126,10 +126,6 @@ module ActionView end # Need to experiment if this priority is the best one: rendered => output_buffer - def document_root_element - Nokogiri::HTML::DocumentFragment.parse(@rendered.blank? ? @output_buffer : @rendered) - end - class RenderedViewsCollection def initialize @rendered_views ||= Hash.new { |hash, key| hash[key] = [] } @@ -161,6 +157,11 @@ module ActionView private + # Need to experiment if this priority is the best one: rendered => output_buffer + def document_root_element + Nokogiri::HTML::Document.parse(@rendered.blank? ? @output_buffer : @rendered).root + end + def say_no_to_protect_against_forgery! _helpers.module_eval do remove_possible_method :protect_against_forgery? diff --git a/actionview/test/template/date_helper_test.rb b/actionview/test/template/date_helper_test.rb index 0cdb130710..a6962b5200 100644 --- a/actionview/test/template/date_helper_test.rb +++ b/actionview/test/template/date_helper_test.rb @@ -1504,7 +1504,7 @@ class DateHelperTest < ActionView::TestCase expected << %(<option value="">Choose seconds</option>\n<option value="00">00</option>\n<option value="01">01</option>\n<option value="02">02</option>\n<option value="03">03</option>\n<option value="04">04</option>\n<option value="05">05</option>\n<option value="06">06</option>\n<option value="07">07</option>\n<option value="08">08</option>\n<option value="09">09</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18" selected="selected">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n<option value="32">32</option>\n<option value="33">33</option>\n<option value="34">34</option>\n<option value="35">35</option>\n<option value="36">36</option>\n<option value="37">37</option>\n<option value="38">38</option>\n<option value="39">39</option>\n<option value="40">40</option>\n<option value="41">41</option>\n<option value="42">42</option>\n<option value="43">43</option>\n<option value="44">44</option>\n<option value="45">45</option>\n<option value="46">46</option>\n<option value="47">47</option>\n<option value="48">48</option>\n<option value="49">49</option>\n<option value="50">50</option>\n<option value="51">51</option>\n<option value="52">52</option>\n<option value="53">53</option>\n<option value="54">54</option>\n<option value="55">55</option>\n<option value="56">56</option>\n<option value="57">57</option>\n<option value="58">58</option>\n<option value="59">59</option>\n) expected << "</select>\n" - assert_dom_equal expected, select_time(Time.mktime(2003, 8, 16, 8, 4, 18), :prompt => true, :include_seconds => true, + assert_dom_equal expected, select_time(Time.mktime(2003, 8, 16, 8, 4, 18), :include_seconds => true, :prompt => {:hour => 'Choose hour', :minute => 'Choose minute', :second => 'Choose seconds'}) end diff --git a/activerecord/lib/active_record/aggregations.rb b/activerecord/lib/active_record/aggregations.rb index e576ec4d40..1040e6e3bb 100644 --- a/activerecord/lib/active_record/aggregations.rb +++ b/activerecord/lib/active_record/aggregations.rb @@ -230,8 +230,8 @@ module ActiveRecord private def reader_method(name, class_name, mapping, allow_nil, constructor) define_method(name) do - if @aggregation_cache[name].nil? && (!allow_nil || mapping.any? {|key, _| !read_attribute(key).nil? }) - attrs = mapping.collect {|key, _| read_attribute(key)} + if @aggregation_cache[name].nil? && (!allow_nil || mapping.any? {|key, _| !_read_attribute(key).nil? }) + attrs = mapping.collect {|key, _| _read_attribute(key)} object = constructor.respond_to?(:call) ? constructor.call(*attrs) : class_name.constantize.send(constructor, *attrs) diff --git a/activerecord/lib/active_record/associations/has_many_association.rb b/activerecord/lib/active_record/associations/has_many_association.rb index 1413efaf7f..93084e0dcf 100644 --- a/activerecord/lib/active_record/associations/has_many_association.rb +++ b/activerecord/lib/active_record/associations/has_many_association.rb @@ -66,7 +66,7 @@ module ActiveRecord # the loaded flag is set to true as well. def count_records count = if has_cached_counter? - owner.read_attribute cached_counter_attribute_name + owner._read_attribute cached_counter_attribute_name else scope.count end diff --git a/activerecord/lib/active_record/associations/has_many_through_association.rb b/activerecord/lib/active_record/associations/has_many_through_association.rb index bde23fc116..6329fdfe95 100644 --- a/activerecord/lib/active_record/associations/has_many_through_association.rb +++ b/activerecord/lib/active_record/associations/has_many_through_association.rb @@ -20,7 +20,7 @@ module ActiveRecord # SELECT query will be generated by using #length instead. def size if has_cached_counter? - owner.read_attribute cached_counter_attribute_name(reflection) + owner._read_attribute cached_counter_attribute_name(reflection) elsif loaded? target.size else diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb index 34ec397aee..d766996d37 100644 --- a/activerecord/lib/active_record/attribute_methods.rb +++ b/activerecord/lib/active_record/attribute_methods.rb @@ -332,7 +332,7 @@ module ActiveRecord # task.attribute_present?(:title) # => true # task.attribute_present?(:is_done) # => true def attribute_present?(attribute) - value = read_attribute(attribute) + value = _read_attribute(attribute) !value.nil? && !(value.respond_to?(:empty?) && value.empty?) end @@ -433,7 +433,7 @@ module ActiveRecord end def typecasted_attribute_value(name) - read_attribute(name) + _read_attribute(name) end end end diff --git a/activerecord/lib/active_record/attribute_methods/dirty.rb b/activerecord/lib/active_record/attribute_methods/dirty.rb index 2f02738f6d..9ba46ec4c7 100644 --- a/activerecord/lib/active_record/attribute_methods/dirty.rb +++ b/activerecord/lib/active_record/attribute_methods/dirty.rb @@ -110,7 +110,7 @@ module ActiveRecord if attribute_changed?(attr) changed_attributes[attr] else - clone_attribute_value(:read_attribute, attr) + clone_attribute_value(:_read_attribute, attr) end end diff --git a/activerecord/lib/active_record/attribute_methods/primary_key.rb b/activerecord/lib/active_record/attribute_methods/primary_key.rb index 104d84a1f8..c28374e4ab 100644 --- a/activerecord/lib/active_record/attribute_methods/primary_key.rb +++ b/activerecord/lib/active_record/attribute_methods/primary_key.rb @@ -17,7 +17,7 @@ module ActiveRecord def id if pk = self.class.primary_key sync_with_transaction_state - read_attribute(pk) + _read_attribute(pk) end end diff --git a/activerecord/lib/active_record/attribute_methods/read.rb b/activerecord/lib/active_record/attribute_methods/read.rb index bf2a084a00..20f0936e52 100644 --- a/activerecord/lib/active_record/attribute_methods/read.rb +++ b/activerecord/lib/active_record/attribute_methods/read.rb @@ -27,7 +27,7 @@ module ActiveRecord <<-EOMETHOD def #{method_name} name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{const_name} - read_attribute(name) { |n| missing_attribute(n, caller) } + _read_attribute(name) { |n| missing_attribute(n, caller) } end EOMETHOD end @@ -64,7 +64,7 @@ module ActiveRecord generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1 def #{temp_method} name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name} - read_attribute(name) { |n| missing_attribute(n, caller) } + _read_attribute(name) { |n| missing_attribute(n, caller) } end STR @@ -76,19 +76,27 @@ module ActiveRecord end end + ID = 'id'.freeze + # Returns the value of the attribute identified by <tt>attr_name</tt> after # it has been typecast (for example, "2004-12-12" in a date column is cast # to a date object, like Date.new(2004, 12, 12)). def read_attribute(attr_name, &block) name = attr_name.to_s - name = self.class.primary_key if name == 'id' - @attributes.fetch_value(name, &block) + name = self.class.primary_key if name == ID + _read_attribute(name, &block) + end + + # This method exists to avoid the expensive primary_key check internally, without + # breaking compatibility with the read_attribute API + def _read_attribute(attr_name) # :nodoc: + @attributes.fetch_value(attr_name.to_s) { |n| yield n if block_given? } end private def attribute(attribute_name) - read_attribute(attribute_name) + _read_attribute(attribute_name) end end end diff --git a/activerecord/lib/active_record/attribute_set.rb b/activerecord/lib/active_record/attribute_set.rb index 21c58cbf1d..6b1d7ea79e 100644 --- a/activerecord/lib/active_record/attribute_set.rb +++ b/activerecord/lib/active_record/attribute_set.rb @@ -27,8 +27,8 @@ module ActiveRecord attributes.initialized_keys end - def fetch_value(name, &block) - self[name].value(&block) + def fetch_value(name) + self[name].value { |n| yield n if block_given? } end def write_from_database(name, value) diff --git a/activerecord/lib/active_record/attribute_set/builder.rb b/activerecord/lib/active_record/attribute_set/builder.rb index 60154a0647..05138ae36d 100644 --- a/activerecord/lib/active_record/attribute_set/builder.rb +++ b/activerecord/lib/active_record/attribute_set/builder.rb @@ -19,7 +19,7 @@ module ActiveRecord end end - class LazyAttributeHash + class LazyAttributeHash # :nodoc: delegate :select, :transform_values, to: :materialize def initialize(types, values, additional_types) @@ -35,11 +35,7 @@ module ActiveRecord end def [](key) - if delegate_hash.key?(key) - delegate_hash[key] - else - assign_default_value(key) - end + delegate_hash[key] || assign_default_value(key) end def []=(key, value) @@ -66,9 +62,11 @@ module ActiveRecord def assign_default_value(name) type = additional_types.fetch(name, types[name]) + value_present = true + value = values.fetch(name) { value_present = false } - if values.key?(name) - delegate_hash[name] = Attribute.from_database(name, values[name], type) + if value_present + delegate_hash[name] = Attribute.from_database(name, value, type) elsif types.key?(name) delegate_hash[name] = Attribute.uninitialized(name, type) end diff --git a/activerecord/lib/active_record/enum.rb b/activerecord/lib/active_record/enum.rb index 5958373e88..f053372cfb 100644 --- a/activerecord/lib/active_record/enum.rb +++ b/activerecord/lib/active_record/enum.rb @@ -142,7 +142,7 @@ module ActiveRecord private def save_changed_attribute(attr_name, old) if (mapping = self.class.defined_enums[attr_name.to_s]) - value = read_attribute(attr_name) + value = _read_attribute(attr_name) if attribute_changed?(attr_name) if mapping[old] == value clear_attribute_changes([attr_name]) diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index 4b58f2deb7..f4a351b092 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -287,7 +287,7 @@ module ActiveRecord def association_scope_cache(conn, owner) key = conn.prepared_statements if polymorphic? - key = [key, owner.read_attribute(@foreign_type)] + key = [key, owner._read_attribute(@foreign_type)] end @association_scope_cache[key] ||= @scope_lock.synchronize { @association_scope_cache[key] ||= yield diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index 8575e5a7be..460daf99bc 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -639,7 +639,7 @@ module ActiveRecord preload = preload_values preload += includes_values unless eager_loading? - preloader = ActiveRecord::Associations::Preloader.new + preloader = build_preloader preload.each do |associations| preloader.preload @records, associations end @@ -650,6 +650,10 @@ module ActiveRecord @records end + def build_preloader + ActiveRecord::Associations::Preloader.new + end + def references_eager_loaded_tables? joined_tables = arel.join_sources.map do |join| if join.is_a?(Arel::Nodes::StringJoin) diff --git a/activerecord/lib/active_record/type/integer.rb b/activerecord/lib/active_record/type/integer.rb index d69e5b3f28..36bbd9cd5e 100644 --- a/activerecord/lib/active_record/type/integer.rb +++ b/activerecord/lib/active_record/type/integer.rb @@ -14,6 +14,11 @@ module ActiveRecord alias type_cast_for_database type_cast + def type_cast_from_database(value) + return if value.nil? + value.to_i + end + protected attr_reader :range diff --git a/activerecord/lib/active_record/validations/uniqueness.rb b/activerecord/lib/active_record/validations/uniqueness.rb index 2dba4c7b94..3e8afe37a8 100644 --- a/activerecord/lib/active_record/validations/uniqueness.rb +++ b/activerecord/lib/active_record/validations/uniqueness.rb @@ -79,7 +79,7 @@ module ActiveRecord scope_value = record.send(reflection.foreign_key) scope_item = reflection.foreign_key else - scope_value = record.read_attribute(scope_item) + scope_value = record._read_attribute(scope_item) end relation = relation.and(table[scope_item].eq(scope_value)) end diff --git a/activerecord/test/cases/inheritance_test.rb b/activerecord/test/cases/inheritance_test.rb index 792950d24d..0338669016 100644 --- a/activerecord/test/cases/inheritance_test.rb +++ b/activerecord/test/cases/inheritance_test.rb @@ -22,7 +22,7 @@ class InheritanceTest < ActiveRecord::TestCase company = Company.first company = company.dup company.extend(Module.new { - def read_attribute(name) + def _read_attribute(name) return ' ' if name == 'type' super end diff --git a/guides/source/3_0_release_notes.md b/guides/source/3_0_release_notes.md index 46be2613ab..2630207c0f 100644 --- a/guides/source/3_0_release_notes.md +++ b/guides/source/3_0_release_notes.md @@ -298,7 +298,7 @@ Deprecations More Information: * [The Rails 3 Router: Rack it Up](http://yehudakatz.com/2009/12/26/the-rails-3-router-rack-it-up/) -* [Revamped Routes in Rails 3](http://rizwanreza.com/2009/12/20/revamped-routes-in-rails-3) +* [Revamped Routes in Rails 3](https://medium.com/fusion-of-thoughts/revamped-routes-in-rails-3-b6d00654e5b0) * [Generic Actions in Rails 3](http://yehudakatz.com/2009/12/20/generic-actions-in-rails-3/) |