diff options
117 files changed, 861 insertions, 541 deletions
@@ -31,6 +31,11 @@ platforms :mri_18 do gem 'ruby-prof' end +platforms :mri_19 do + # TODO: Remove the conditional when ruby-debug19 supports Ruby >= 1.9.3 + gem "ruby-debug19" if RUBY_VERSION < "1.9.3" +end + platforms :ruby do gem 'json' gem 'yajl-ruby' diff --git a/actionmailer/CHANGELOG b/actionmailer/CHANGELOG index 9c073dce1f..167c1da9c5 100644 --- a/actionmailer/CHANGELOG +++ b/actionmailer/CHANGELOG @@ -2,6 +2,10 @@ * No changes +*Rails 3.0.2 (unreleased)* + +* No changes + *Rails 3.0.1 (October 15, 2010)* * No Changes, just a version bump. diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 2d133ca0b2..db02beee35 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -23,6 +23,10 @@ * Add Rack::Cache to the default stack. Create a Rails store that delegates to the Rails cache, so by default, whatever caching layer you are using will be used for HTTP caching. Note that Rack::Cache will be used if you use #expires_in, #fresh_when or #stale with :public => true. Otherwise, the caching rules will apply to the browser only. [Yehuda Katz, Carl Lerche] +*Rails 3.0.2 (unreleased)* + +* The helper number_to_currency accepts a new :negative_format option to be able to configure how to render negative amounts. [Don Wilson] + *Rails 3.0.1 (October 15, 2010)* * No Changes, just a version bump. diff --git a/actionpack/lib/abstract_controller/callbacks.rb b/actionpack/lib/abstract_controller/callbacks.rb index 7b0d80614d..f169ab7c3a 100644 --- a/actionpack/lib/abstract_controller/callbacks.rb +++ b/actionpack/lib/abstract_controller/callbacks.rb @@ -81,27 +81,29 @@ module AbstractController class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 # Append a before, after or around filter. See _insert_callbacks # for details on the allowed parameters. - def #{filter}_filter(*names, &blk) # def before_filter(*names, &blk) - _insert_callbacks(names, blk) do |name, options| # _insert_callbacks(names, blk) do |name, options} - set_callback(:process_action, :#{filter}, name, options) # set_callback(:process_action, :before_filter, name, options) - end # end - end # end + def #{filter}_filter(*names, &blk) + _insert_callbacks(names, blk) do |name, options| + options[:if] = (Array.wrap(options[:if]) << "!halted") if #{filter == :after} + set_callback(:process_action, :#{filter}, name, options) + end + end # Prepend a before, after or around filter. See _insert_callbacks # for details on the allowed parameters. - def prepend_#{filter}_filter(*names, &blk) # def prepend_before_filter(*names, &blk) - _insert_callbacks(names, blk) do |name, options| # _insert_callbacks(names, blk) do |name, options| - set_callback(:process_action, :#{filter}, name, options.merge(:prepend => true)) # set_callback(:process_action, :before, name, options.merge(:prepend => true)) - end # end - end # end + def prepend_#{filter}_filter(*names, &blk) + _insert_callbacks(names, blk) do |name, options| + options[:if] = (Array.wrap(options[:if]) << "!halted") if #{filter == :after} + set_callback(:process_action, :#{filter}, name, options.merge(:prepend => true)) + end + end # Skip a before, after or around filter. See _insert_callbacks # for details on the allowed parameters. - def skip_#{filter}_filter(*names, &blk) # def skip_before_filter(*names, &blk) - _insert_callbacks(names, blk) do |name, options| # _insert_callbacks(names, blk) do |name, options| - skip_callback(:process_action, :#{filter}, name, options) # skip_callback(:process_action, :before, name, options) - end # end - end # end + def skip_#{filter}_filter(*names, &blk) + _insert_callbacks(names, blk) do |name, options| + skip_callback(:process_action, :#{filter}, name, options) + end + end # *_filter is the same as append_*_filter alias_method :append_#{filter}_filter, :#{filter}_filter diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb index c6d4c6d936..f7dd0dcb69 100644 --- a/actionpack/lib/action_controller/metal/mime_responds.rb +++ b/actionpack/lib/action_controller/metal/mime_responds.rb @@ -227,7 +227,7 @@ module ActionController #:nodoc: "controller responds to in the class level" if self.class.mimes_for_respond_to.empty? if response = retrieve_response_from_mimes(&block) - options = resources.extract_options! + options = resources.size == 1 ? {} : resources.extract_options! options.merge!(:default_response => response) (options.delete(:responder) || self.class.responder).call(self, resources, options) end diff --git a/actionpack/lib/action_controller/metal/testing.rb b/actionpack/lib/action_controller/metal/testing.rb index 4b8c452d50..f4efeb33ba 100644 --- a/actionpack/lib/action_controller/metal/testing.rb +++ b/actionpack/lib/action_controller/metal/testing.rb @@ -14,18 +14,9 @@ module ActionController cookies.write(@_response) end @_response.prepare! - set_test_assigns ret end - def set_test_assigns - @assigns = {} - (instance_variable_names - self.class.protected_instance_variables).each do |var| - name, value = var[1..-1], instance_variable_get(var) - @assigns[name] = value - end - end - # TODO : Rewrite tests using controller.headers= to use Rack env def headers=(new_headers) @_response ||= ActionDispatch::Response.new diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb index 0c26071379..2b2f647d32 100644 --- a/actionpack/lib/action_controller/test_case.rb +++ b/actionpack/lib/action_controller/test_case.rb @@ -411,8 +411,9 @@ module ActionController @controller.request = @request @controller.params.merge!(parameters) build_request_uri(action, parameters) - Base.class_eval { include Testing } + @controller.class.class_eval { include Testing } @controller.process_with_new_base_test(@request, @response) + @assigns = @controller.respond_to?(:view_assigns) ? @controller.view_assigns : {} @request.session.delete('flash') if @request.session['flash'].blank? @response end @@ -448,7 +449,7 @@ module ActionController def build_request_uri(action, parameters) unless @request.env["PATH_INFO"] - options = @controller.__send__(:url_options).merge(parameters) + options = @controller.respond_to?(:url_options) ? @controller.__send__(:url_options).merge(parameters) : parameters options.update( :only_path => true, :action => action, diff --git a/actionpack/lib/action_dispatch/routing/route.rb b/actionpack/lib/action_dispatch/routing/route.rb index f91a48e16c..08a8408f25 100644 --- a/actionpack/lib/action_dispatch/routing/route.rb +++ b/actionpack/lib/action_dispatch/routing/route.rb @@ -30,7 +30,8 @@ module ActionDispatch if method = conditions[:request_method] case method when Regexp - method.source.upcase + source = method.source.upcase + source =~ /\A\^[-A-Z|]+\$\Z/ ? source[1..-2] : source else method.to_s.upcase end diff --git a/actionpack/lib/action_dispatch/testing/test_process.rb b/actionpack/lib/action_dispatch/testing/test_process.rb index c56ebc6438..16f3674164 100644 --- a/actionpack/lib/action_dispatch/testing/test_process.rb +++ b/actionpack/lib/action_dispatch/testing/test_process.rb @@ -22,7 +22,7 @@ module ActionDispatch end def cookies - @request.cookies.merge(@response.cookies) + HashWithIndifferentAccess.new(@request.cookies.merge(@response.cookies)) end def redirect_to_url diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb index a728fde748..db5f5f301a 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb @@ -878,7 +878,7 @@ module ActionView end def join_asset_file_contents(paths) - paths.collect { |path| File.read(asset_file_path!(path)) }.join("\n\n") + paths.collect { |path| File.read(asset_file_path!(path, true)) }.join("\n\n") end def write_asset_file_contents(joined_asset_path, asset_paths) @@ -896,8 +896,10 @@ module ActionView File.join(config.assets_dir, path.split('?').first) end - def asset_file_path!(path) - unless is_uri?(path) + def asset_file_path!(path, error_if_file_is_uri = false) + if is_uri?(path) + raise(Errno::ENOENT, "Asset file #{path} is uri and cannot be merged into single file") if error_if_file_is_uri + else absolute_path = asset_file_path(path) raise(Errno::ENOENT, "Asset file not found at '#{absolute_path}'" ) unless File.exist?(absolute_path) return absolute_path diff --git a/actionpack/lib/action_view/helpers/capture_helper.rb b/actionpack/lib/action_view/helpers/capture_helper.rb index 0401e6a09b..c88bd1efd5 100644 --- a/actionpack/lib/action_view/helpers/capture_helper.rb +++ b/actionpack/lib/action_view/helpers/capture_helper.rb @@ -1,4 +1,5 @@ require 'active_support/core_ext/object/blank' +require 'active_support/core_ext/string/output_safety' module ActionView # = Action View Capture Helper @@ -38,7 +39,7 @@ module ActionView value = nil buffer = with_output_buffer { value = yield(*args) } if string = buffer.presence || value and string.is_a?(String) - string + ERB::Util.html_escape string end end diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb index c1214bc44e..875ec9b77b 100644 --- a/actionpack/lib/action_view/helpers/date_helper.rb +++ b/actionpack/lib/action_view/helpers/date_helper.rb @@ -882,6 +882,8 @@ module ActionView # Returns the separator for a given datetime component def separator(type) case type + when :year + @options[:discard_year] ? "" : @options[:date_separator] when :month @options[:discard_month] ? "" : @options[:date_separator] when :day diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index d6e175c7e8..0470b051c6 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -294,10 +294,9 @@ module ActionView # # If you don't need to attach a form to a model instance, then check out # FormTagHelper#form_tag. - def form_for(record, options = nil, &proc) + def form_for(record, options = {}, &proc) raise ArgumentError, "Missing block" unless block_given? - options ||= {} options[:html] ||= {} case record @@ -1278,11 +1277,11 @@ module ActionView if association.respond_to?(:persisted?) association = [association] if @object.send(association_name).is_a?(Array) - elsif !association.is_a?(Array) + elsif !association.respond_to?(:to_ary) association = @object.send(association_name) end - if association.is_a?(Array) + if association.respond_to?(:to_ary) explicit_child_index = options[:child_index] output = ActiveSupport::SafeBuffer.new association.each do |child| diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionpack/lib/action_view/helpers/number_helper.rb index 1488e72c6e..a9400c347f 100644 --- a/actionpack/lib/action_view/helpers/number_helper.rb +++ b/actionpack/lib/action_view/helpers/number_helper.rb @@ -15,7 +15,7 @@ module ActionView # unchanged if can't be converted into a valid number. module NumberHelper - DEFAULT_CURRENCY_VALUES = { :format => "%u%n", :unit => "$", :separator => ".", :delimiter => ",", + DEFAULT_CURRENCY_VALUES = { :format => "%u%n", :negative_format => "-%u%n", :unit => "$", :separator => ".", :delimiter => ",", :precision => 2, :significant => false, :strip_insignificant_zeros => false } # Raised when argument +number+ param given to the helpers is invalid and @@ -81,15 +81,18 @@ module ActionView # in the +options+ hash. # # ==== Options - # * <tt>:locale</tt> - Sets the locale to be used for formatting (defaults to current locale). - # * <tt>:precision</tt> - Sets the level of precision (defaults to 2). - # * <tt>:unit</tt> - Sets the denomination of the currency (defaults to "$"). - # * <tt>:separator</tt> - Sets the separator between the units (defaults to "."). - # * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults to ","). - # * <tt>:format</tt> - Sets the format of the output string (defaults to "%u%n"). The field types are: - # - # %u The currency unit - # %n The number + # * <tt>:locale</tt> - Sets the locale to be used for formatting (defaults to current locale). + # * <tt>:precision</tt> - Sets the level of precision (defaults to 2). + # * <tt>:unit</tt> - Sets the denomination of the currency (defaults to "$"). + # * <tt>:separator</tt> - Sets the separator between the units (defaults to "."). + # * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults to ","). + # * <tt>:format</tt> - Sets the format for non-negative numbers (defaults to "%u%n"). + # Fields are <tt>%u</tt> for the currency, and <tt>%n</tt> + # for the number. + # * <tt>:negative_format</tt> - Sets the format for negative numbers (defaults to prepending + # an hyphen to the formatted number given by <tt>:format</tt>). + # Accepts the same fields than <tt>:format</tt>, except + # <tt>%n</tt> is here the absolute value of the number. # # ==== Examples # number_to_currency(1234567890.50) # => $1,234,567,890.50 @@ -97,6 +100,8 @@ module ActionView # number_to_currency(1234567890.506, :precision => 3) # => $1,234,567,890.506 # number_to_currency(1234567890.506, :locale => :fr) # => 1 234 567 890,506 € # + # number_to_currency(1234567890.50, :negative_format => "(%u%n)") + # # => ($1,234,567,890.51) # number_to_currency(1234567890.50, :unit => "£", :separator => ",", :delimiter => "") # # => £1234567890,50 # number_to_currency(1234567890.50, :unit => "£", :separator => ",", :delimiter => "", :format => "%n %u") @@ -110,11 +115,17 @@ module ActionView currency = I18n.translate(:'number.currency.format', :locale => options[:locale], :default => {}) defaults = DEFAULT_CURRENCY_VALUES.merge(defaults).merge!(currency) + defaults[:negative_format] = "-" + options[:format] if options[:format] options = defaults.merge!(options) unit = options.delete(:unit) format = options.delete(:format) + if number.to_f < 0 + format = options.delete(:negative_format) + number = number.respond_to?("abs") ? number.abs : number.sub(/^-/, '') + end + begin value = number_with_precision(number, options.merge(:raise => true)) format.gsub(/%n/, value).gsub(/%u/, unit).html_safe diff --git a/actionpack/lib/action_view/template/handlers/erb.rb b/actionpack/lib/action_view/template/handlers/erb.rb index b827610456..0803114f44 100644 --- a/actionpack/lib/action_view/template/handlers/erb.rb +++ b/actionpack/lib/action_view/template/handlers/erb.rb @@ -15,6 +15,7 @@ module ActionView super(value.to_s) end alias :append= :<< + alias :safe_append= :safe_concat end class Template @@ -40,7 +41,11 @@ module ActionView end def add_expr_escaped(src, code) - src << '@output_buffer.append= ' << escaped_expr(code) << ';' + if code =~ BLOCK_EXPR + src << "@output_buffer.safe_append= " << code + else + src << "@output_buffer.safe_concat((" << code << ").to_s);" + end end def add_postamble(src) diff --git a/actionpack/test/activerecord/active_record_store_test.rb b/actionpack/test/activerecord/active_record_store_test.rb index f5811a1530..7c595d1b89 100644 --- a/actionpack/test/activerecord/active_record_store_test.rb +++ b/actionpack/test/activerecord/active_record_store_test.rb @@ -27,6 +27,12 @@ class ActiveRecordStoreTest < ActionDispatch::IntegrationTest head :ok end + def renew + env["rack.session.options"][:renew] = true + session[:foo] = "baz" + head :ok + end + def rescue_action(e) raise end end @@ -64,6 +70,20 @@ class ActiveRecordStoreTest < ActionDispatch::IntegrationTest end end end + + define_method("test_renewing_with_#{class_name}_store") do + with_store class_name do + with_test_route_set do + get '/set_session_value' + assert_response :success + assert cookies['_session_id'] + + get '/renew' + assert_response :success + assert_not_equal [], headers['Set-Cookie'] + end + end + end end def test_getting_nil_session_value diff --git a/actionpack/test/controller/filters_test.rb b/actionpack/test/controller/filters_test.rb index 3a8a37d967..68febf425d 100644 --- a/actionpack/test/controller/filters_test.rb +++ b/actionpack/test/controller/filters_test.rb @@ -78,7 +78,8 @@ class FilterTest < ActionController::TestCase end class RenderingController < ActionController::Base - before_filter :render_something_else + before_filter :before_filter_rendering + after_filter :unreached_after_filter def show @ran_action = true @@ -86,9 +87,59 @@ class FilterTest < ActionController::TestCase end private - def render_something_else + def before_filter_rendering + @ran_filter ||= [] + @ran_filter << "before_filter_rendering" render :inline => "something else" end + + def unreached_after_filter + @ran_filter << "unreached_after_filter_after_render" + end + end + + class RenderingForPrependAfterFilterController < RenderingController + prepend_after_filter :unreached_prepend_after_filter + + private + def unreached_prepend_after_filter + @ran_filter << "unreached_preprend_after_filter_after_render" + end + end + + class BeforeFilterRedirectionController < ActionController::Base + before_filter :before_filter_redirects + after_filter :unreached_after_filter + + def show + @ran_action = true + render :inline => "ran show action" + end + + def target_of_redirection + @ran_target_of_redirection = true + render :inline => "ran target_of_redirection action" + end + + private + def before_filter_redirects + @ran_filter ||= [] + @ran_filter << "before_filter_redirects" + redirect_to(:action => 'target_of_redirection') + end + + def unreached_after_filter + @ran_filter << "unreached_after_filter_after_redirection" + end + end + + class BeforeFilterRedirectionForPrependAfterFilterController < BeforeFilterRedirectionController + prepend_after_filter :unreached_prepend_after_filter_after_redirection + + private + def unreached_prepend_after_filter_after_redirection + @ran_filter << "unreached_prepend_after_filter_after_redirection" + end end class ConditionalFilterController < ActionController::Base @@ -625,6 +676,32 @@ class FilterTest < ActionController::TestCase assert !assigns["ran_action"] end + def test_before_filter_rendering_breaks_filtering_chain_for_after_filter + response = test_process(RenderingController) + assert_equal %w( before_filter_rendering ), assigns["ran_filter"] + assert !assigns["ran_action"] + end + + def test_before_filter_redirects_breaks_filtering_chain_for_after_filter + response = test_process(BeforeFilterRedirectionController) + assert_response :redirect + assert_equal "http://test.host/filter_test/before_filter_redirection/target_of_redirection", redirect_to_url + assert_equal %w( before_filter_redirects ), assigns["ran_filter"] + end + + def test_before_filter_rendering_breaks_filtering_chain_for_preprend_after_filter + response = test_process(RenderingForPrependAfterFilterController) + assert_equal %w( before_filter_rendering ), assigns["ran_filter"] + assert !assigns["ran_action"] + end + + def test_before_filter_redirects_breaks_filtering_chain_for_preprend_after_filter + response = test_process(BeforeFilterRedirectionForPrependAfterFilterController) + assert_response :redirect + assert_equal "http://test.host/filter_test/before_filter_redirection_for_prepend_after_filter/target_of_redirection", redirect_to_url + assert_equal %w( before_filter_redirects ), assigns["ran_filter"] + end + def test_filters_with_mixed_specialization_run_in_order assert_nothing_raised do response = test_process(MixedSpecializationController, 'bar') diff --git a/actionpack/test/controller/mime_responds_test.rb b/actionpack/test/controller/mime_responds_test.rb index a898ef76e5..b6ce9f7d34 100644 --- a/actionpack/test/controller/mime_responds_test.rb +++ b/actionpack/test/controller/mime_responds_test.rb @@ -487,6 +487,10 @@ class RespondWithController < ActionController::Base respond_with(resource) end + def using_hash_resource + respond_with({:result => resource}) + end + def using_resource_with_block respond_with(resource) do |format| format.csv { render :text => "CSV" } @@ -587,6 +591,18 @@ class RespondWithControllerTest < ActionController::TestCase end end + def test_using_hash_resource + @request.accept = "application/xml" + get :using_hash_resource + assert_equal "application/xml", @response.content_type + assert_equal "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<hash>\n <name>david</name>\n</hash>\n", @response.body + + @request.accept = "application/json" + get :using_hash_resource + assert_equal "application/json", @response.content_type + assert_equal %Q[{"result":["david",13]}], @response.body + end + def test_using_resource_with_block @request.accept = "*/*" get :using_resource_with_block diff --git a/actionpack/test/controller/new_base/bare_metal_test.rb b/actionpack/test/controller/new_base/bare_metal_test.rb index 44922cecff..543c02b2c5 100644 --- a/actionpack/test/controller/new_base/bare_metal_test.rb +++ b/actionpack/test/controller/new_base/bare_metal_test.rb @@ -39,4 +39,11 @@ module BareMetalTest assert_equal 404, status end end + + class BareControllerTest < ActionController::TestCase + test "GET index" do + get :index + assert_equal "Hello world", @response.body + end + end end diff --git a/actionpack/test/controller/new_base/render_template_test.rb b/actionpack/test/controller/new_base/render_template_test.rb index d31193a063..9899036fe8 100644 --- a/actionpack/test/controller/new_base/render_template_test.rb +++ b/actionpack/test/controller/new_base/render_template_test.rb @@ -9,6 +9,7 @@ module RenderTemplate "locals.html.erb" => "The secret is <%= secret %>", "xml_template.xml.builder" => "xml.html do\n xml.p 'Hello'\nend", "with_raw.html.erb" => "Hello <%=raw '<strong>this is raw</strong>' %>", + "with_implicit_raw.html.erb"=> "Hello <%== '<strong>this is also raw</strong>' %>", "test/with_json.html.erb" => "<%= render :template => 'test/with_json.json' %>", "test/with_json.json.erb" => "<%= render :template => 'test/final' %>", "test/final.json.erb" => "{ final: json }", @@ -51,6 +52,10 @@ module RenderTemplate render :template => "with_raw" end + def with_implicit_raw + render :template => "with_implicit_raw" + end + def with_error render :template => "test/with_error" end @@ -99,6 +104,11 @@ module RenderTemplate assert_body "Hello <strong>this is raw</strong>" assert_status 200 + + get :with_implicit_raw + + assert_body "Hello <strong>this is also raw</strong>" + assert_status 200 end test "rendering a template with renders another template with other format that renders other template in the same format" do diff --git a/actionpack/test/dispatch/cookies_test.rb b/actionpack/test/dispatch/cookies_test.rb index faeae91f6b..5ec7f12cc1 100644 --- a/actionpack/test/dispatch/cookies_test.rb +++ b/actionpack/test/dispatch/cookies_test.rb @@ -94,6 +94,16 @@ class CookiesTest < ActionController::TestCase cookies.delete(:user_name, :domain => :all) head :ok end + + def symbol_key + cookies[:user_name] = "david" + head :ok + end + + def string_key + cookies['user_name'] = "david" + head :ok + end end tests TestController @@ -291,6 +301,14 @@ class CookiesTest < ActionController::TestCase assert_cookie_header "user_name=; domain=.nextangle.com; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT" end + def test_cookies_hash_is_indifferent_access + [:symbol_key, :string_key].each do |cookie_key| + get cookie_key + assert_equal "david", cookies[:user_name] + assert_equal "david", cookies['user_name'] + end + end + private def assert_cookie_header(expected) header = @response.headers["Set-Cookie"] diff --git a/actionpack/test/fixtures/layouts/_partial_and_yield.erb b/actionpack/test/fixtures/layouts/_partial_and_yield.erb new file mode 100644 index 0000000000..74cc428ffa --- /dev/null +++ b/actionpack/test/fixtures/layouts/_partial_and_yield.erb @@ -0,0 +1,2 @@ +<%= render :partial => 'test/partial' %> +<%= yield %> diff --git a/actionpack/test/fixtures/layouts/_yield_only.erb b/actionpack/test/fixtures/layouts/_yield_only.erb new file mode 100644 index 0000000000..37f0bddbd7 --- /dev/null +++ b/actionpack/test/fixtures/layouts/_yield_only.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/actionpack/test/fixtures/layouts/_yield_with_params.erb b/actionpack/test/fixtures/layouts/_yield_with_params.erb new file mode 100644 index 0000000000..68e6557fb8 --- /dev/null +++ b/actionpack/test/fixtures/layouts/_yield_with_params.erb @@ -0,0 +1 @@ +<%= yield 'Yield!' %> diff --git a/actionpack/test/fixtures/layouts/yield_with_render_partial_inside.erb b/actionpack/test/fixtures/layouts/yield_with_render_partial_inside.erb new file mode 100644 index 0000000000..74cc428ffa --- /dev/null +++ b/actionpack/test/fixtures/layouts/yield_with_render_partial_inside.erb @@ -0,0 +1,2 @@ +<%= render :partial => 'test/partial' %> +<%= yield %> diff --git a/actionpack/test/fixtures/test/_partial_with_partial.erb b/actionpack/test/fixtures/test/_partial_with_partial.erb new file mode 100644 index 0000000000..ee0d5037b6 --- /dev/null +++ b/actionpack/test/fixtures/test/_partial_with_partial.erb @@ -0,0 +1,2 @@ +<%= render 'test/partial' %> +partial with partial diff --git a/actionpack/test/lib/controller/fake_models.rb b/actionpack/test/lib/controller/fake_models.rb index dba632e6df..ae0c38184d 100644 --- a/actionpack/test/lib/controller/fake_models.rb +++ b/actionpack/test/lib/controller/fake_models.rb @@ -184,3 +184,13 @@ module Blog end end end + +class ArelLike + def to_ary + true + end + def each + a = Array.new(2) { |id| Comment.new(id + 1) } + a.each { |i| yield i } + end +end diff --git a/actionpack/test/template/asset_tag_helper_test.rb b/actionpack/test/template/asset_tag_helper_test.rb index 3abcdfbc1e..caf1c694c8 100644 --- a/actionpack/test/template/asset_tag_helper_test.rb +++ b/actionpack/test/template/asset_tag_helper_test.rb @@ -727,6 +727,17 @@ class AssetTagHelperTest < ActionView::TestCase assert !File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'money.js')) end + def test_caching_javascript_include_tag_when_caching_on_and_javascript_file_is_uri + ENV["RAILS_ASSET_ID"] = "" + config.perform_caching = true + + assert_raise(Errno::ENOENT) { + javascript_include_tag('bank', 'robber', 'https://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.js', :cache => true) + } + + assert !File.exist?(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'all.js')) + end + def test_caching_javascript_include_tag_when_caching_off_and_missing_javascript_file ENV["RAILS_ASSET_ID"] = "" config.perform_caching = false diff --git a/actionpack/test/template/capture_helper_test.rb b/actionpack/test/template/capture_helper_test.rb index 8f81076299..03050485fa 100644 --- a/actionpack/test/template/capture_helper_test.rb +++ b/actionpack/test/template/capture_helper_test.rb @@ -28,6 +28,16 @@ class CaptureHelperTest < ActionView::TestCase assert_nil @av.capture { 1 } end + def test_capture_escapes_html + string = @av.capture { '<em>bar</em>' } + assert_equal '<em>bar</em>', string + end + + def test_capture_doesnt_escape_twice + string = @av.capture { '<em>bar</em>'.html_safe } + assert_equal '<em>bar</em>', string + end + def test_content_for assert ! content_for?(:title) content_for :title, 'title' diff --git a/actionpack/test/template/date_helper_test.rb b/actionpack/test/template/date_helper_test.rb index 0cf7885772..55c384e68f 100644 --- a/actionpack/test/template/date_helper_test.rb +++ b/actionpack/test/template/date_helper_test.rb @@ -1584,6 +1584,47 @@ class DateHelperTest < ActionView::TestCase assert_dom_equal expected, date_select("post", "written_on", { :date_separator => " / " }) end + def test_date_select_with_separator_and_order + @post = Post.new + @post.written_on = Date.new(2004, 6, 15) + + expected = %{<select id="post_written_on_3i" name="post[written_on(3i)]">\n} + expected << %{<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</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" selected="selected">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">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} + expected << "</select>\n" + + expected << " / " + + expected << %{<select id="post_written_on_2i" name="post[written_on(2i)]">\n} + expected << %{<option value="1">January</option>\n<option value="2">February</option>\n<option value="3">March</option>\n<option value="4">April</option>\n<option value="5">May</option>\n<option value="6" selected="selected">June</option>\n<option value="7">July</option>\n<option value="8">August</option>\n<option value="9">September</option>\n<option value="10">October</option>\n<option value="11">November</option>\n<option value="12">December</option>\n} + expected << "</select>\n" + + expected << " / " + + expected << %{<select id="post_written_on_1i" name="post[written_on(1i)]">\n} + expected << %{<option value="1999">1999</option>\n<option value="2000">2000</option>\n<option value="2001">2001</option>\n<option value="2002">2002</option>\n<option value="2003">2003</option>\n<option value="2004" selected="selected">2004</option>\n<option value="2005">2005</option>\n<option value="2006">2006</option>\n<option value="2007">2007</option>\n<option value="2008">2008</option>\n<option value="2009">2009</option>\n} + expected << "</select>\n" + + assert_dom_equal expected, date_select("post", "written_on", { :order => [:day, :month, :year], :date_separator => " / " }) + end + + def test_date_select_with_separator_and_order_and_year_discarded + @post = Post.new + @post.written_on = Date.new(2004, 6, 15) + + expected = %{<select id="post_written_on_3i" name="post[written_on(3i)]">\n} + expected << %{<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</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" selected="selected">15</option>\n<option value="16">16</option>\n<option value="17">17</option>\n<option value="18">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} + expected << "</select>\n" + + expected << " / " + + expected << %{<select id="post_written_on_2i" name="post[written_on(2i)]">\n} + expected << %{<option value="1">January</option>\n<option value="2">February</option>\n<option value="3">March</option>\n<option value="4">April</option>\n<option value="5">May</option>\n<option value="6" selected="selected">June</option>\n<option value="7">July</option>\n<option value="8">August</option>\n<option value="9">September</option>\n<option value="10">October</option>\n<option value="11">November</option>\n<option value="12">December</option>\n} + expected << "</select>\n" + expected << %{<input type="hidden" id="post_written_on_1i" name="post[written_on(1i)]" value="2004" />\n} + + assert_dom_equal expected, date_select("post", "written_on", { :order => [:day, :month, :year], :discard_year => true, :date_separator => " / " }) + end + def test_date_select_with_default_prompt @post = Post.new @post.written_on = Date.new(2004, 6, 15) diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb index acb6e7aa64..2c60096475 100644 --- a/actionpack/test/template/form_helper_test.rb +++ b/actionpack/test/template/form_helper_test.rb @@ -1230,6 +1230,27 @@ class FormHelperTest < ActionView::TestCase assert_dom_equal expected, output_buffer end + def test_nested_fields_for_arel_like + @post.comments = ArelLike.new + + form_for(@post) do |f| + concat f.text_field(:title) + concat f.fields_for(:comments, @post.comments) { |cf| + concat cf.text_field(:name) + } + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', :method => 'put') do + '<input name="post[title]" size="30" type="text" id="post_title" value="Hello World" />' + + '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" size="30" type="text" value="comment #1" />' + + '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="1" />' + + '<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" size="30" type="text" value="comment #2" />' + + '<input id="post_comments_attributes_1_id" name="post[comments_attributes][1][id]" type="hidden" value="2" />' + end + + assert_dom_equal expected, output_buffer + end + def test_nested_fields_for_with_existing_records_on_a_supplied_nested_attributes_collection_different_from_record_one comments = Array.new(2) { |id| Comment.new(id + 1) } @post.comments = [] diff --git a/actionpack/test/template/number_helper_i18n_test.rb b/actionpack/test/template/number_helper_i18n_test.rb index c82ead663f..5df09b4d3b 100644 --- a/actionpack/test/template/number_helper_i18n_test.rb +++ b/actionpack/test/template/number_helper_i18n_test.rb @@ -7,7 +7,7 @@ class NumberHelperTest < ActionView::TestCase I18n.backend.store_translations 'ts', :number => { :format => { :precision => 3, :delimiter => ',', :separator => '.', :significant => false, :strip_insignificant_zeros => false }, - :currency => { :format => { :unit => '&$', :format => '%u - %n', :precision => 2 } }, + :currency => { :format => { :unit => '&$', :format => '%u - %n', :negative_format => '(%u - %n)', :precision => 2 } }, :human => { :format => { :precision => 2, @@ -43,11 +43,14 @@ class NumberHelperTest < ActionView::TestCase def test_number_to_i18n_currency assert_equal("&$ - 10.00", number_to_currency(10, :locale => 'ts')) + assert_equal("(&$ - 10.00)", number_to_currency(-10, :locale => 'ts')) + assert_equal("-10.00 - &$", number_to_currency(-10, :locale => 'ts', :format => "%n - %u")) end def test_number_to_currency_with_clean_i18n_settings clean_i18n do assert_equal("$10.00", number_to_currency(10)) + assert_equal("-$10.00", number_to_currency(-10)) end end diff --git a/actionpack/test/template/number_helper_test.rb b/actionpack/test/template/number_helper_test.rb index dcdf28ddd5..ab127521ad 100644 --- a/actionpack/test/template/number_helper_test.rb +++ b/actionpack/test/template/number_helper_test.rb @@ -45,11 +45,15 @@ class NumberHelperTest < ActionView::TestCase def test_number_to_currency assert_equal("$1,234,567,890.50", number_to_currency(1234567890.50)) assert_equal("$1,234,567,890.51", number_to_currency(1234567890.506)) + assert_equal("-$1,234,567,890.50", number_to_currency(-1234567890.50)) + assert_equal("-$ 1,234,567,890.50", number_to_currency(-1234567890.50, {:format => "%u %n"})) + assert_equal("($1,234,567,890.50)", number_to_currency(-1234567890.50, {:negative_format => "(%u%n)"})) assert_equal("$1,234,567,892", number_to_currency(1234567891.50, {:precision => 0})) assert_equal("$1,234,567,890.5", number_to_currency(1234567890.50, {:precision => 1})) assert_equal("£1234567890,50", number_to_currency(1234567890.50, {:unit => "£", :separator => ",", :delimiter => ""})) assert_equal("$1,234,567,890.50", number_to_currency("1234567890.50")) assert_equal("1,234,567,890.50 Kč", number_to_currency("1234567890.50", {:unit => "Kč", :format => "%n %u"})) + assert_equal("1,234,567,890.50 - Kč", number_to_currency("-1234567890.50", {:unit => "Kč", :format => "%n %u", :negative_format => "%n - %u"})) end def test_number_to_percentage diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb index 17bb610b6a..08d50257d4 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionpack/test/template/render_test.rb @@ -247,6 +247,36 @@ module RenderTestCases @view.render(:file => "test/hello_world.erb", :layout => "layouts/yield_with_render_inline_inside") end + def test_render_with_layout_which_renders_another_partial + assert_equal %(partial html\nHello world!\n), + @view.render(:file => "test/hello_world.erb", :layout => "layouts/yield_with_render_partial_inside") + end + + def test_render_layout_with_block_and_yield + assert_equal %(Content from block!\n), + @view.render(:layout => "layouts/yield_only") { "Content from block!" } + end + + def test_render_layout_with_block_and_yield_with_params + assert_equal %(Yield! Content from block!\n), + @view.render(:layout => "layouts/yield_with_params") { |param| "#{param} Content from block!" } + end + + def test_render_layout_with_block_which_renders_another_partial_and_yields + assert_equal %(partial html\nContent from block!\n), + @view.render(:layout => "layouts/partial_and_yield") { "Content from block!" } + end + + def test_render_partial_and_layout_without_block_with_locals + assert_equal %(Before (Foo!)\npartial html\nAfter), + @view.render(:partial => 'test/partial', :layout => 'test/layout_for_partial', :locals => { :name => 'Foo!'}) + end + + def test_render_partial_and_layout_without_block_with_locals_and_rendering_another_partial + assert_equal %(Before (Foo!)\npartial html\npartial with partial\n\nAfter), + @view.render(:partial => 'test/partial_with_partial', :layout => 'test/layout_for_partial', :locals => { :name => 'Foo!'}) + end + def test_render_with_nested_layout assert_equal %(<title>title</title>\n\n<div id="column">column</div>\n<div id="content">content</div>\n), @view.render(:file => "test/nested_layout.erb", :layout => "layouts/yield") diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb index bc2548e06c..4a8cea36d4 100644 --- a/actionpack/test/template/url_helper_test.rb +++ b/actionpack/test/template/url_helper_test.rb @@ -263,12 +263,7 @@ class UrlHelperTest < ActiveSupport::TestCase assert_equal "<strong>Showing</strong>", link_to_unless(true, "Showing", url_hash) { |name| - "<strong>#{name}</strong>" - } - - assert_equal "<strong>Showing</strong>", - link_to_unless(true, "Showing", url_hash) { |name| - "<strong>#{name}</strong>" + "<strong>#{name}</strong>".html_safe } assert_equal "test", diff --git a/activemodel/CHANGELOG b/activemodel/CHANGELOG index e93d84ab59..4e963c77b0 100644 --- a/activemodel/CHANGELOG +++ b/activemodel/CHANGELOG @@ -2,6 +2,10 @@ * No changes +*Rails 3.0.2 (unreleased)* + +* No changes + *Rails 3.0.1 (October 15, 2010)* * No Changes, just a version bump. diff --git a/activemodel/test/cases/serializeration/xml_serialization_test.rb b/activemodel/test/cases/serializeration/xml_serialization_test.rb index ff786658b7..cc19d322b3 100644 --- a/activemodel/test/cases/serializeration/xml_serialization_test.rb +++ b/activemodel/test/cases/serializeration/xml_serialization_test.rb @@ -70,6 +70,13 @@ class XmlSerializationTest < ActiveModel::TestCase assert_match %r{<CreatedAt}, @xml end + test "should allow lower-camelized tags" do + @xml = @contact.to_xml :root => 'xml_contact', :camelize => :lower + assert_match %r{^<xmlContact>}, @xml + assert_match %r{</xmlContact>$}, @xml + assert_match %r{<createdAt}, @xml + end + test "should allow skipped types" do @xml = @contact.to_xml :skip_types => true assert_match %r{<age>25</age>}, @xml diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index d3530e0da9..11eb47917d 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -18,6 +18,35 @@ [Aaron Patterson] +*Rails 3.0.2 (unreleased)* + +* reorder is deprecated in favor of except(:order).order(...) [Santiago Pastorino] + +* except is now AR public API + + Model.order('name').except(:order).order('salary') + + generates: + + SELECT * FROM models ORDER BY salary + + [Santiago Pastorino] + +* The following code: + + Model.limit(10).scoping { Model.count } + + now generates the following SQL: + + SELECT COUNT(*) FROM models LIMIT 10 + + This may not return what you want. Instead, you may with to do something + like this: + + Model.limit(10).scoping { Model.all.size } + + [Aaron Patterson] + *Rails 3.0.1 (October 15, 2010)* * Introduce a fix for CVE-2010-3993 diff --git a/activerecord/activerecord.gemspec b/activerecord/activerecord.gemspec index b8a980b1fb..b1df24844a 100644 --- a/activerecord/activerecord.gemspec +++ b/activerecord/activerecord.gemspec @@ -23,6 +23,6 @@ Gem::Specification.new do |s| s.add_dependency('activesupport', version) s.add_dependency('activemodel', version) - s.add_dependency('arel', '~> 2.0.0') + s.add_dependency('arel', '~> 2.0.2') s.add_dependency('tzinfo', '~> 0.3.23') end diff --git a/activerecord/lib/active_record/aggregations.rb b/activerecord/lib/active_record/aggregations.rb index 16206c1056..8cd7389005 100644 --- a/activerecord/lib/active_record/aggregations.rb +++ b/activerecord/lib/active_record/aggregations.rb @@ -6,7 +6,7 @@ module ActiveRecord def clear_aggregation_cache #:nodoc: self.class.reflect_on_all_aggregations.to_a.each do |assoc| instance_variable_set "@#{assoc.name}", nil - end unless self.new_record? + end if self.persisted? end # Active Record implements aggregation through a macro-like class method called +composed_of+ diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index dc466eafc2..08a4ebfd7e 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -118,7 +118,7 @@ module ActiveRecord def clear_association_cache #:nodoc: self.class.reflect_on_all_associations.to_a.each do |assoc| instance_variable_set "@#{assoc.name}", nil - end unless self.new_record? + end if self.persisted? end private @@ -1839,8 +1839,6 @@ module ActiveRecord @join_parts = [JoinBase.new(base, joins)] @associations = {} @reflections = [] - @base_records_hash = {} - @base_records_in_order = [] @table_aliases = Hash.new(0) @table_aliases[base.table_name] = 1 build(associations) @@ -1874,15 +1872,18 @@ module ActiveRecord end def instantiate(rows) - rows.each_with_index do |row, i| - primary_id = join_base.record_id(row) - unless @base_records_hash[primary_id] - @base_records_in_order << (@base_records_hash[primary_id] = join_base.instantiate(row)) - end - construct(@base_records_hash[primary_id], @associations, join_associations.dup, row) - end - remove_duplicate_results!(join_base.active_record, @base_records_in_order, @associations) - return @base_records_in_order + primary_key = join_base.aliased_primary_key + parents = {} + + records = rows.map { |model| + primary_id = model[primary_key] + parent = parents[primary_id] ||= join_base.instantiate(model) + construct(parent, @associations, join_associations.dup, model) + parent + }.uniq + + remove_duplicate_results!(join_base.active_record, records, @associations) + records end def remove_duplicate_results!(base, records, associations) @@ -1982,10 +1983,13 @@ module ActiveRecord def construct(parent, associations, join_parts, row) case associations when Symbol, String + name = associations.to_s + join_part = join_parts.detect { |j| - j.reflection.name.to_s == associations.to_s && + j.reflection.name.to_s == name && j.parent_table_name == parent.class.table_name } - raise(ConfigurationError, "No such association") if join_part.nil? + + raise(ConfigurationError, "No such association") unless join_part join_parts.delete(join_part) construct_association(parent, join_part, row) @@ -1995,13 +1999,7 @@ module ActiveRecord end when Hash associations.sort_by { |k,_| k.to_s }.each do |name, assoc| - join_part = join_parts.detect{ |j| - j.reflection.name.to_s == name.to_s && - j.parent_table_name == parent.class.table_name } - raise(ConfigurationError, "No such association") if join_part.nil? - - association = construct_association(parent, join_part, row) - join_parts.delete(join_part) + association = construct(parent, name, join_parts, row) construct(association, assoc, join_parts, row) if association end else diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb index 896e18af01..71d8c2d3c8 100644 --- a/activerecord/lib/active_record/associations/association_collection.rb +++ b/activerecord/lib/active_record/associations/association_collection.rb @@ -120,13 +120,13 @@ module ActiveRecord # Since << flattens its argument list and inserts each record, +push+ and +concat+ behave identically. def <<(*records) result = true - load_target if @owner.new_record? + load_target unless @owner.persisted? transaction do flatten_deeper(records).each do |record| raise_on_type_mismatch(record) add_record_to_target_with_callbacks(record) do |r| - result &&= insert_record(record) unless @owner.new_record? + result &&= insert_record(record) if @owner.persisted? end end end @@ -285,12 +285,12 @@ module ActiveRecord # This method is abstract in the sense that it relies on # +count_records+, which is a method descendants have to provide. def size - if @owner.new_record? || (loaded? && !@reflection.options[:uniq]) + if !@owner.persisted? || (loaded? && !@reflection.options[:uniq]) @target.size elsif !loaded? && @reflection.options[:group] load_target.size elsif !loaded? && !@reflection.options[:uniq] && @target.is_a?(Array) - unsaved_records = @target.select { |r| r.new_record? } + unsaved_records = @target.reject { |r| r.persisted? } unsaved_records.size + count_records else count_records @@ -357,7 +357,7 @@ module ActiveRecord def include?(record) return false unless record.is_a?(@reflection.klass) - return include_in_memory?(record) if record.new_record? + return include_in_memory?(record) unless record.persisted? load_target if @reflection.options[:finder_sql] && !loaded? return @target.include?(record) if loaded? exists?(record) @@ -372,7 +372,7 @@ module ActiveRecord end def load_target - if !@owner.new_record? || foreign_key_present + if @owner.persisted? || foreign_key_present begin if !loaded? if @target.is_a?(Array) && @target.any? @@ -513,7 +513,7 @@ module ActiveRecord transaction do records.each { |record| callback(:before_remove, record) } - old_records = records.reject { |r| r.new_record? } + old_records = records.select { |r| r.persisted? } yield(records, old_records) records.each { |record| callback(:after_remove, record) } end @@ -538,14 +538,14 @@ module ActiveRecord end def ensure_owner_is_not_new - if @owner.new_record? + unless @owner.persisted? raise ActiveRecord::RecordNotSaved, "You cannot call create unless the parent is saved" end end def fetch_first_or_last_using_find?(args) - args.first.kind_of?(Hash) || !(loaded? || @owner.new_record? || @reflection.options[:finder_sql] || - @target.any? { |record| record.new_record? } || args.first.kind_of?(Integer)) + args.first.kind_of?(Hash) || !(loaded? || !@owner.persisted? || @reflection.options[:finder_sql] || + !@target.all? { |record| record.persisted? } || args.first.kind_of?(Integer)) end def include_in_memory?(record) diff --git a/activerecord/lib/active_record/associations/association_proxy.rb b/activerecord/lib/active_record/associations/association_proxy.rb index 0c12c3737d..09bba213ce 100644 --- a/activerecord/lib/active_record/associations/association_proxy.rb +++ b/activerecord/lib/active_record/associations/association_proxy.rb @@ -53,7 +53,7 @@ module ActiveRecord alias_method :proxy_respond_to?, :respond_to? alias_method :proxy_extend, :extend delegate :to_param, :to => :proxy_target - instance_methods.each { |m| undef_method m unless m.to_s =~ /^(?:nil\?|send|object_id|to_a)$|^__|proxy_/ } + instance_methods.each { |m| undef_method m unless m.to_s =~ /^(?:nil\?|send|object_id|to_a)$|^__|^respond_to_missing|proxy_/ } def initialize(owner, reflection) @owner, @reflection = owner, reflection @@ -175,10 +175,10 @@ module ActiveRecord # If the association is polymorphic the type of the owner is also set. def set_belongs_to_association_for(record) if @reflection.options[:as] - record["#{@reflection.options[:as]}_id"] = @owner.id unless @owner.new_record? + record["#{@reflection.options[:as]}_id"] = @owner.id if @owner.persisted? record["#{@reflection.options[:as]}_type"] = @owner.class.base_class.name.to_s else - unless @owner.new_record? + if @owner.persisted? primary_key = @reflection.options[:primary_key] || :id record[@reflection.primary_key_name] = @owner.send(primary_key) end @@ -252,7 +252,7 @@ module ActiveRecord def load_target return nil unless defined?(@loaded) - if !loaded? and (!@owner.new_record? || foreign_key_present) + if !loaded? and (@owner.persisted? || foreign_key_present) @target = find_target end diff --git a/activerecord/lib/active_record/associations/belongs_to_association.rb b/activerecord/lib/active_record/associations/belongs_to_association.rb index 34b6cd5576..b624951cd9 100644 --- a/activerecord/lib/active_record/associations/belongs_to_association.rb +++ b/activerecord/lib/active_record/associations/belongs_to_association.rb @@ -14,7 +14,7 @@ module ActiveRecord counter_cache_name = @reflection.counter_cache_column if record.nil? - if counter_cache_name && !@owner.new_record? + if counter_cache_name && @owner.persisted? @reflection.klass.decrement_counter(counter_cache_name, previous_record_id) if @owner[@reflection.primary_key_name] end @@ -22,13 +22,13 @@ module ActiveRecord else raise_on_type_mismatch(record) - if counter_cache_name && !@owner.new_record? && record.id != @owner[@reflection.primary_key_name] + if counter_cache_name && @owner.persisted? && record.id != @owner[@reflection.primary_key_name] @reflection.klass.increment_counter(counter_cache_name, record.id) @reflection.klass.decrement_counter(counter_cache_name, @owner[@reflection.primary_key_name]) if @owner[@reflection.primary_key_name] end @target = (AssociationProxy === record ? record.target : record) - @owner[@reflection.primary_key_name] = record_id(record) unless record.new_record? + @owner[@reflection.primary_key_name] = record_id(record) if record.persisted? @updated = true end diff --git a/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb b/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb index 1fc9aba5cf..da742fa668 100644 --- a/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb +++ b/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb @@ -34,7 +34,7 @@ module ActiveRecord end def insert_record(record, force = true, validate = true) - if record.new_record? + unless record.persisted? if force record.save! else 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 437c8b1fd6..51770cff0f 100644 --- a/activerecord/lib/active_record/associations/has_many_through_association.rb +++ b/activerecord/lib/active_record/associations/has_many_through_association.rb @@ -59,7 +59,7 @@ module ActiveRecord end def insert_record(record, force = true, validate = true) - if record.new_record? + unless record.persisted? if force record.save! else diff --git a/activerecord/lib/active_record/associations/has_one_association.rb b/activerecord/lib/active_record/associations/has_one_association.rb index 17901387e9..e6e037441f 100644 --- a/activerecord/lib/active_record/associations/has_one_association.rb +++ b/activerecord/lib/active_record/associations/has_one_association.rb @@ -30,18 +30,18 @@ module ActiveRecord if dependent? && !dont_save case @reflection.options[:dependent] when :delete - @target.delete unless @target.new_record? + @target.delete if @target.persisted? @owner.clear_association_cache when :destroy - @target.destroy unless @target.new_record? + @target.destroy if @target.persisted? @owner.clear_association_cache when :nullify @target[@reflection.primary_key_name] = nil - @target.save unless @owner.new_record? || @target.new_record? + @target.save if @owner.persisted? && @target.persisted? end else @target[@reflection.primary_key_name] = nil - @target.save unless @owner.new_record? || @target.new_record? + @target.save if @owner.persisted? && @target.persisted? end end @@ -56,7 +56,7 @@ module ActiveRecord set_inverse_instance(obj, @owner) @loaded = true - unless @owner.new_record? or obj.nil? or dont_save + unless !@owner.persisted? or obj.nil? or dont_save return (obj.save ? self : false) else return (obj.nil? ? nil : self) @@ -113,7 +113,7 @@ module ActiveRecord if replace_existing replace(record, true) else - record[@reflection.primary_key_name] = @owner.id unless @owner.new_record? + record[@reflection.primary_key_name] = @owner.id if @owner.persisted? self.target = record set_inverse_instance(record, @owner) end diff --git a/activerecord/lib/active_record/associations/has_one_through_association.rb b/activerecord/lib/active_record/associations/has_one_through_association.rb index 7f28abf464..6e98f7dffb 100644 --- a/activerecord/lib/active_record/associations/has_one_through_association.rb +++ b/activerecord/lib/active_record/associations/has_one_through_association.rb @@ -21,7 +21,7 @@ module ActiveRecord if current_object new_value ? current_object.update_attributes(construct_join_attributes(new_value)) : current_object.destroy elsif new_value - if @owner.new_record? + unless @owner.persisted? self.target = new_value through_association = @owner.send(:association_instance_get, @reflection.through_reflection.name) through_association.build(construct_join_attributes(new_value)) diff --git a/activerecord/lib/active_record/attribute_methods/primary_key.rb b/activerecord/lib/active_record/attribute_methods/primary_key.rb index 82d94b848a..75ae06f5e9 100644 --- a/activerecord/lib/active_record/attribute_methods/primary_key.rb +++ b/activerecord/lib/active_record/attribute_methods/primary_key.rb @@ -3,10 +3,11 @@ module ActiveRecord module PrimaryKey extend ActiveSupport::Concern - # Returns this record's primary key value wrapped in an Array - # or nil if the record is a new_record? + # Returns this record's primary key value wrapped in an Array or nil if + # the record is not persisted? or has just been destroyed. def to_key - new_record? ? nil : [ id ] + key = send(self.class.primary_key) + [key] if key end module ClassMethods diff --git a/activerecord/lib/active_record/autosave_association.rb b/activerecord/lib/active_record/autosave_association.rb index 0b89a49896..cb5bc06580 100644 --- a/activerecord/lib/active_record/autosave_association.rb +++ b/activerecord/lib/active_record/autosave_association.rb @@ -217,7 +217,7 @@ module ActiveRecord # Returns whether or not this record has been changed in any way (including whether # any of its nested autosave associations are likewise changed) def changed_for_autosave? - new_record? || changed? || marked_for_destruction? || nested_records_changed_for_autosave? + !persisted? || changed? || marked_for_destruction? || nested_records_changed_for_autosave? end private @@ -231,7 +231,7 @@ module ActiveRecord elsif autosave association.target.find_all { |record| record.changed_for_autosave? } else - association.target.find_all { |record| record.new_record? } + association.target.find_all { |record| !record.persisted? } end end @@ -257,7 +257,7 @@ module ActiveRecord # +reflection+. def validate_collection_association(reflection) if association = association_instance_get(reflection.name) - if records = associated_records_to_validate_or_save(association, new_record?, reflection.options[:autosave]) + if records = associated_records_to_validate_or_save(association, !persisted?, reflection.options[:autosave]) records.each { |record| association_valid?(reflection, record) } end end @@ -286,7 +286,7 @@ module ActiveRecord # Is used as a before_save callback to check while saving a collection # association whether or not the parent was a new record before saving. def before_save_collection_association - @new_record_before_save = new_record? + @new_record_before_save = !persisted? true end @@ -308,7 +308,7 @@ module ActiveRecord if autosave && record.marked_for_destruction? association.destroy(record) - elsif autosave != false && (@new_record_before_save || record.new_record?) + elsif autosave != false && (@new_record_before_save || !record.persisted?) if autosave saved = association.send(:insert_record, record, false, false) else @@ -343,7 +343,7 @@ module ActiveRecord association.destroy else key = reflection.options[:primary_key] ? send(reflection.options[:primary_key]) : id - if autosave != false && (new_record? || association.new_record? || association[reflection.primary_key_name] != key || autosave) + if autosave != false && (!persisted? || !association.persisted? || association[reflection.primary_key_name] != key || autosave) association[reflection.primary_key_name] = key saved = association.save(:validate => !autosave) raise ActiveRecord::Rollback if !saved && autosave @@ -363,7 +363,7 @@ module ActiveRecord if autosave && association.marked_for_destruction? association.destroy elsif autosave != false - saved = association.save(:validate => !autosave) if association.new_record? || autosave + saved = association.save(:validate => !autosave) if !association.persisted? || autosave if association.updated? association_id = association.send(reflection.options[:primary_key] || :id) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 06a388cd21..f588475bbf 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -204,7 +204,7 @@ module ActiveRecord #:nodoc: # # # No 'Winter' tag exists # winter = Tag.find_or_initialize_by_name("Winter") - # winter.new_record? # true + # winter.persisted? # false # # To find by a subset of the attributes to be used for instantiating a new object, pass a hash instead of # a list of parameters. @@ -1368,7 +1368,7 @@ MSG def initialize(attributes = nil) @attributes = attributes_from_column_definition @attributes_cache = {} - @new_record = true + @persisted = false @readonly = false @destroyed = false @marked_for_destruction = false @@ -1403,7 +1403,7 @@ MSG clear_aggregation_cache clear_association_cache @attributes_cache = {} - @new_record = true + @persisted = false ensure_proper_type populate_with_current_scope_attributes @@ -1422,7 +1422,8 @@ MSG def init_with(coder) @attributes = coder['attributes'] @attributes_cache, @previously_changed, @changed_attributes = {}, {}, {} - @new_record = @readonly = @destroyed = @marked_for_destruction = false + @readonly = @destroyed = @marked_for_destruction = false + @persisted = true _run_find_callbacks _run_initialize_callbacks end @@ -1463,7 +1464,7 @@ MSG # Person.find(5).cache_key # => "people/5-20071224150000" (updated_at available) def cache_key case - when new_record? + when !persisted? "#{self.class.model_name.cache_key}/new" when timestamp = self[:updated_at] "#{self.class.model_name.cache_key}/#{id}-#{timestamp.to_s(:number)}" @@ -1584,8 +1585,9 @@ MSG # Returns true if the +comparison_object+ is the same object, or is of the same type and has the same id. def ==(comparison_object) comparison_object.equal?(self) || - (comparison_object.instance_of?(self.class) && - comparison_object.id == id && !comparison_object.new_record?) + persisted? && + (comparison_object.instance_of?(self.class) && + comparison_object.id == id) end # Delegates to == @@ -1630,7 +1632,7 @@ MSG # Returns the contents of the record as a nicely formatted string. def inspect attributes_as_nice_string = self.class.column_names.collect { |name| - if has_attribute?(name) || new_record? + if has_attribute?(name) || !persisted? "#{name}: #{attribute_for_inspect(name)}" end }.compact.join(", ") diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb index 6178130c00..ee9a0af35c 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -50,7 +50,7 @@ module ActiveRecord # Executes +sql+ statement in the context of this connection using # +binds+ as the bind substitutes. +name+ is logged along with # the executed +sql+ statement. - def exec(sql, name = 'SQL', binds = []) + def exec_query(sql, name = 'SQL', binds = []) end # Returns the last auto-generated ID from the affected table. diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index 7d47d06ae1..ce2352486b 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -326,7 +326,7 @@ module ActiveRecord @statements.clear end - def exec(sql, name = 'SQL', binds = []) + def exec_query(sql, name = 'SQL', binds = []) log(sql, name) do result = nil @@ -708,7 +708,7 @@ module ActiveRecord def select(sql, name = nil, binds = []) @connection.query_with_result = true - rows = exec(sql, name, binds).to_a + rows = exec_query(sql, name, binds).to_a @connection.more_results && @connection.next_result # invoking stored procedures with CLIENT_MULTI_RESULTS requires this to tidy up else connection will be dropped rows end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 58c0f85dc2..ccc5085b84 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -398,7 +398,7 @@ module ActiveRecord # Set the authorized user for this session def session_auth=(user) clear_cache! - exec "SET SESSION AUTHORIZATION #{user}" + exec_query "SET SESSION AUTHORIZATION #{user}" end # REFERENTIAL INTEGRITY ==================================== @@ -532,7 +532,7 @@ module ActiveRecord Arel.sql("$#{current_values.length + 1}") end - def exec(sql, name = 'SQL', binds = []) + def exec_query(sql, name = 'SQL', binds = []) return exec_no_cache(sql, name) if binds.empty? log(sql, name) do @@ -714,8 +714,8 @@ module ActiveRecord # Returns the list of all column definitions for a table. def columns(table_name, name = nil) # Limit, precision, and scale are all handled by the superclass. - column_definitions(table_name).collect do |name, type, default, notnull| - PostgreSQLColumn.new(name, default, type, notnull == 'f') + column_definitions(table_name).collect do |column_name, type, default, notnull| + PostgreSQLColumn.new(column_name, default, type, notnull == 'f') end end @@ -932,12 +932,12 @@ module ActiveRecord # requires that the ORDER BY include the distinct column. # # distinct("posts.id", "posts.created_at desc") - def distinct(columns, order_by) #:nodoc: - return "DISTINCT #{columns}" if order_by.blank? + def distinct(columns, orders) #:nodoc: + return "DISTINCT #{columns}" if orders.empty? # Construct a clean list of column names from the ORDER BY clause, removing # any ASC/DESC modifiers - order_columns = order_by.split(',').collect { |s| s.split.first } + order_columns = orders.collect { |s| s =~ /^(.+)\s+(ASC|DESC)\s*$/i ? $1 : s } order_columns.delete_if { |c| c.blank? } order_columns = order_columns.zip((0...order_columns.size).to_a).map { |s,i| "#{s} AS alias_#{i}" } @@ -1040,7 +1040,7 @@ module ActiveRecord # Executes a SELECT query and returns the results, performing any data type # conversions that are required to be performed here instead of in PostgreSQLColumn. def select(sql, name = nil, binds = []) - exec(sql, name, binds).to_a + exec_query(sql, name, binds).to_a end def select_raw(sql, name = nil) diff --git a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb index fc4d84a4f2..d76fc4103e 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb @@ -143,7 +143,7 @@ module ActiveRecord # DATABASE STATEMENTS ====================================== - def exec(sql, name = nil, binds = []) + def exec_query(sql, name = nil, binds = []) log(sql, name) do # Don't cache statements without bind values @@ -186,7 +186,7 @@ module ActiveRecord alias :create :insert_sql def select_rows(sql, name = nil) - exec(sql, name).rows + exec_query(sql, name).rows end def begin_db_transaction #:nodoc: @@ -210,7 +210,7 @@ module ActiveRecord WHERE type = 'table' AND NOT name = 'sqlite_sequence' SQL - exec(sql, name).map do |row| + exec_query(sql, name).map do |row| row['name'] end end @@ -222,12 +222,12 @@ module ActiveRecord end def indexes(table_name, name = nil) #:nodoc: - exec("PRAGMA index_list(#{quote_table_name(table_name)})", name).map do |row| + exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", name).map do |row| IndexDefinition.new( table_name, row['name'], row['unique'] != 0, - exec("PRAGMA index_info('#{row['name']}')").map { |col| + exec_query("PRAGMA index_info('#{row['name']}')").map { |col| col['name'] }) end @@ -241,11 +241,11 @@ module ActiveRecord end def remove_index!(table_name, index_name) #:nodoc: - exec "DROP INDEX #{quote_column_name(index_name)}" + exec_query "DROP INDEX #{quote_column_name(index_name)}" end def rename_table(name, new_name) - exec "ALTER TABLE #{quote_table_name(name)} RENAME TO #{quote_table_name(new_name)}" + exec_query "ALTER TABLE #{quote_table_name(name)} RENAME TO #{quote_table_name(new_name)}" end # See: http://www.sqlite.org/lang_altertable.html @@ -282,7 +282,7 @@ module ActiveRecord def change_column_null(table_name, column_name, null, default = nil) unless null || default.nil? - exec("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL") + exec_query("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL") end alter_table(table_name) do |definition| definition[column_name].null = null @@ -314,7 +314,7 @@ module ActiveRecord protected def select(sql, name = nil, binds = []) #:nodoc: - result = exec(sql, name, binds) + result = exec_query(sql, name, binds) columns = result.columns.map { |column| column.sub(/^"?\w+"?\./, '') } @@ -399,11 +399,11 @@ module ActiveRecord quoted_columns = columns.map { |col| quote_column_name(col) } * ',' quoted_to = quote_table_name(to) - exec("SELECT * FROM #{quote_table_name(from)}").each do |row| + exec_query("SELECT * FROM #{quote_table_name(from)}").each do |row| sql = "INSERT INTO #{quoted_to} (#{quoted_columns}) VALUES (" sql << columns.map {|col| quote row[column_mappings[col]]} * ', ' sql << ')' - exec sql + exec_query sql end end diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb index b6f87a57b8..bf626301f1 100644 --- a/activerecord/lib/active_record/locking/optimistic.rb +++ b/activerecord/lib/active_record/locking/optimistic.rb @@ -109,7 +109,7 @@ module ActiveRecord def destroy #:nodoc: return super unless locking_enabled? - unless new_record? + if persisted? lock_col = self.class.locking_column previous_value = send(lock_col).to_i diff --git a/activerecord/lib/active_record/locking/pessimistic.rb b/activerecord/lib/active_record/locking/pessimistic.rb index 9ad6a2baf7..d900831e13 100644 --- a/activerecord/lib/active_record/locking/pessimistic.rb +++ b/activerecord/lib/active_record/locking/pessimistic.rb @@ -47,7 +47,7 @@ module ActiveRecord # or pass true for "FOR UPDATE" (the default, an exclusive row lock). Returns # the locked record. def lock!(lock = true) - reload(:lock => lock) unless new_record? + reload(:lock => lock) if persisted? self end end diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb index aca91c907d..fb48459b6f 100644 --- a/activerecord/lib/active_record/nested_attributes.rb +++ b/activerecord/lib/active_record/nested_attributes.rb @@ -323,7 +323,7 @@ module ActiveRecord (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) - elsif attributes['id'] + elsif !attributes['id'].blank? raise_nested_attributes_record_not_found(association_name, attributes['id']) elsif !reject_new_record?(association_name, attributes) diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index 707c1a05be..594a2214bb 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -4,7 +4,7 @@ module ActiveRecord # Returns true if this object hasn't been saved yet -- that is, a record # for the object doesn't exist in the data store yet; otherwise, returns false. def new_record? - @new_record + !@persisted end # Returns true if this object has been destroyed, otherwise returns false. @@ -15,7 +15,7 @@ module ActiveRecord # Returns if the record is persisted, i.e. it's not a new record and it was # not destroyed. def persisted? - !(new_record? || destroyed?) + @persisted && !destroyed? end # Saves the model. @@ -94,8 +94,9 @@ module ActiveRecord became = klass.new became.instance_variable_set("@attributes", @attributes) became.instance_variable_set("@attributes_cache", @attributes_cache) - became.instance_variable_set("@new_record", new_record?) + became.instance_variable_set("@persisted", persisted?) became.instance_variable_set("@destroyed", destroyed?) + became.type = klass.name unless self.class.descends_from_active_record? became end @@ -240,7 +241,7 @@ module ActiveRecord private def create_or_update raise ReadOnlyRecord if readonly? - result = new_record? ? create : update + result = persisted? ? update : create result != false end @@ -269,7 +270,7 @@ module ActiveRecord self.id ||= new_id - @new_record = false + @persisted = true id end diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index fe1ef2e2e3..e9e9c85122 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -171,14 +171,16 @@ module ActiveRecord def exists?(id = nil) id = id.id if ActiveRecord::Base === id + relation = select(primary_key).limit(1) + case id when Array, Hash - where(id).exists? + relation = relation.where(id) else - relation = select(primary_key).limit(1) relation = relation.where(primary_key.eq(id)) if id - relation.first ? true : false end + + relation.first ? true : false end protected @@ -222,7 +224,7 @@ module ActiveRecord end def construct_limited_ids_condition(relation) - orders = relation.order_values.join(", ") + orders = relation.order_values values = @klass.connection.distinct("#{@klass.connection.quote_table_name @klass.table_name}.#{@klass.primary_key}", orders) ids_array = relation.select(values).collect {|row| row[@klass.primary_key]} diff --git a/activerecord/lib/active_record/session_store.rb b/activerecord/lib/active_record/session_store.rb index 3fc596e02a..ba99800fb2 100644 --- a/activerecord/lib/active_record/session_store.rb +++ b/activerecord/lib/active_record/session_store.rb @@ -228,7 +228,7 @@ module ActiveRecord @session_id = attributes[:session_id] @data = attributes[:data] @marshaled_data = attributes[:marshaled_data] - @new_record = @marshaled_data.nil? + @persisted = !@marshaled_data.nil? end # Lazy-unmarshal session state. @@ -252,8 +252,8 @@ module ActiveRecord marshaled_data = self.class.marshal(data) connect = connection - if @new_record - @new_record = false + unless @persisted + @persisted = true connect.update <<-end_sql, 'Create session' INSERT INTO #{table_name} ( #{connect.quote_column_name(session_id_column)}, @@ -272,7 +272,7 @@ module ActiveRecord end def destroy - return if @new_record + return unless @persisted connect = connection connect.delete <<-end_sql, 'Destroy session' @@ -321,6 +321,7 @@ module ActiveRecord if sid = current_session_id(env) Base.silence do get_session_model(env, sid).destroy + env[SESSION_RECORD_KEY] = nil end end diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb index ab737f0f88..8c94d1a2bc 100644 --- a/activerecord/lib/active_record/transactions.rb +++ b/activerecord/lib/active_record/transactions.rb @@ -242,7 +242,7 @@ module ActiveRecord with_transaction_returning_status { super } end - # Reset id and @new_record if the transaction rolls back. + # Reset id and @persisted if the transaction rolls back. def rollback_active_record_state! remember_transaction_record_state yield @@ -297,9 +297,9 @@ module ActiveRecord # Save the new record state and id of a record so it can be restored later if a transaction fails. def remember_transaction_record_state #:nodoc @_start_transaction_state ||= {} - unless @_start_transaction_state.include?(:new_record) + unless @_start_transaction_state.include?(:persisted) @_start_transaction_state[:id] = id if has_attribute?(self.class.primary_key) - @_start_transaction_state[:new_record] = @new_record + @_start_transaction_state[:persisted] = @persisted end unless @_start_transaction_state.include?(:destroyed) @_start_transaction_state[:destroyed] = @destroyed @@ -323,7 +323,7 @@ module ActiveRecord restore_state = remove_instance_variable(:@_start_transaction_state) if restore_state @attributes = @attributes.dup if @attributes.frozen? - @new_record = restore_state[:new_record] + @persisted = restore_state[:persisted] @destroyed = restore_state[:destroyed] if restore_state[:id] self.id = restore_state[:id] @@ -345,11 +345,11 @@ module ActiveRecord def transaction_include_action?(action) #:nodoc case action when :create - transaction_record_state(:new_record) + transaction_record_state(:new_record) || !transaction_record_state(:persisted) when :destroy destroyed? when :update - !(transaction_record_state(:new_record) || destroyed?) + !(transaction_record_state(:new_record) || !transaction_record_state(:persisted) || destroyed?) end end end diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index f367315b22..ee45fcdf35 100644 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -51,7 +51,7 @@ module ActiveRecord # Runs all the specified validations and returns true if no errors were added otherwise false. def valid?(context = nil) - context ||= (new_record? ? :create : :update) + context ||= (persisted? ? :update : :create) output = super(context) errors.empty? && output end diff --git a/activerecord/lib/active_record/validations/uniqueness.rb b/activerecord/lib/active_record/validations/uniqueness.rb index cb1d2ae421..3eba7510ac 100644 --- a/activerecord/lib/active_record/validations/uniqueness.rb +++ b/activerecord/lib/active_record/validations/uniqueness.rb @@ -31,7 +31,7 @@ module ActiveRecord relation = relation.where(scope_item => scope_value) end - unless record.new_record? + if record.persisted? # TODO : This should be in Arel relation = relation.where("#{record.class.quoted_table_name}.#{record.class.primary_key} <> ?", record.send(:id)) end @@ -154,33 +154,25 @@ module ActiveRecord # | # title! # # This could even happen if you use transactions with the 'serializable' - # isolation level. There are several ways to get around this problem: + # isolation level. The best way to work around this problem is to add a unique + # index to the database table using + # ActiveRecord::ConnectionAdapters::SchemaStatements#add_index. In the + # rare case that a race condition occurs, the database will guarantee + # the field's uniqueness. # - # - By locking the database table before validating, and unlocking it after - # saving. However, table locking is very expensive, and thus not - # recommended. - # - By locking a lock file before validating, and unlocking it after saving. - # This does not work if you've scaled your Rails application across - # multiple web servers (because they cannot share lock files, or cannot - # do that efficiently), and thus not recommended. - # - Creating a unique index on the field, by using - # ActiveRecord::ConnectionAdapters::SchemaStatements#add_index. In the - # rare case that a race condition occurs, the database will guarantee - # the field's uniqueness. + # When the database catches such a duplicate insertion, + # ActiveRecord::Base#save will raise an ActiveRecord::StatementInvalid + # exception. You can either choose to let this error propagate (which + # will result in the default Rails exception page being shown), or you + # can catch it and restart the transaction (e.g. by telling the user + # that the title already exists, and asking him to re-enter the title). + # This technique is also known as optimistic concurrency control: + # http://en.wikipedia.org/wiki/Optimistic_concurrency_control # - # When the database catches such a duplicate insertion, - # ActiveRecord::Base#save will raise an ActiveRecord::StatementInvalid - # exception. You can either choose to let this error propagate (which - # will result in the default Rails exception page being shown), or you - # can catch it and restart the transaction (e.g. by telling the user - # that the title already exists, and asking him to re-enter the title). - # This technique is also known as optimistic concurrency control: - # http://en.wikipedia.org/wiki/Optimistic_concurrency_control - # - # Active Record currently provides no way to distinguish unique - # index constraint errors from other types of database errors, so you - # will have to parse the (database-specific) exception message to detect - # such a case. + # Active Record currently provides no way to distinguish unique + # index constraint errors from other types of database errors, so you + # will have to parse the (database-specific) exception message to detect + # such a case. # def validates_uniqueness_of(*attr_names) validates_with UniquenessValidator, _merge_attributes(attr_names) diff --git a/activerecord/test/cases/adapters/mysql/connection_test.rb b/activerecord/test/cases/adapters/mysql/connection_test.rb index 67bd8ec7e0..62ffde558f 100644 --- a/activerecord/test/cases/adapters/mysql/connection_test.rb +++ b/activerecord/test/cases/adapters/mysql/connection_test.rb @@ -49,18 +49,18 @@ class MysqlConnectionTest < ActiveRecord::TestCase end def test_exec_no_binds - @connection.exec('drop table if exists ex') - @connection.exec(<<-eosql) + @connection.exec_query('drop table if exists ex') + @connection.exec_query(<<-eosql) CREATE TABLE `ex` (`id` int(11) DEFAULT NULL auto_increment PRIMARY KEY, `data` varchar(255)) eosql - result = @connection.exec('SELECT id, data FROM ex') + result = @connection.exec_query('SELECT id, data FROM ex') assert_equal 0, result.rows.length assert_equal 2, result.columns.length assert_equal %w{ id data }, result.columns - @connection.exec('INSERT INTO ex (id, data) VALUES (1, "foo")') - result = @connection.exec('SELECT id, data FROM ex') + @connection.exec_query('INSERT INTO ex (id, data) VALUES (1, "foo")') + result = @connection.exec_query('SELECT id, data FROM ex') assert_equal 1, result.rows.length assert_equal 2, result.columns.length @@ -68,13 +68,13 @@ class MysqlConnectionTest < ActiveRecord::TestCase end def test_exec_with_binds - @connection.exec('drop table if exists ex') - @connection.exec(<<-eosql) + @connection.exec_query('drop table if exists ex') + @connection.exec_query(<<-eosql) CREATE TABLE `ex` (`id` int(11) DEFAULT NULL auto_increment PRIMARY KEY, `data` varchar(255)) eosql - @connection.exec('INSERT INTO ex (id, data) VALUES (1, "foo")') - result = @connection.exec( + @connection.exec_query('INSERT INTO ex (id, data) VALUES (1, "foo")') + result = @connection.exec_query( 'SELECT id, data FROM ex WHERE id = ?', nil, [[nil, 1]]) assert_equal 1, result.rows.length @@ -84,15 +84,15 @@ class MysqlConnectionTest < ActiveRecord::TestCase end def test_exec_typecasts_bind_vals - @connection.exec('drop table if exists ex') - @connection.exec(<<-eosql) + @connection.exec_query('drop table if exists ex') + @connection.exec_query(<<-eosql) CREATE TABLE `ex` (`id` int(11) DEFAULT NULL auto_increment PRIMARY KEY, `data` varchar(255)) eosql - @connection.exec('INSERT INTO ex (id, data) VALUES (1, "foo")') + @connection.exec_query('INSERT INTO ex (id, data) VALUES (1, "foo")') column = @connection.columns('ex').find { |col| col.name == 'id' } - result = @connection.exec( + result = @connection.exec_query( 'SELECT id, data FROM ex WHERE id = ?', nil, [[column, '1-fuu']]) assert_equal 1, result.rows.length diff --git a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb index b0fd2273df..b0a4a4e39d 100644 --- a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb +++ b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb @@ -5,8 +5,8 @@ module ActiveRecord class PostgreSQLAdapterTest < ActiveRecord::TestCase def setup @connection = ActiveRecord::Base.connection - @connection.exec('drop table if exists ex') - @connection.exec('create table ex(id serial primary key, data character varying(255))') + @connection.exec_query('drop table if exists ex') + @connection.exec_query('create table ex(id serial primary key, data character varying(255))') end def test_table_alias_length @@ -16,14 +16,14 @@ module ActiveRecord end def test_exec_no_binds - result = @connection.exec('SELECT id, data FROM ex') + result = @connection.exec_query('SELECT id, data FROM ex') assert_equal 0, result.rows.length assert_equal 2, result.columns.length assert_equal %w{ id data }, result.columns string = @connection.quote('foo') - @connection.exec("INSERT INTO ex (id, data) VALUES (1, #{string})") - result = @connection.exec('SELECT id, data FROM ex') + @connection.exec_query("INSERT INTO ex (id, data) VALUES (1, #{string})") + result = @connection.exec_query('SELECT id, data FROM ex') assert_equal 1, result.rows.length assert_equal 2, result.columns.length @@ -32,8 +32,8 @@ module ActiveRecord def test_exec_with_binds string = @connection.quote('foo') - @connection.exec("INSERT INTO ex (id, data) VALUES (1, #{string})") - result = @connection.exec( + @connection.exec_query("INSERT INTO ex (id, data) VALUES (1, #{string})") + result = @connection.exec_query( 'SELECT id, data FROM ex WHERE id = $1', nil, [[nil, 1]]) assert_equal 1, result.rows.length @@ -44,10 +44,10 @@ module ActiveRecord def test_exec_typecasts_bind_vals string = @connection.quote('foo') - @connection.exec("INSERT INTO ex (id, data) VALUES (1, #{string})") + @connection.exec_query("INSERT INTO ex (id, data) VALUES (1, #{string})") column = @connection.columns('ex').find { |col| col.name == 'id' } - result = @connection.exec( + result = @connection.exec_query( 'SELECT id, data FROM ex WHERE id = $1', nil, [[column, '1-fuu']]) assert_equal 1, result.rows.length diff --git a/activerecord/test/cases/adapters/postgresql/schema_authorization_test.rb b/activerecord/test/cases/adapters/postgresql/schema_authorization_test.rb index 881631fb19..d5e1838543 100644 --- a/activerecord/test/cases/adapters/postgresql/schema_authorization_test.rb +++ b/activerecord/test/cases/adapters/postgresql/schema_authorization_test.rb @@ -55,7 +55,7 @@ class SchemaAuthorizationTest < ActiveRecord::TestCase set_session_auth USERS.each do |u| set_session_auth u - assert_equal u, @connection.exec("SELECT name FROM #{TABLE_NAME} WHERE id = $1", 'SQL', [[nil, 1]]).first['name'] + assert_equal u, @connection.exec_query("SELECT name FROM #{TABLE_NAME} WHERE id = $1", 'SQL', [[nil, 1]]).first['name'] set_session_auth end end @@ -67,7 +67,7 @@ class SchemaAuthorizationTest < ActiveRecord::TestCase USERS.each do |u| @connection.clear_cache! set_session_auth u - assert_equal u, @connection.exec("SELECT name FROM #{TABLE_NAME} WHERE id = $1", 'SQL', [[nil, 1]]).first['name'] + assert_equal u, @connection.exec_query("SELECT name FROM #{TABLE_NAME} WHERE id = $1", 'SQL', [[nil, 1]]).first['name'] set_session_auth end end diff --git a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb index 973c51f3d7..234696adeb 100644 --- a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb @@ -58,24 +58,24 @@ module ActiveRecord end def test_exec_no_binds - @conn.exec('create table ex(id int, data string)') - result = @conn.exec('SELECT id, data FROM ex') + @conn.exec_query('create table ex(id int, data string)') + result = @conn.exec_query('SELECT id, data FROM ex') assert_equal 0, result.rows.length assert_equal 2, result.columns.length assert_equal %w{ id data }, result.columns - @conn.exec('INSERT INTO ex (id, data) VALUES (1, "foo")') - result = @conn.exec('SELECT id, data FROM ex') + @conn.exec_query('INSERT INTO ex (id, data) VALUES (1, "foo")') + result = @conn.exec_query('SELECT id, data FROM ex') assert_equal 1, result.rows.length assert_equal 2, result.columns.length assert_equal [[1, 'foo']], result.rows end - def test_exec_with_binds - @conn.exec('create table ex(id int, data string)') - @conn.exec('INSERT INTO ex (id, data) VALUES (1, "foo")') - result = @conn.exec( + def test_exec_query_with_binds + @conn.exec_query('create table ex(id int, data string)') + @conn.exec_query('INSERT INTO ex (id, data) VALUES (1, "foo")') + result = @conn.exec_query( 'SELECT id, data FROM ex WHERE id = ?', nil, [[nil, 1]]) assert_equal 1, result.rows.length @@ -84,12 +84,12 @@ module ActiveRecord assert_equal [[1, 'foo']], result.rows end - def test_exec_typecasts_bind_vals - @conn.exec('create table ex(id int, data string)') - @conn.exec('INSERT INTO ex (id, data) VALUES (1, "foo")') + def test_exec_query_typecasts_bind_vals + @conn.exec_query('create table ex(id int, data string)') + @conn.exec_query('INSERT INTO ex (id, data) VALUES (1, "foo")') column = @conn.columns('ex').find { |col| col.name == 'id' } - result = @conn.exec( + result = @conn.exec_query( 'SELECT id, data FROM ex WHERE id = ?', nil, [[column, '1-fuu']]) assert_equal 1, result.rows.length diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb index 0fa4328826..1b0c00bd5a 100644 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -285,10 +285,10 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase final_cut = Client.new("name" => "Final Cut") firm = Firm.find(1) final_cut.firm = firm - assert final_cut.new_record? + assert !final_cut.persisted? assert final_cut.save - assert !final_cut.new_record? - assert !firm.new_record? + assert final_cut.persisted? + assert firm.persisted? assert_equal firm, final_cut.firm assert_equal firm, final_cut.firm(true) end @@ -297,10 +297,10 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase final_cut = Client.new("name" => "Final Cut") firm = Firm.find(1) final_cut.firm_with_primary_key = firm - assert final_cut.new_record? + assert !final_cut.persisted? assert final_cut.save - assert !final_cut.new_record? - assert !firm.new_record? + assert final_cut.persisted? + assert firm.persisted? assert_equal firm, final_cut.firm_with_primary_key assert_equal firm, final_cut.firm_with_primary_key(true) end diff --git a/activerecord/test/cases/associations/cascaded_eager_loading_test.rb b/activerecord/test/cases/associations/cascaded_eager_loading_test.rb index 271bb92ee8..37c6f354a8 100644 --- a/activerecord/test/cases/associations/cascaded_eager_loading_test.rb +++ b/activerecord/test/cases/associations/cascaded_eager_loading_test.rb @@ -137,7 +137,7 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase end def test_eager_association_loading_with_multiple_stis_and_order - author = Author.find(:first, :include => { :posts => [ :special_comments , :very_special_comment ] }, :order => 'authors.name, comments.body, very_special_comments_posts.body', :conditions => 'posts.id = 4') + author = Author.find(:first, :include => { :posts => [ :special_comments , :very_special_comment ] }, :order => ['authors.name', 'comments.body', 'very_special_comments_posts.body'], :conditions => 'posts.id = 4') assert_equal authors(:david), author assert_no_queries do author.posts.first.special_comments diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb index 2d8e02e398..b559c9ddad 100644 --- a/activerecord/test/cases/associations/eager_test.rb +++ b/activerecord/test/cases/associations/eager_test.rb @@ -584,8 +584,8 @@ class EagerAssociationTest < ActiveRecord::TestCase end def test_limited_eager_with_multiple_order_columns - assert_equal posts(:thinking, :sti_comments), Post.find(:all, :include => [:author, :comments], :conditions => "authors.name = 'David'", :order => 'UPPER(posts.title), posts.id', :limit => 2, :offset => 1) - assert_equal posts(:sti_post_and_comments, :sti_comments), Post.find(:all, :include => [:author, :comments], :conditions => "authors.name = 'David'", :order => 'UPPER(posts.title) DESC, posts.id', :limit => 2, :offset => 1) + assert_equal posts(:thinking, :sti_comments), Post.find(:all, :include => [:author, :comments], :conditions => "authors.name = 'David'", :order => ['UPPER(posts.title)', 'posts.id'], :limit => 2, :offset => 1) + assert_equal posts(:sti_post_and_comments, :sti_comments), Post.find(:all, :include => [:author, :comments], :conditions => "authors.name = 'David'", :order => ['UPPER(posts.title) DESC', 'posts.id'], :limit => 2, :offset => 1) end def test_limited_eager_with_numeric_in_association diff --git a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb index 7e070e1746..c55523de38 100644 --- a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb @@ -251,10 +251,10 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase no_of_projects = Project.count aredridel = Developer.new("name" => "Aredridel") aredridel.projects.concat([Project.find(1), p = Project.new("name" => "Projekt")]) - assert aredridel.new_record? - assert p.new_record? + assert !aredridel.persisted? + assert !p.persisted? assert aredridel.save - assert !aredridel.new_record? + assert aredridel.persisted? assert_equal no_of_devels+1, Developer.count assert_equal no_of_projects+1, Project.count assert_equal 2, aredridel.projects.size @@ -288,9 +288,9 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase assert_equal devel.projects.last, proj assert devel.projects.loaded? - assert proj.new_record? + assert !proj.persisted? devel.save - assert !proj.new_record? + assert proj.persisted? assert_equal devel.projects.last, proj assert_equal Developer.find(1).projects.sort_by(&:id).last, proj # prove join table is updated end @@ -300,10 +300,10 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase proj1 = devel.projects.build(:name => "Make bed") proj2 = devel.projects.build(:name => "Lie in it") assert_equal devel.projects.last, proj2 - assert proj2.new_record? + assert !proj2.persisted? devel.save - assert !devel.new_record? - assert !proj2.new_record? + assert devel.persisted? + assert proj2.persisted? assert_equal devel.projects.last, proj2 assert_equal Developer.find_by_name("Marcel").projects.last, proj2 # prove join table is updated end @@ -316,7 +316,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase assert_equal devel.projects.last, proj assert !devel.projects.loaded? - assert !proj.new_record? + assert proj.persisted? assert_equal Developer.find(1).projects.sort_by(&:id).last, proj # prove join table is updated end @@ -325,10 +325,10 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase proj1 = devel.projects.build(:name => "Make bed") proj2 = devel.projects.build(:name => "Lie in it") assert_equal devel.projects.last, proj2 - assert proj2.new_record? + assert !proj2.persisted? devel.save - assert !devel.new_record? - assert !proj2.new_record? + assert devel.persisted? + assert proj2.persisted? assert_equal devel.projects.last, proj2 assert_equal Developer.find_by_name("Marcel").projects.last, proj2 # prove join table is updated end @@ -343,7 +343,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase # in Oracle '' is saved as null therefore need to save ' ' in not null column another_post = categories(:general).post_with_conditions.create(:body => ' ') - assert !another_post.new_record? + assert another_post.persisted? assert_equal 'Yet Another Testing Title', another_post.title end diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index c9f00fd737..e9c119b823 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -187,7 +187,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase another = author.posts.find_or_create_by_title_and_body("Another Post", "This is the Body") assert_equal number_of_posts + 1, Post.count assert_equal another, author.posts.find_or_create_by_title_and_body("Another Post", "This is the Body") - assert !another.new_record? + assert another.persisted? end def test_cant_save_has_many_readonly_association @@ -453,7 +453,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert !company.clients_of_firm.loaded? assert_equal "Another Client", new_client.name - assert new_client.new_record? + assert !new_client.persisted? assert_equal new_client, company.clients_of_firm.last end @@ -508,7 +508,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert !company.clients_of_firm.loaded? assert_equal "Another Client", new_client.name - assert new_client.new_record? + assert !new_client.persisted? assert_equal new_client, company.clients_of_firm.last end @@ -543,7 +543,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_create force_signal37_to_load_all_clients_of_firm new_client = companies(:first_firm).clients_of_firm.create("name" => "Another Client") - assert !new_client.new_record? + assert new_client.persisted? assert_equal new_client, companies(:first_firm).clients_of_firm.last assert_equal new_client, companies(:first_firm).clients_of_firm(true).last end @@ -563,7 +563,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase the_client = companies(:first_firm).clients.find_or_initialize_by_name("Yet another client") assert_equal companies(:first_firm).id, the_client.firm_id assert_equal "Yet another client", the_client.name - assert the_client.new_record? + assert !the_client.persisted? end def test_find_or_create_updates_size @@ -752,7 +752,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase another_ms_client = companies(:first_firm).clients_like_ms_with_hash_conditions.create - assert !another_ms_client.new_record? + assert another_ms_client.persisted? assert_equal 'Microsoft', another_ms_client.name end diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb index b522be3fe0..6fbeff8aa9 100644 --- a/activerecord/test/cases/associations/has_one_associations_test.rb +++ b/activerecord/test/cases/associations/has_one_associations_test.rb @@ -268,7 +268,7 @@ class HasOneAssociationsTest < ActiveRecord::TestCase def test_assignment_before_child_saved firm = Firm.find(1) firm.account = a = Account.new("credit_limit" => 1000) - assert !a.new_record? + assert a.persisted? assert_equal a, firm.account assert_equal a, firm.account assert_equal a, firm.account(true) @@ -323,7 +323,7 @@ class HasOneAssociationsTest < ActiveRecord::TestCase def test_create_respects_hash_condition account = companies(:first_firm).create_account_limit_500_with_hash_conditions - assert !account.new_record? + assert account.persisted? assert_equal 500, account.credit_limit end diff --git a/activerecord/test/cases/associations/join_model_test.rb b/activerecord/test/cases/associations/join_model_test.rb index 7a22ce4dad..96edcfbb35 100644 --- a/activerecord/test/cases/associations/join_model_test.rb +++ b/activerecord/test/cases/associations/join_model_test.rb @@ -450,11 +450,11 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase new_tag = Tag.new(:name => "new") saved_post.tags << new_tag - assert !new_tag.new_record? #consistent with habtm! - assert !saved_post.new_record? + assert new_tag.persisted? #consistent with habtm! + assert saved_post.persisted? assert saved_post.tags.include?(new_tag) - assert !new_tag.new_record? + assert new_tag.persisted? assert saved_post.reload.tags(true).include?(new_tag) @@ -462,16 +462,16 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase saved_tag = tags(:general) new_post.tags << saved_tag - assert new_post.new_record? - assert !saved_tag.new_record? + assert !new_post.persisted? + assert saved_tag.persisted? assert new_post.tags.include?(saved_tag) new_post.save! - assert !new_post.new_record? + assert new_post.persisted? assert new_post.reload.tags(true).include?(saved_tag) - assert posts(:thinking).tags.build.new_record? - assert posts(:thinking).tags.new.new_record? + assert !posts(:thinking).tags.build.persisted? + assert !posts(:thinking).tags.new.persisted? end def test_create_associate_when_adding_to_has_many_through diff --git a/activerecord/test/cases/autosave_association_test.rb b/activerecord/test/cases/autosave_association_test.rb index 89be94c81f..459f9fa55c 100644 --- a/activerecord/test/cases/autosave_association_test.rb +++ b/activerecord/test/cases/autosave_association_test.rb @@ -83,7 +83,7 @@ class TestDefaultAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCas assert !firm.build_account_using_primary_key.valid? assert firm.save - assert firm.account_using_primary_key.new_record? + assert !firm.account_using_primary_key.persisted? end def test_save_fails_for_invalid_has_one @@ -114,10 +114,10 @@ class TestDefaultAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCas account = firm.account.build("credit_limit" => 1000) assert_equal account, firm.account - assert account.new_record? + assert !account.persisted? assert firm.save assert_equal account, firm.account - assert !account.new_record? + assert account.persisted? end def test_build_before_either_saved @@ -125,16 +125,16 @@ class TestDefaultAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCas firm.account = account = Account.new("credit_limit" => 1000) assert_equal account, firm.account - assert account.new_record? + assert !account.persisted? assert firm.save assert_equal account, firm.account - assert !account.new_record? + assert account.persisted? end def test_assignment_before_parent_saved firm = Firm.new("name" => "GlobalMegaCorp") firm.account = a = Account.find(1) - assert firm.new_record? + assert !firm.persisted? assert_equal a, firm.account assert firm.save assert_equal a, firm.account @@ -144,12 +144,12 @@ class TestDefaultAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCas def test_assignment_before_either_saved firm = Firm.new("name" => "GlobalMegaCorp") firm.account = a = Account.new("credit_limit" => 1000) - assert firm.new_record? - assert a.new_record? + assert !firm.persisted? + assert !a.persisted? assert_equal a, firm.account assert firm.save - assert !firm.new_record? - assert !a.new_record? + assert firm.persisted? + assert a.persisted? assert_equal a, firm.account assert_equal a, firm.account(true) end @@ -203,7 +203,7 @@ class TestDefaultAutosaveAssociationOnABelongsToAssociation < ActiveRecord::Test assert !client.firm.valid? assert client.save - assert client.firm.new_record? + assert !client.firm.persisted? end def test_save_fails_for_invalid_belongs_to @@ -232,10 +232,10 @@ class TestDefaultAutosaveAssociationOnABelongsToAssociation < ActiveRecord::Test apple = Firm.new("name" => "Apple") client.firm = apple assert_equal apple, client.firm - assert apple.new_record? + assert !apple.persisted? assert client.save assert apple.save - assert !apple.new_record? + assert apple.persisted? assert_equal apple, client.firm assert_equal apple, client.firm(true) end @@ -244,11 +244,11 @@ class TestDefaultAutosaveAssociationOnABelongsToAssociation < ActiveRecord::Test final_cut = Client.new("name" => "Final Cut") apple = Firm.new("name" => "Apple") final_cut.firm = apple - assert final_cut.new_record? - assert apple.new_record? + assert !final_cut.persisted? + assert !apple.persisted? assert final_cut.save - assert !final_cut.new_record? - assert !apple.new_record? + assert final_cut.persisted? + assert apple.persisted? assert_equal apple, final_cut.firm assert_equal apple, final_cut.firm(true) end @@ -348,10 +348,10 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa def test_invalid_adding firm = Firm.find(1) assert !(firm.clients_of_firm << c = Client.new) - assert c.new_record? + assert !c.persisted? assert !firm.valid? assert !firm.save - assert c.new_record? + assert !c.persisted? end def test_invalid_adding_before_save @@ -359,12 +359,12 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa no_of_clients = Client.count new_firm = Firm.new("name" => "A New Firm, Inc") new_firm.clients_of_firm.concat([c = Client.new, Client.new("name" => "Apple")]) - assert c.new_record? + assert !c.persisted? assert !c.valid? assert !new_firm.valid? assert !new_firm.save - assert c.new_record? - assert new_firm.new_record? + assert !c.persisted? + assert !new_firm.persisted? end def test_invalid_adding_with_validate_false @@ -375,7 +375,7 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa assert firm.valid? assert !client.valid? assert firm.save - assert client.new_record? + assert !client.persisted? end def test_valid_adding_with_validate_false @@ -386,22 +386,22 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa assert firm.valid? assert client.valid? - assert client.new_record? + assert !client.persisted? firm.unvalidated_clients_of_firm << client assert firm.save - assert !client.new_record? + assert client.persisted? assert_equal no_of_clients + 1, Client.count end def test_invalid_build new_client = companies(:first_firm).clients_of_firm.build - assert new_client.new_record? + assert !new_client.persisted? assert !new_client.valid? assert_equal new_client, companies(:first_firm).clients_of_firm.last assert !companies(:first_firm).save - assert new_client.new_record? + assert !new_client.persisted? assert_equal 1, companies(:first_firm).clients_of_firm(true).size end @@ -420,8 +420,8 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa assert_equal no_of_firms, Firm.count # Firm was not saved to database. assert_equal no_of_clients, Client.count # Clients were not saved to database. assert new_firm.save - assert !new_firm.new_record? - assert !c.new_record? + assert new_firm.persisted? + assert c.persisted? assert_equal new_firm, c.firm assert_equal no_of_firms + 1, Firm.count # Firm was saved to database. assert_equal no_of_clients + 2, Client.count # Clients were saved to database. @@ -455,7 +455,7 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa company.name += '-changed' assert_queries(2) { assert company.save } - assert !new_client.new_record? + assert new_client.persisted? assert_equal 2, company.clients_of_firm(true).size end @@ -475,7 +475,7 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa company.name += '-changed' assert_queries(2) { assert company.save } - assert !new_client.new_record? + assert new_client.persisted? assert_equal 2, company.clients_of_firm(true).size end @@ -507,62 +507,62 @@ class TestDefaultAutosaveAssociationOnNewRecord < ActiveRecord::TestCase new_account = Account.new("credit_limit" => 1000) new_firm = Firm.new("name" => "some firm") - assert new_firm.new_record? + assert !new_firm.persisted? new_account.firm = new_firm new_account.save! - assert !new_firm.new_record? + assert new_firm.persisted? new_account = Account.new("credit_limit" => 1000) new_autosaved_firm = Firm.new("name" => "some firm") - assert new_autosaved_firm.new_record? + assert !new_autosaved_firm.persisted? new_account.unautosaved_firm = new_autosaved_firm new_account.save! - assert new_autosaved_firm.new_record? + assert !new_autosaved_firm.persisted? end def test_autosave_new_record_on_has_one_can_be_disabled_per_relationship firm = Firm.new("name" => "some firm") account = Account.new("credit_limit" => 1000) - assert account.new_record? + assert !account.persisted? firm.account = account firm.save! - assert !account.new_record? + assert account.persisted? firm = Firm.new("name" => "some firm") account = Account.new("credit_limit" => 1000) firm.unautosaved_account = account - assert account.new_record? + assert !account.persisted? firm.unautosaved_account = account firm.save! - assert account.new_record? + assert !account.persisted? end def test_autosave_new_record_on_has_many_can_be_disabled_per_relationship firm = Firm.new("name" => "some firm") account = Account.new("credit_limit" => 1000) - assert account.new_record? + assert !account.persisted? firm.accounts << account firm.save! - assert !account.new_record? + assert account.persisted? firm = Firm.new("name" => "some firm") account = Account.new("credit_limit" => 1000) - assert account.new_record? + assert !account.persisted? firm.unautosaved_accounts << account firm.save! - assert account.new_record? + assert !account.persisted? end end diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index ceb1272862..9f2b0c9c86 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -656,8 +656,8 @@ class BasicsTest < ActiveRecord::TestCase end def test_new_record_returns_boolean - assert_equal true, Topic.new.new_record? - assert_equal false, Topic.find(1).new_record? + assert_equal false, Topic.new.persisted? + assert_equal true, Topic.find(1).persisted? end def test_clone @@ -665,7 +665,7 @@ class BasicsTest < ActiveRecord::TestCase cloned_topic = nil assert_nothing_raised { cloned_topic = topic.clone } assert_equal topic.title, cloned_topic.title - assert cloned_topic.new_record? + assert !cloned_topic.persisted? # test if the attributes have been cloned topic.title = "a" @@ -684,7 +684,7 @@ class BasicsTest < ActiveRecord::TestCase # test if saved clone object differs from original cloned_topic.save - assert !cloned_topic.new_record? + assert cloned_topic.persisted? assert_not_equal cloned_topic.id, topic.id cloned_topic.reload @@ -700,7 +700,7 @@ class BasicsTest < ActiveRecord::TestCase assert_nothing_raised { clone = dev.clone } assert_kind_of DeveloperSalary, clone.salary assert_equal dev.salary.amount, clone.salary.amount - assert clone.new_record? + assert !clone.persisted? # test if the attributes have been cloned original_amount = clone.salary.amount @@ -708,7 +708,7 @@ class BasicsTest < ActiveRecord::TestCase assert_equal original_amount, clone.salary.amount assert clone.save - assert !clone.new_record? + assert clone.persisted? assert_not_equal clone.id, dev.id end diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb index c058196078..87ec999b03 100644 --- a/activerecord/test/cases/finder_test.rb +++ b/activerecord/test/cases/finder_test.rb @@ -726,7 +726,7 @@ class FinderTest < ActiveRecord::TestCase sig38 = Company.find_or_create_by_name("38signals") assert_equal number_of_companies + 1, Company.count assert_equal sig38, Company.find_or_create_by_name("38signals") - assert !sig38.new_record? + assert sig38.persisted? end def test_find_or_create_from_two_attributes @@ -734,7 +734,7 @@ class FinderTest < ActiveRecord::TestCase another = Topic.find_or_create_by_title_and_author_name("Another topic","John") assert_equal number_of_topics + 1, Topic.count assert_equal another, Topic.find_or_create_by_title_and_author_name("Another topic", "John") - assert !another.new_record? + assert another.persisted? end def test_find_or_create_from_two_attributes_with_one_being_an_aggregate @@ -742,7 +742,7 @@ class FinderTest < ActiveRecord::TestCase created_customer = Customer.find_or_create_by_balance_and_name(Money.new(123), "Elizabeth") assert_equal number_of_customers + 1, Customer.count assert_equal created_customer, Customer.find_or_create_by_balance(Money.new(123), "Elizabeth") - assert !created_customer.new_record? + assert created_customer.persisted? end def test_find_or_create_from_one_attribute_and_hash @@ -750,7 +750,7 @@ class FinderTest < ActiveRecord::TestCase sig38 = Company.find_or_create_by_name({:name => "38signals", :firm_id => 17, :client_of => 23}) assert_equal number_of_companies + 1, Company.count assert_equal sig38, Company.find_or_create_by_name({:name => "38signals", :firm_id => 17, :client_of => 23}) - assert !sig38.new_record? + assert sig38.persisted? assert_equal "38signals", sig38.name assert_equal 17, sig38.firm_id assert_equal 23, sig38.client_of @@ -761,7 +761,7 @@ class FinderTest < ActiveRecord::TestCase created_customer = Customer.find_or_create_by_balance(Money.new(123)) assert_equal number_of_customers + 1, Customer.count assert_equal created_customer, Customer.find_or_create_by_balance(Money.new(123)) - assert !created_customer.new_record? + assert created_customer.persisted? end def test_find_or_create_from_one_aggregate_attribute_and_hash @@ -771,7 +771,7 @@ class FinderTest < ActiveRecord::TestCase created_customer = Customer.find_or_create_by_balance({:balance => balance, :name => name}) assert_equal number_of_customers + 1, Customer.count assert_equal created_customer, Customer.find_or_create_by_balance({:balance => balance, :name => name}) - assert !created_customer.new_record? + assert created_customer.persisted? assert_equal balance, created_customer.balance assert_equal name, created_customer.name end @@ -779,13 +779,13 @@ class FinderTest < ActiveRecord::TestCase def test_find_or_initialize_from_one_attribute sig38 = Company.find_or_initialize_by_name("38signals") assert_equal "38signals", sig38.name - assert sig38.new_record? + assert !sig38.persisted? end def test_find_or_initialize_from_one_aggregate_attribute new_customer = Customer.find_or_initialize_by_balance(Money.new(123)) assert_equal 123, new_customer.balance.amount - assert new_customer.new_record? + assert !new_customer.persisted? end def test_find_or_initialize_from_one_attribute_should_not_set_attribute_even_when_protected @@ -793,7 +793,7 @@ class FinderTest < ActiveRecord::TestCase assert_equal "Fortune 1000", c.name assert_not_equal 1000, c.rating assert c.valid? - assert c.new_record? + assert !c.persisted? end def test_find_or_create_from_one_attribute_should_not_set_attribute_even_when_protected @@ -801,7 +801,7 @@ class FinderTest < ActiveRecord::TestCase assert_equal "Fortune 1000", c.name assert_not_equal 1000, c.rating assert c.valid? - assert !c.new_record? + assert c.persisted? end def test_find_or_initialize_from_one_attribute_should_set_attribute_even_when_protected @@ -809,7 +809,7 @@ class FinderTest < ActiveRecord::TestCase assert_equal "Fortune 1000", c.name assert_equal 1000, c.rating assert c.valid? - assert c.new_record? + assert !c.persisted? end def test_find_or_create_from_one_attribute_should_set_attribute_even_when_protected @@ -817,7 +817,7 @@ class FinderTest < ActiveRecord::TestCase assert_equal "Fortune 1000", c.name assert_equal 1000, c.rating assert c.valid? - assert !c.new_record? + assert c.persisted? end def test_find_or_initialize_from_one_attribute_should_set_attribute_even_when_protected_and_also_set_the_hash @@ -825,7 +825,7 @@ class FinderTest < ActiveRecord::TestCase assert_equal "Fortune 1000", c.name assert_equal 1000, c.rating assert c.valid? - assert c.new_record? + assert !c.persisted? end def test_find_or_create_from_one_attribute_should_set_attribute_even_when_protected_and_also_set_the_hash @@ -833,7 +833,7 @@ class FinderTest < ActiveRecord::TestCase assert_equal "Fortune 1000", c.name assert_equal 1000, c.rating assert c.valid? - assert !c.new_record? + assert c.persisted? end def test_find_or_initialize_should_set_protected_attributes_if_given_as_block @@ -841,7 +841,7 @@ class FinderTest < ActiveRecord::TestCase assert_equal "Fortune 1000", c.name assert_equal 1000.to_f, c.rating.to_f assert c.valid? - assert c.new_record? + assert !c.persisted? end def test_find_or_create_should_set_protected_attributes_if_given_as_block @@ -849,7 +849,7 @@ class FinderTest < ActiveRecord::TestCase assert_equal "Fortune 1000", c.name assert_equal 1000.to_f, c.rating.to_f assert c.valid? - assert !c.new_record? + assert c.persisted? end def test_find_or_create_should_work_with_block_on_first_call @@ -860,21 +860,21 @@ class FinderTest < ActiveRecord::TestCase assert_equal "Fortune 1000", c.name assert_equal 1000.to_f, c.rating.to_f assert c.valid? - assert !c.new_record? + assert c.persisted? end def test_find_or_initialize_from_two_attributes another = Topic.find_or_initialize_by_title_and_author_name("Another topic","John") assert_equal "Another topic", another.title assert_equal "John", another.author_name - assert another.new_record? + assert !another.persisted? end def test_find_or_initialize_from_one_aggregate_attribute_and_one_not new_customer = Customer.find_or_initialize_by_balance_and_name(Money.new(123), "Elizabeth") assert_equal 123, new_customer.balance.amount assert_equal "Elizabeth", new_customer.name - assert new_customer.new_record? + assert !new_customer.persisted? end def test_find_or_initialize_from_one_attribute_and_hash @@ -882,7 +882,7 @@ class FinderTest < ActiveRecord::TestCase assert_equal "38signals", sig38.name assert_equal 17, sig38.firm_id assert_equal 23, sig38.client_of - assert sig38.new_record? + assert !sig38.persisted? end def test_find_or_initialize_from_one_aggregate_attribute_and_hash @@ -891,7 +891,7 @@ class FinderTest < ActiveRecord::TestCase new_customer = Customer.find_or_initialize_by_balance({:balance => balance, :name => name}) assert_equal balance, new_customer.balance assert_equal name, new_customer.name - assert new_customer.new_record? + assert !new_customer.persisted? end def test_find_with_bad_sql diff --git a/activerecord/test/cases/helper.rb b/activerecord/test/cases/helper.rb index f6ef155d66..52f26b71f5 100644 --- a/activerecord/test/cases/helper.rb +++ b/activerecord/test/cases/helper.rb @@ -48,6 +48,10 @@ end ActiveRecord::Base.connection.class.class_eval do IGNORED_SQL = [/^PRAGMA/, /^SELECT currval/, /^SELECT CAST/, /^SELECT @@IDENTITY/, /^SELECT @@ROWCOUNT/, /^SAVEPOINT/, /^ROLLBACK TO SAVEPOINT/, /^RELEASE SAVEPOINT/, /SHOW FIELDS/] + # FIXME: this needs to be refactored so specific database can add their own + # ignored SQL. This ignored SQL is for Oracle. + IGNORED_SQL.concat [/^select .*nextval/i, /^SAVEPOINT/, /^ROLLBACK TO/, /^\s*select .* from ((all|user)_tab_columns|(all|user)_triggers|(all|user)_constraints)/im] + def execute_with_query_record(sql, name = nil, &block) $queries_executed ||= [] $queries_executed << sql unless IGNORED_SQL.any? { |r| sql =~ r } @@ -56,13 +60,13 @@ ActiveRecord::Base.connection.class.class_eval do alias_method_chain :execute, :query_record - def exec_with_query_record(sql, name = nil, binds = [], &block) + def exec_query_with_query_record(sql, name = nil, binds = [], &block) $queries_executed ||= [] $queries_executed << sql unless IGNORED_SQL.any? { |r| sql =~ r } - exec_without_query_record(sql, name, binds, &block) + exec_query_without_query_record(sql, name, binds, &block) end - alias_method_chain :exec, :query_record + alias_method_chain :exec_query, :query_record end ActiveRecord::Base.connection.class.class_eval { diff --git a/activerecord/test/cases/nested_attributes_test.rb b/activerecord/test/cases/nested_attributes_test.rb index 60f89da95e..92af53d56f 100644 --- a/activerecord/test/cases/nested_attributes_test.rb +++ b/activerecord/test/cases/nested_attributes_test.rb @@ -139,6 +139,14 @@ class TestNestedAttributesInGeneral < ActiveRecord::TestCase assert_equal 'gardening', interest.reload.topic end + def test_reject_if_with_blank_nested_attributes_id + # When using a select list to choose an existing 'ship' id, with :include_blank => true + Pirate.accepts_nested_attributes_for :ship, :reject_if => proc {|attributes| attributes[:id].blank? } + + pirate = Pirate.new(:catchphrase => "Stop wastin' me time") + pirate.ship_attributes = { :id => "" } + assert_nothing_raised(ActiveRecord::RecordNotFound) { pirate.save! } + end end class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase @@ -163,7 +171,7 @@ class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase @ship.destroy @pirate.reload.ship_attributes = { :name => 'Davy Jones Gold Dagger' } - assert @pirate.ship.new_record? + assert !@pirate.ship.persisted? assert_equal 'Davy Jones Gold Dagger', @pirate.ship.name end @@ -184,7 +192,7 @@ class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase def test_should_replace_an_existing_record_if_there_is_no_id @pirate.reload.ship_attributes = { :name => 'Davy Jones Gold Dagger' } - assert @pirate.ship.new_record? + assert !@pirate.ship.persisted? assert_equal 'Davy Jones Gold Dagger', @pirate.ship.name assert_equal 'Nights Dirty Lightning', @ship.name end @@ -256,7 +264,7 @@ class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase def test_should_also_work_with_a_HashWithIndifferentAccess @pirate.ship_attributes = HashWithIndifferentAccess.new(:id => @ship.id, :name => 'Davy Jones Gold Dagger') - assert !@pirate.ship.new_record? + assert @pirate.ship.persisted? assert_equal 'Davy Jones Gold Dagger', @pirate.ship.name end @@ -348,7 +356,7 @@ class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase @pirate.destroy @ship.reload.pirate_attributes = { :catchphrase => 'Arr' } - assert @ship.pirate.new_record? + assert !@ship.pirate.persisted? assert_equal 'Arr', @ship.pirate.catchphrase end @@ -369,7 +377,7 @@ class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase def test_should_replace_an_existing_record_if_there_is_no_id @ship.reload.pirate_attributes = { :catchphrase => 'Arr' } - assert @ship.pirate.new_record? + assert !@ship.pirate.persisted? assert_equal 'Arr', @ship.pirate.catchphrase assert_equal 'Aye', @pirate.catchphrase end @@ -458,7 +466,7 @@ class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase @pirate.delete @ship.reload.attributes = { :update_only_pirate_attributes => { :catchphrase => 'Arr' } } - assert @ship.update_only_pirate.new_record? + assert !@ship.update_only_pirate.persisted? end def test_should_update_existing_when_update_only_is_true_and_no_id_is_given @@ -596,10 +604,10 @@ module NestedAttributesOnACollectionAssociationTests association_getter => { 'foo' => { :name => 'Grace OMalley' }, 'bar' => { :name => 'Privateers Greed' }} } - assert @pirate.send(@association_name).first.new_record? + assert !@pirate.send(@association_name).first.persisted? assert_equal 'Grace OMalley', @pirate.send(@association_name).first.name - assert @pirate.send(@association_name).last.new_record? + assert !@pirate.send(@association_name).last.persisted? assert_equal 'Privateers Greed', @pirate.send(@association_name).last.name end diff --git a/activerecord/test/cases/persistence_test.rb b/activerecord/test/cases/persistence_test.rb index ffe6fb95b8..07262f56be 100644 --- a/activerecord/test/cases/persistence_test.rb +++ b/activerecord/test/cases/persistence_test.rb @@ -241,6 +241,15 @@ class PersistencesTest < ActiveRecord::TestCase assert_nothing_raised { minimalistic.save } end + def test_update_sti_type + assert_instance_of Reply, topics(:second) + + topic = topics(:second).becomes(Topic) + assert_instance_of Topic, topic + topic.save! + assert_instance_of Topic, Topic.find(topic.id) + end + def test_delete topic = Topic.find(1) assert_equal topic, topic.delete, 'topic.delete did not return self' diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index f4f3dc4d5a..b44c716db8 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -1,4 +1,5 @@ require "cases/helper" +require 'models/tag' require 'models/tagging' require 'models/post' require 'models/topic' @@ -17,7 +18,7 @@ require 'models/tyre' class RelationTest < ActiveRecord::TestCase fixtures :authors, :topics, :entrants, :developers, :companies, :developers_projects, :accounts, :categories, :categorizations, :posts, :comments, - :taggings, :cars + :tags, :taggings, :cars def test_bind_values relation = Post.scoped @@ -144,6 +145,16 @@ class RelationTest < ActiveRecord::TestCase assert_equal entrants(:first).name, entrants.first.name end + def test_finding_with_complex_order_and_limit + tags = Tag.includes(:taggings).order("REPLACE('abc', taggings.taggable_type, taggings.taggable_type)").limit(1).to_a + assert_equal 1, tags.length + end + + def test_finding_with_complex_order + tags = Tag.includes(:taggings).order("REPLACE('abc', taggings.taggable_type, taggings.taggable_type)").to_a + assert_equal 2, tags.length + end + def test_finding_with_order_limit_and_offset entrants = Entrant.order("id ASC").limit(2).offset(1) @@ -372,7 +383,7 @@ class RelationTest < ActiveRecord::TestCase lifo = authors.find_or_initialize_by_name('Lifo') assert_equal "Lifo", lifo.name - assert lifo.new_record? + assert !lifo.persisted? assert_equal authors(:david), authors.find_or_initialize_by_name(:name => 'David') end @@ -382,7 +393,7 @@ class RelationTest < ActiveRecord::TestCase lifo = authors.find_or_create_by_name('Lifo') assert_equal "Lifo", lifo.name - assert ! lifo.new_record? + assert lifo.persisted? assert_equal authors(:david), authors.find_or_create_by_name(:name => 'David') end @@ -616,10 +627,10 @@ class RelationTest < ActiveRecord::TestCase sparrow = birds.create assert_kind_of Bird, sparrow - assert sparrow.new_record? + assert !sparrow.persisted? hen = birds.where(:name => 'hen').create - assert ! hen.new_record? + assert hen.persisted? assert_equal 'hen', hen.name end @@ -630,7 +641,7 @@ class RelationTest < ActiveRecord::TestCase hen = birds.where(:name => 'hen').create! assert_kind_of Bird, hen - assert ! hen.new_record? + assert hen.persisted? assert_equal 'hen', hen.name end diff --git a/activerecord/test/cases/session_store/sql_bypass.rb b/activerecord/test/cases/session_store/sql_bypass.rb index f0ba166465..7402b2afd6 100644 --- a/activerecord/test/cases/session_store/sql_bypass.rb +++ b/activerecord/test/cases/session_store/sql_bypass.rb @@ -18,9 +18,9 @@ module ActiveRecord assert !Session.table_exists? end - def test_new_record? + def test_persisted? s = SqlBypass.new :data => 'foo', :session_id => 10 - assert s.new_record?, 'this is a new record!' + assert !s.persisted?, 'this is a new record!' end def test_not_loaded? diff --git a/activerecord/test/cases/transactions_test.rb b/activerecord/test/cases/transactions_test.rb index 0fbcef4091..dd9de3510b 100644 --- a/activerecord/test/cases/transactions_test.rb +++ b/activerecord/test/cases/transactions_test.rb @@ -182,7 +182,7 @@ class TransactionTest < ActiveRecord::TestCase :bonus_time => "2005-01-30t15:28:00.00+01:00", :content => "Have a nice day", :approved => false) - new_record_snapshot = new_topic.new_record? + new_record_snapshot = !new_topic.persisted? id_present = new_topic.has_attribute?(Topic.primary_key) id_snapshot = new_topic.id @@ -195,7 +195,7 @@ class TransactionTest < ActiveRecord::TestCase flunk rescue => e assert_equal "Make the transaction rollback", e.message - assert_equal new_record_snapshot, new_topic.new_record?, "The topic should have its old new_record value" + assert_equal new_record_snapshot, !new_topic.persisted?, "The topic should have its old persisted value" assert_equal id_snapshot, new_topic.id, "The topic should have its old id" assert_equal id_present, new_topic.has_attribute?(Topic.primary_key) ensure @@ -370,21 +370,21 @@ class TransactionTest < ActiveRecord::TestCase assert topic_2.save @first.save @second.destroy - assert_equal false, topic_1.new_record? + assert_equal true, topic_1.persisted? assert_not_nil topic_1.id - assert_equal false, topic_2.new_record? + assert_equal true, topic_2.persisted? assert_not_nil topic_2.id - assert_equal false, @first.new_record? + assert_equal true, @first.persisted? assert_not_nil @first.id assert_equal true, @second.destroyed? raise ActiveRecord::Rollback end - assert_equal true, topic_1.new_record? + assert_equal false, topic_1.persisted? assert_nil topic_1.id - assert_equal true, topic_2.new_record? + assert_equal false, topic_2.persisted? assert_nil topic_2.id - assert_equal false, @first.new_record? + assert_equal true, @first.persisted? assert_not_nil @first.id assert_equal false, @second.destroyed? end diff --git a/activerecord/test/connections/native_oracle/connection.rb b/activerecord/test/connections/native_oracle/connection.rb index c942036128..99f921879c 100644 --- a/activerecord/test/connections/native_oracle/connection.rb +++ b/activerecord/test/connections/native_oracle/connection.rb @@ -33,15 +33,3 @@ ActiveRecord::Base.configurations = { ActiveRecord::Base.establish_connection 'arunit' Course.establish_connection 'arunit2' -# for assert_queries test helper -ActiveRecord::Base.connection.class.class_eval do - IGNORED_SELECT_SQL = [/^select .*nextval/i, /^SAVEPOINT/, /^ROLLBACK TO/, /^\s*select .* from ((all|user)_tab_columns|(all|user)_triggers|(all|user)_constraints)/im] - - def select_with_query_record(sql, name = nil) - $queries_executed ||= [] - $queries_executed << sql unless IGNORED_SELECT_SQL.any? { |r| sql =~ r } - select_without_query_record(sql, name) - end - - alias_method_chain :select, :query_record -end diff --git a/activerecord/test/models/eye.rb b/activerecord/test/models/eye.rb index 77f17b578e..dc8ae2b3f6 100644 --- a/activerecord/test/models/eye.rb +++ b/activerecord/test/models/eye.rb @@ -17,7 +17,7 @@ class Eye < ActiveRecord::Base after_save :trace_after_save2 def trace_after_create - (@after_create_callbacks_stack ||= []) << iris.new_record? + (@after_create_callbacks_stack ||= []) << !iris.persisted? end alias trace_after_create2 trace_after_create diff --git a/activerecord/test/models/pirate.rb b/activerecord/test/models/pirate.rb index d89c8cf381..f2c45053e7 100644 --- a/activerecord/test/models/pirate.rb +++ b/activerecord/test/models/pirate.rb @@ -48,7 +48,7 @@ class Pirate < ActiveRecord::Base end def reject_empty_ships_on_create(attributes) - attributes.delete('_reject_me_if_new').present? && new_record? + attributes.delete('_reject_me_if_new').present? && !persisted? end attr_accessor :cancel_save_from_callback diff --git a/activerecord/test/models/subject.rb b/activerecord/test/models/subject.rb index d4b8b91de8..8e28f8b86b 100644 --- a/activerecord/test/models/subject.rb +++ b/activerecord/test/models/subject.rb @@ -8,7 +8,7 @@ class Subject < ActiveRecord::Base protected def set_email_address - if self.new_record? + unless self.persisted? self.author_email_address = 'test@test.com' end end diff --git a/activerecord/test/models/topic.rb b/activerecord/test/models/topic.rb index 82d4b5997f..6496f36f7e 100644 --- a/activerecord/test/models/topic.rb +++ b/activerecord/test/models/topic.rb @@ -89,7 +89,7 @@ class Topic < ActiveRecord::Base end def set_email_address - if self.new_record? + unless self.persisted? self.author_email_address = 'test@test.com' end end diff --git a/activeresource/CHANGELOG b/activeresource/CHANGELOG index 24fe3072e0..386bafd7de 100644 --- a/activeresource/CHANGELOG +++ b/activeresource/CHANGELOG @@ -2,6 +2,10 @@ * No changes +*Rails 3.0.2 (unreleased)* + +* No changes + *Rails 3.0.1 (October 15, 2010)* * No Changes, just a version bump. diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG index 3b6a29f7d6..6e8cce0d27 100644 --- a/activesupport/CHANGELOG +++ b/activesupport/CHANGELOG @@ -4,6 +4,10 @@ * Added before_remove_const callback to ActiveSupport::Dependencies.remove_unloadable_constants! [Andrew White] +*Rails 3.0.2 (unreleased)* + +* Added before_remove_const callback to ActiveSupport::Dependencies.remove_unloadable_constants! [Andrew White] + *Rails 3.0.1 (October 15, 2010)* * No Changes, just a version bump. diff --git a/activesupport/lib/active_support/cache/file_store.rb b/activesupport/lib/active_support/cache/file_store.rb index 84f6f29572..18182bbb40 100644 --- a/activesupport/lib/active_support/cache/file_store.rb +++ b/activesupport/lib/active_support/cache/file_store.rb @@ -1,5 +1,6 @@ require 'active_support/core_ext/file/atomic' require 'active_support/core_ext/string/conversions' +require 'rack/utils' module ActiveSupport module Cache @@ -11,8 +12,6 @@ module ActiveSupport attr_reader :cache_path DIR_FORMATTER = "%03X" - ESCAPE_FILENAME_CHARS = /[^a-z0-9_.-]/i - UNESCAPE_FILENAME_CHARS = /%[0-9A-F]{2}/ def initialize(cache_path, options = nil) super(options) @@ -136,7 +135,7 @@ module ActiveSupport # Translate a key into a file path. def key_file_path(key) - fname = key.to_s.gsub(ESCAPE_FILENAME_CHARS){|match| "%#{match.ord.to_s(16).upcase}"} + fname = Rack::Utils.escape(key) hash = Zlib.adler32(fname) hash, dir_1 = hash.divmod(0x1000) dir_2 = hash.modulo(0x1000) @@ -156,7 +155,7 @@ module ActiveSupport # Translate a file path into a key. def file_path_key(path) fname = path[cache_path.size, path.size].split(File::SEPARATOR, 4).last - fname.gsub(UNESCAPE_FILENAME_CHARS){|match| $1.ord.to_s(16)} + Rack::Utils.unescape(fname) end # Delete empty directories in the cache. diff --git a/activesupport/lib/active_support/core_ext/cgi.rb b/activesupport/lib/active_support/core_ext/cgi.rb deleted file mode 100644 index 7279a3d4da..0000000000 --- a/activesupport/lib/active_support/core_ext/cgi.rb +++ /dev/null @@ -1 +0,0 @@ -require 'active_support/core_ext/cgi/escape_skipping_slashes' diff --git a/activesupport/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb b/activesupport/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb deleted file mode 100644 index d3c3575748..0000000000 --- a/activesupport/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb +++ /dev/null @@ -1,19 +0,0 @@ -require 'cgi' - -class CGI #:nodoc: - if RUBY_VERSION >= '1.9' - def self.escape_skipping_slashes(str) - str = str.join('/') if str.respond_to? :join - str.gsub(/([^ \/a-zA-Z0-9_.-])/n) do - "%#{$1.unpack('H2' * $1.bytesize).join('%').upcase}" - end.tr(' ', '+') - end - else - def self.escape_skipping_slashes(str) - str = str.join('/') if str.respond_to? :join - str.gsub(/([^ \/a-zA-Z0-9_.-])/n) do - "%#{$1.unpack('H2').first.upcase}" - end.tr(' ', '+') - end - end -end diff --git a/activesupport/lib/active_support/core_ext/object/instance_variables.rb b/activesupport/lib/active_support/core_ext/object/instance_variables.rb index 77a3cfc21d..eda9694614 100644 --- a/activesupport/lib/active_support/core_ext/object/instance_variables.rb +++ b/activesupport/lib/active_support/core_ext/object/instance_variables.rb @@ -30,35 +30,4 @@ class Object else alias_method :instance_variable_names, :instance_variables end - - # Copies the instance variables of +object+ into +self+. - # - # Instance variable names in the +exclude+ array are ignored. If +object+ - # responds to <tt>protected_instance_variables</tt> the ones returned are - # also ignored. For example, Rails controllers implement that method. - # - # In both cases strings and symbols are understood, and they have to include - # the at sign. - # - # class C - # def initialize(x, y, z) - # @x, @y, @z = x, y, z - # end - # - # def protected_instance_variables - # %w(@z) - # end - # end - # - # a = C.new(0, 1, 2) - # b = C.new(3, 4, 5) - # - # a.copy_instance_variables_from(b, [:@y]) - # # a is now: @x = 3, @y = 1, @z = 2 - def copy_instance_variables_from(object, exclude = []) #:nodoc: - exclude += object.protected_instance_variables if object.respond_to? :protected_instance_variables - - vars = object.instance_variables.map(&:to_s) - exclude.map(&:to_s) - vars.each { |name| instance_variable_set(name, object.instance_variable_get(name)) } - end end diff --git a/activesupport/lib/active_support/hash_with_indifferent_access.rb b/activesupport/lib/active_support/hash_with_indifferent_access.rb index c406dd3c2e..06dd18966e 100644 --- a/activesupport/lib/active_support/hash_with_indifferent_access.rb +++ b/activesupport/lib/active_support/hash_with_indifferent_access.rb @@ -28,7 +28,7 @@ module ActiveSupport end def self.new_from_hash_copying_default(hash) - ActiveSupport::HashWithIndifferentAccess.new(hash).tap do |new_hash| + new(hash).tap do |new_hash| new_hash.default = hash.default end end @@ -97,7 +97,9 @@ module ActiveSupport # Returns an exact copy of the hash. def dup - HashWithIndifferentAccess.new(self) + self.class.new(self).tap do |new_hash| + new_hash.default = default + end end # Merges the instantized and the specified hashes together, giving precedence to the values from the second hash diff --git a/activesupport/lib/active_support/ordered_hash.rb b/activesupport/lib/active_support/ordered_hash.rb index 7f148dc853..8e157d3af4 100644 --- a/activesupport/lib/active_support/ordered_hash.rb +++ b/activesupport/lib/active_support/ordered_hash.rb @@ -137,6 +137,8 @@ module ActiveSupport alias_method :each_pair, :each + alias_method :select, :find_all + def clear super @keys.clear diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb index 93f5d5a0cc..6a7da8266c 100644 --- a/activesupport/lib/active_support/time_with_zone.rb +++ b/activesupport/lib/active_support/time_with_zone.rb @@ -73,7 +73,7 @@ module ActiveSupport # Returns a <tt>Time.local()</tt> instance of the simultaneous time in your system's <tt>ENV['TZ']</tt> zone def localtime - utc.getlocal + utc.respond_to?(:getlocal) ? utc.getlocal : utc.to_time.getlocal end alias_method :getlocal, :localtime diff --git a/activesupport/lib/active_support/xml_mini.rb b/activesupport/lib/active_support/xml_mini.rb index b6a8cf3caf..cddfcddb57 100644 --- a/activesupport/lib/active_support/xml_mini.rb +++ b/activesupport/lib/active_support/xml_mini.rb @@ -126,9 +126,11 @@ module ActiveSupport end def rename_key(key, options = {}) - camelize = options.has_key?(:camelize) && options[:camelize] + camelize = options[:camelize] dasherize = !options.has_key?(:dasherize) || options[:dasherize] - key = key.camelize if camelize + if camelize + key = true == camelize ? key.camelize : key.camelize(camelize) + end key = _dasherize(key) if dasherize key end diff --git a/activesupport/test/caching_test.rb b/activesupport/test/caching_test.rb index 28ef695a4b..579d5dad24 100644 --- a/activesupport/test/caching_test.rb +++ b/activesupport/test/caching_test.rb @@ -356,9 +356,13 @@ module CacheDeleteMatchedBehavior def test_delete_matched @cache.write("foo", "bar") @cache.write("fu", "baz") + @cache.write("foo/bar", "baz") + @cache.write("fu/baz", "bar") @cache.delete_matched(/oo/) assert_equal false, @cache.exist?("foo") assert_equal true, @cache.exist?("fu") + assert_equal false, @cache.exist?("foo/bar") + assert_equal true, @cache.exist?("fu/baz") end end @@ -509,6 +513,11 @@ class FileStoreTest < ActiveSupport::TestCase assert_nil old_cache.read('foo') end end + + def test_key_transformation + key = @cache.send(:key_file_path, "views/index?id=1") + assert_equal "views/index?id=1", @cache.send(:file_path_key, key) + end end class MemoryStoreTest < ActiveSupport::TestCase diff --git a/activesupport/test/core_ext/cgi_ext_test.rb b/activesupport/test/core_ext/cgi_ext_test.rb deleted file mode 100644 index c80362e382..0000000000 --- a/activesupport/test/core_ext/cgi_ext_test.rb +++ /dev/null @@ -1,15 +0,0 @@ -require 'abstract_unit' -require 'active_support/core_ext/cgi' - -class EscapeSkippingSlashesTest < Test::Unit::TestCase - def test_array - assert_equal 'hello/world', CGI.escape_skipping_slashes(%w(hello world)) - assert_equal 'hello+world/how/are/you', CGI.escape_skipping_slashes(['hello world', 'how', 'are', 'you']) - end - - def test_typical - assert_equal 'hi', CGI.escape_skipping_slashes('hi') - assert_equal 'hi/world', CGI.escape_skipping_slashes('hi/world') - assert_equal 'hi/world+you+funky+thing', CGI.escape_skipping_slashes('hi/world you funky thing') - end -end diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb index bfcfddad47..d7b77e43bd 100644 --- a/activesupport/test/core_ext/hash_ext_test.rb +++ b/activesupport/test/core_ext/hash_ext_test.rb @@ -6,6 +6,9 @@ require 'active_support/ordered_hash' require 'active_support/core_ext/object/conversions' class HashExtTest < Test::Unit::TestCase + class IndifferentHash < HashWithIndifferentAccess + end + def setup @strings = { 'a' => 1, 'b' => 2 } @symbols = { :a => 1, :b => 2 } @@ -267,7 +270,6 @@ class HashExtTest < Test::Unit::TestCase assert_equal 1, h['first'] end - def test_indifferent_subhashes h = {'user' => {'id' => 5}}.with_indifferent_access ['user', :user].each {|user| [:id, 'id'].each {|id| assert_equal 5, h[user][id], "h[#{user.inspect}][#{id.inspect}] should be 5"}} @@ -276,6 +278,17 @@ class HashExtTest < Test::Unit::TestCase ['user', :user].each {|user| [:id, 'id'].each {|id| assert_equal 5, h[user][id], "h[#{user.inspect}][#{id.inspect}] should be 5"}} end + def test_indifferent_duplication + # Should preserve default value + h = HashWithIndifferentAccess.new + h.default = '1234' + assert_equal h.default, h.dup.default + + # Should preserve class for subclasses + h = IndifferentHash.new + assert_equal h.class, h.dup.class + end + def test_assert_valid_keys assert_nothing_raised do { :failure => "stuff", :funny => "business" }.assert_valid_keys([ :failure, :funny ]) @@ -501,7 +514,7 @@ class HashExtToParamTests < Test::Unit::TestCase def test_to_param_hash_escapes_its_keys_and_values assert_equal 'param+1=A+string+with+%2F+characters+%26+that+should+be+%3F+escaped', { 'param 1' => 'A string with / characters & that should be ? escaped' }.to_param end - + def test_to_param_orders_by_key_in_ascending_order assert_equal 'a=2&b=1&c=0', ActiveSupport::OrderedHash[*%w(b 1 c 0 a 2)].to_param end @@ -540,6 +553,13 @@ class HashToXmlTest < Test::Unit::TestCase assert xml.include?(%(<Name>David</Name>)) end + def test_one_level_camelize_lower + xml = { :name => "David", :street_name => "Paulina" }.to_xml(@xml_options.merge(:camelize => :lower)) + assert_equal "<person>", xml.first(8) + assert xml.include?(%(<streetName>Paulina</streetName>)) + assert xml.include?(%(<name>David</name>)) + end + def test_one_level_with_types xml = { :name => "David", :street => "Paulina", :age => 26, :age_in_millis => 820497600000, :moved_on => Date.new(2005, 11, 15), :resident => :yes }.to_xml(@xml_options) assert_equal "<person>", xml.first(8) diff --git a/activesupport/test/core_ext/object_and_class_ext_test.rb b/activesupport/test/core_ext/object_and_class_ext_test.rb index 3ccf18f473..64f339ed90 100644 --- a/activesupport/test/core_ext/object_and_class_ext_test.rb +++ b/activesupport/test/core_ext/object_and_class_ext_test.rb @@ -82,37 +82,6 @@ class ObjectInstanceVariableTest < Test::Unit::TestCase assert_equal %w(@bar @baz), @source.instance_variable_names.sort end - def test_copy_instance_variables_from_without_explicit_excludes - assert_equal [], @dest.instance_variables - @dest.copy_instance_variables_from(@source) - - assert_equal %w(@bar @baz), @dest.instance_variables.sort.map(&:to_s) - %w(@bar @baz).each do |name| - assert_equal @source.instance_variable_get(name).object_id, - @dest.instance_variable_get(name).object_id - end - end - - def test_copy_instance_variables_from_with_explicit_excludes - @dest.copy_instance_variables_from(@source, ['@baz']) - assert !@dest.instance_variable_defined?('@baz') - assert_equal 'bar', @dest.instance_variable_get('@bar') - end - - def test_copy_instance_variables_automatically_excludes_protected_instance_variables - @source.instance_variable_set(:@quux, 'quux') - class << @source - def protected_instance_variables - ['@bar', :@quux] - end - end - - @dest.copy_instance_variables_from(@source) - assert !@dest.instance_variable_defined?('@bar') - assert !@dest.instance_variable_defined?('@quux') - assert_equal 'baz', @dest.instance_variable_get('@baz') - end - def test_instance_values object = Object.new object.instance_variable_set :@a, 1 diff --git a/activesupport/test/core_ext/time_with_zone_test.rb b/activesupport/test/core_ext/time_with_zone_test.rb index 0bb2c4a39e..5579c27215 100644 --- a/activesupport/test/core_ext/time_with_zone_test.rb +++ b/activesupport/test/core_ext/time_with_zone_test.rb @@ -36,6 +36,10 @@ class TimeWithZoneTest < Test::Unit::TestCase assert_equal @twz.object_id, @twz.in_time_zone(ActiveSupport::TimeZone['Eastern Time (US & Canada)']).object_id end + def test_localtime + assert_equal @twz.localtime, @twz.utc.getlocal + end + def test_utc? assert_equal false, @twz.utc? assert_equal true, ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['UTC']).utc? @@ -763,6 +767,13 @@ class TimeWithZoneMethodsForTimeAndDateTimeTest < Test::Unit::TestCase end end + def test_localtime + Time.zone_default = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + assert_equal @dt.in_time_zone.localtime, @dt.in_time_zone.utc.to_time.getlocal + ensure + Time.zone_default = nil + end + def test_use_zone Time.zone = 'Alaska' Time.use_zone 'Hawaii' do diff --git a/activesupport/test/ordered_hash_test.rb b/activesupport/test/ordered_hash_test.rb index 50778b5864..72088854fc 100644 --- a/activesupport/test/ordered_hash_test.rb +++ b/activesupport/test/ordered_hash_test.rb @@ -109,6 +109,14 @@ class OrderedHashTest < Test::Unit::TestCase assert_equal @keys, keys end + def test_find_all + assert_equal @keys, @ordered_hash.find_all { true }.map(&:first) + end + + def test_select + assert_equal @keys, @ordered_hash.select { true }.map(&:first) + end + def test_delete_if copy = @ordered_hash.dup copy.delete('pink') diff --git a/activesupport/test/test_xml_mini.rb b/activesupport/test/test_xml_mini.rb index 585eb15c6e..309fa234bf 100644 --- a/activesupport/test/test_xml_mini.rb +++ b/activesupport/test/test_xml_mini.rb @@ -14,14 +14,26 @@ class XmlMiniTest < Test::Unit::TestCase assert_equal "my_key", ActiveSupport::XmlMini.rename_key("my_key", :dasherize => false) end - def test_rename_key_camelizes_with_camelize_true - assert_equal "MyKey", ActiveSupport::XmlMini.rename_key("my_key", :camelize => true) + def test_rename_key_camelizes_with_camelize_false + assert_equal "my_key", ActiveSupport::XmlMini.rename_key("my_key", :camelize => false) + end + + def test_rename_key_camelizes_with_camelize_nil + assert_equal "my_key", ActiveSupport::XmlMini.rename_key("my_key", :camelize => nil) end def test_rename_key_camelizes_with_camelize_true assert_equal "MyKey", ActiveSupport::XmlMini.rename_key("my_key", :camelize => true) end + def test_rename_key_lower_camelizes_with_camelize_lower + assert_equal "myKey", ActiveSupport::XmlMini.rename_key("my_key", :camelize => :lower) + end + + def test_rename_key_lower_camelizes_with_camelize_upper + assert_equal "MyKey", ActiveSupport::XmlMini.rename_key("my_key", :camelize => :upper) + end + def test_rename_key_does_not_dasherize_leading_underscores assert_equal "_id", ActiveSupport::XmlMini.rename_key("_id") end diff --git a/railties/guides/source/active_support_core_extensions.textile b/railties/guides/source/active_support_core_extensions.textile index 9b1d264d2c..8c11b2a11a 100644 --- a/railties/guides/source/active_support_core_extensions.textile +++ b/railties/guides/source/active_support_core_extensions.textile @@ -395,39 +395,6 @@ C.new(0, 1).instance_values # => {"x" => 0, "y" => 1} NOTE: Defined in +active_support/core_ext/object/instance_variables.rb+. -h5. +copy_instance_variables_from(object, exclude = [])+ - -Copies the instance variables of +object+ into +self+. - -Instance variable names in the +exclude+ array are ignored. If +object+ -responds to +protected_instance_variables+ the ones returned are -also ignored. For example, Rails controllers implement that method. - -In both arrays strings and symbols are understood, and they have to include -the at sign. - -<ruby> -class C - def initialize(x, y, z) - @x, @y, @z = x, y, z - end - - def protected_instance_variables - %w(@z) - end -end - -a = C.new(0, 1, 2) -b = C.new(3, 4, 5) - -a.copy_instance_variables_from(b, [:@y]) -# a is now: @x = 3, @y = 1, @z = 2 -</ruby> - -In the example +object+ and +self+ are of the same type, but they don't need to. - -NOTE: Defined in +active_support/core_ext/object/instance_variables.rb+. - h4. Silencing Warnings, Streams, and Exceptions The methods +silence_warnings+ and +enable_warnings+ change the value of +$VERBOSE+ accordingly for the duration of their block, and reset it afterwards: diff --git a/railties/guides/source/api_documentation_guidelines.textile b/railties/guides/source/api_documentation_guidelines.textile index 900b3fb5d5..e3ccd6396c 100644 --- a/railties/guides/source/api_documentation_guidelines.textile +++ b/railties/guides/source/api_documentation_guidelines.textile @@ -116,14 +116,12 @@ Use fixed-width fonts for: * file names <ruby> -# Copies the instance variables of +object+ into +self+. -# -# Instance variable names in the +exclude+ array are ignored. If +object+ -# responds to <tt>protected_instance_variables</tt> the ones returned are -# also ignored. For example, Rails controllers implement that method. -# ... -def copy_instance_variables_from(object, exclude = []) - ... +class Array + # Calls <tt>to_param</tt> on all its elements and joins the result with + # slashes. This is used by <tt>url_for</tt> in Action Pack. + def to_param + collect { |e| e.to_param }.join '/' + end end </ruby> diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index d84373cddf..182068071d 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -35,7 +35,6 @@ module Rails # class Application < Engine autoload :Bootstrap, 'rails/application/bootstrap' - autoload :Configurable, 'rails/application/configurable' autoload :Configuration, 'rails/application/configuration' autoload :Finisher, 'rails/application/finisher' autoload :Railties, 'rails/application/railties' diff --git a/railties/lib/rails/cli.rb b/railties/lib/rails/cli.rb index c8d70d8ffa..2b32f7edf1 100644 --- a/railties/lib/rails/cli.rb +++ b/railties/lib/rails/cli.rb @@ -5,9 +5,6 @@ require 'rails/script_rails_loader' # the rest of this script is not run. Rails::ScriptRailsLoader.exec_script_rails! -railties_path = File.expand_path('../../lib', __FILE__) -$:.unshift(railties_path) if File.directory?(railties_path) && !$:.include?(railties_path) - require 'rails/ruby_version_check' Signal.trap("INT") { puts; exit } diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index 72bfe207d7..466a31c2a0 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -324,8 +324,8 @@ module Rails # MyEngine::Engine.load_seed # class Engine < Railtie - autoload :Configurable, "rails/engine/configurable" autoload :Configuration, "rails/engine/configuration" + autoload :Railties, "rails/engine/railties" class << self attr_accessor :called_from, :isolated diff --git a/railties/lib/rails/generators/rails/app/templates/config/application.rb b/railties/lib/rails/generators/rails/app/templates/config/application.rb index 00a23a7b89..6e515756fe 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/application.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/application.rb @@ -48,6 +48,10 @@ module <%= app_const_base %> # config.action_view.javascript_expansions[:defaults] = %w(jquery rails) <% end -%> +<% if options[:skip_test_unit] -%> + config.generators.test_framework = false +<% end -%> + # Configure the default encoding used in templates for Ruby 1.9. config.encoding = "utf-8" diff --git a/railties/lib/rails/generators/resource_helpers.rb b/railties/lib/rails/generators/resource_helpers.rb index c9e70468a1..d6ccfc496a 100644 --- a/railties/lib/rails/generators/resource_helpers.rb +++ b/railties/lib/rails/generators/resource_helpers.rb @@ -17,7 +17,7 @@ module Rails def initialize(*args) #:nodoc: super - if name == name.pluralize && !options[:force_plural] + if name == name.pluralize && name.singularize != name.pluralize && !options[:force_plural] unless ResourceHelpers.skip_warn say "Plural version of the model detected, using singularized version. Override with --force-plural." ResourceHelpers.skip_warn = true diff --git a/railties/lib/rails/info.rb b/railties/lib/rails/info.rb index 6cbd1f21c0..d05e031f56 100644 --- a/railties/lib/rails/info.rb +++ b/railties/lib/rails/info.rb @@ -1,5 +1,4 @@ require "cgi" -require "active_support/core_ext/cgi" module Rails module Info diff --git a/railties/railties.gemspec b/railties/railties.gemspec index d26c1bcdbc..c3793d3ac3 100644 --- a/railties/railties.gemspec +++ b/railties/railties.gemspec @@ -20,7 +20,7 @@ Gem::Specification.new do |s| s.has_rdoc = false s.add_dependency('rake', '>= 0.8.7') - s.add_dependency('thor', '~> 0.14.3') + s.add_dependency('thor', '~> 0.14.4') s.add_dependency('activesupport', version) s.add_dependency('actionpack', version) end diff --git a/railties/test/application/rake_test.rb b/railties/test/application/rake_test.rb index 8e527236ea..719550f9d9 100644 --- a/railties/test/application/rake_test.rb +++ b/railties/test/application/rake_test.rb @@ -38,5 +38,14 @@ module ApplicationTests assert_match "Code LOC: 5 Test LOC: 0 Code to Test Ratio: 1:0.0", Dir.chdir(app_path){ `rake stats` } end + + def test_rake_routes_output_strips_anchors_from_http_verbs + app_file "config/routes.rb", <<-RUBY + AppTemplate::Application.routes.draw do + get '/cart', :to => 'cart#show' + end + RUBY + assert_match 'cart GET /cart(.:format)', Dir.chdir(app_path){ `rake routes` } + end end end diff --git a/railties/test/generators/resource_generator_test.rb b/railties/test/generators/resource_generator_test.rb index 55d5bd6f83..71b3619351 100644 --- a/railties/test/generators/resource_generator_test.rb +++ b/railties/test/generators/resource_generator_test.rb @@ -73,6 +73,11 @@ class ResourceGeneratorTest < Rails::Generators::TestCase assert_no_match /Plural version of the model detected/, content end + def test_mass_nouns_do_not_throw_warnings + content = run_generator ["sheep".freeze] + assert_no_match /Plural version of the model detected/, content + end + def test_route_is_removed_on_revoke run_generator run_generator ["account"], :behavior => :revoke |