From a982443ae5bd12535405dbdb40f27df2d612256e Mon Sep 17 00:00:00 2001 From: Daniel Schierbeck Date: Sat, 9 Jul 2011 14:24:28 +0200 Subject: [PATCH 001/345] Make #extract_schema_and_table an instance method in Utils Also, move the utils test into its own test case. --- .../connection_adapters/postgresql_adapter.rb | 4 +++- .../cases/adapters/postgresql/schema_test.rb | 15 --------------- .../cases/adapters/postgresql/utils_test.rb | 18 ++++++++++++++++++ 3 files changed, 21 insertions(+), 16 deletions(-) create mode 100644 activerecord/test/cases/adapters/postgresql/utils_test.rb diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index a84f73c73f..df753d087c 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -948,6 +948,8 @@ module ActiveRecord end module Utils + extend self + # Returns an array of [schema_name, table_name] extracted from +name+. # +schema_name+ is nil if not specified in +name+. # +schema_name+ and +table_name+ exclude surrounding quotes (regardless of whether provided in +name+) @@ -958,7 +960,7 @@ module ActiveRecord # * schema_name.table_name # * schema_name."table.name" # * "schema.name"."table name" - def self.extract_schema_and_table(name) + def extract_schema_and_table(name) table, schema = name.scan(/[^".\s]+|"[^"]*"/)[0..1].collect{|m| m.gsub(/(^"|"$)/,'') }.reverse [schema, table] end diff --git a/activerecord/test/cases/adapters/postgresql/schema_test.rb b/activerecord/test/cases/adapters/postgresql/schema_test.rb index 3a7f1badf0..4c6d865d59 100644 --- a/activerecord/test/cases/adapters/postgresql/schema_test.rb +++ b/activerecord/test/cases/adapters/postgresql/schema_test.rb @@ -219,21 +219,6 @@ class SchemaTest < ActiveRecord::TestCase end end - def test_extract_schema_and_table - { - %(table_name) => [nil,'table_name'], - %("table.name") => [nil,'table.name'], - %(schema.table_name) => %w{schema table_name}, - %("schema".table_name) => %w{schema table_name}, - %(schema."table_name") => %w{schema table_name}, - %("schema"."table_name") => %w{schema table_name}, - %("even spaces".table) => ['even spaces','table'], - %(schema."table.name") => ['schema', 'table.name'] - }.each do |given, expect| - assert_equal expect, ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::Utils.extract_schema_and_table(given) - end - end - def test_current_schema { %('$user',public) => 'public', diff --git a/activerecord/test/cases/adapters/postgresql/utils_test.rb b/activerecord/test/cases/adapters/postgresql/utils_test.rb new file mode 100644 index 0000000000..5f08f79171 --- /dev/null +++ b/activerecord/test/cases/adapters/postgresql/utils_test.rb @@ -0,0 +1,18 @@ +class PostgreSQLUtilsTest < ActiveSupport::TestCase + include ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::Utils + + def test_extract_schema_and_table + { + %(table_name) => [nil,'table_name'], + %("table.name") => [nil,'table.name'], + %(schema.table_name) => %w{schema table_name}, + %("schema".table_name) => %w{schema table_name}, + %(schema."table_name") => %w{schema table_name}, + %("schema"."table_name") => %w{schema table_name}, + %("even spaces".table) => ['even spaces','table'], + %(schema."table.name") => ['schema', 'table.name'] + }.each do |given, expect| + assert_equal expect, extract_schema_and_table(given) + end + end +end From c6d83ab741456303784305b0a457512e4682f97f Mon Sep 17 00:00:00 2001 From: Dan Gebhardt Date: Fri, 15 Jul 2011 18:22:31 -0400 Subject: [PATCH 002/345] fixed problem in which options[:html][:remote] would be overridden in form_for() - fixes #2094 --- actionpack/lib/action_view/helpers/form_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index 3a30263b49..89bd1365cd 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -365,7 +365,7 @@ module ActionView apply_form_for_options!(record, options) end - options[:html][:remote] = options.delete(:remote) + options[:html][:remote] = options.delete(:remote) if options.has_key?(:remote) options[:html][:method] = options.delete(:method) if options.has_key?(:method) options[:html][:authenticity_token] = options.delete(:authenticity_token) From 455e3212846586eb07cedae2946887583f874204 Mon Sep 17 00:00:00 2001 From: Dan Gebhardt Date: Sat, 16 Jul 2011 08:22:43 -0400 Subject: [PATCH 003/345] added test case for fix to issue #2094 --- actionpack/test/template/form_helper_test.rb | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb index cc3d2cddf7..aca2dc9e4d 100644 --- a/actionpack/test/template/form_helper_test.rb +++ b/actionpack/test/template/form_helper_test.rb @@ -791,6 +791,23 @@ class FormHelperTest < ActionView::TestCase assert_dom_equal expected, output_buffer end + def test_form_for_with_remote_in_html + form_for(@post, :url => '/', :html => { :remote => true, :id => 'create-post', :method => :put }) do |f| + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) + end + + expected = whole_form("/", "create-post", "edit_post", :method => "put", :remote => true) do + "" + + "" + + "" + + "" + end + + assert_dom_equal expected, output_buffer + end + def test_form_for_with_remote_without_html @post.persisted = false form_for(@post, :remote => true) do |f| From b9c91426032e110aa60fca563ab513621096289a Mon Sep 17 00:00:00 2001 From: Erik Michaels-Ober Date: Mon, 25 Jul 2011 11:37:25 -0700 Subject: [PATCH 004/345] Allow a route to have :format => true When format is true, it is mandatory (as opposed to :format => false). This is currently not possible with resource routes, which automatically make format optional by default. --- actionpack/lib/action_dispatch/routing/mapper.rb | 2 ++ actionpack/test/dispatch/mapper_test.rb | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 1331f67a78..003bc1dc2c 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -119,6 +119,8 @@ module ActionDispatch path elsif path.include?(":format") || path.end_with?('/') path + elsif @options[:format] == true + "#{path}.:format" else "#{path}(.:format)" end diff --git a/actionpack/test/dispatch/mapper_test.rb b/actionpack/test/dispatch/mapper_test.rb index b6c08ffc33..81f0efb76e 100644 --- a/actionpack/test/dispatch/mapper_test.rb +++ b/actionpack/test/dispatch/mapper_test.rb @@ -83,6 +83,13 @@ module ActionDispatch assert_equal '/*path', fakeset.conditions.first[:path_info] assert_nil fakeset.requirements.first[:path] end + + def test_map_wildcard_with_format_true + fakeset = FakeSet.new + mapper = Mapper.new fakeset + mapper.match '/*path', :to => 'pages#show', :format => true + assert_equal '/*path.:format', fakeset.conditions.first[:path_info] + end end end end From bf812074fd55e7dcfa426d6c9bfd4d8d68922194 Mon Sep 17 00:00:00 2001 From: Grant Hutchins & Peter Jaros Date: Fri, 8 Jul 2011 17:54:15 -0400 Subject: [PATCH 005/345] Let ActiveModel instances define partial paths. Deprecate ActiveModel::Name#partial_path. Now you should call #to_path directly on ActiveModel instances. --- .../lib/action_view/helpers/form_helper.rb | 8 +++- .../action_view/renderer/partial_renderer.rb | 43 ++++++++++--------- actionpack/test/template/form_helper_test.rb | 11 +++++ actionpack/test/template/render_test.rb | 30 +++++++++++++ activemodel/lib/active_model/conversion.rb | 26 ++++++++++- activemodel/lib/active_model/lint.rb | 15 +++++-- activemodel/lib/active_model/naming.rb | 3 ++ activemodel/test/cases/conversion_test.rb | 9 +++- activemodel/test/cases/naming_test.rb | 16 +++++-- activemodel/test/models/helicopter.rb | 3 ++ 10 files changed, 131 insertions(+), 33 deletions(-) create mode 100644 activemodel/test/models/helicopter.rb diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index 974c963d44..c835aa6f15 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -1227,8 +1227,12 @@ module ActionView parent_builder.multipart = multipart if parent_builder end - def self.model_name - @model_name ||= Struct.new(:partial_path).new(name.demodulize.underscore.sub!(/_builder$/, '')) + def self.to_path + @_to_path ||= name.demodulize.underscore.sub!(/_builder$/, '') + end + + def to_path + self.class.to_path end def to_model diff --git a/actionpack/lib/action_view/renderer/partial_renderer.rb b/actionpack/lib/action_view/renderer/partial_renderer.rb index c0ac332c4e..fc8a6b3107 100644 --- a/actionpack/lib/action_view/renderer/partial_renderer.rb +++ b/actionpack/lib/action_view/renderer/partial_renderer.rb @@ -206,13 +206,6 @@ module ActionView # <%- end -%> # <% end %> class PartialRenderer < AbstractRenderer #:nodoc: - PARTIAL_NAMES = Hash.new {|h,k| h[k] = {} } - - def initialize(*) - super - @partial_names = PARTIAL_NAMES[@lookup_context.prefixes.first] - end - def render(context, options, block) setup(context, options, block) @@ -359,28 +352,36 @@ module ActionView segments end + PARTIAL_PATHS = {} + def partial_path(object = @object) - @partial_names[object.class.name] ||= begin - object = object.to_model if object.respond_to?(:to_model) - object.class.model_name.partial_path.dup.tap do |partial| - path = @lookup_context.prefixes.first - merge_path_into_partial(path, partial) - end + object = object.to_model if object.respond_to?(:to_model) + + path = if object.respond_to?(:to_path) + object.to_path + else + ActiveSupport::Deprecation.warn "ActiveModel-compatible objects whose classes return a #model_name that responds to #partial_path are deprecated. Please respond to #to_path directly instead." + object.class.model_name.partial_path + end + + prefix = @lookup_context.prefixes.first + PARTIAL_PATHS[ [path, prefix] ] ||= path.dup.tap do |object_path| + merge_prefix_into_object_path(prefix, object_path) end end - def merge_path_into_partial(path, partial) - if path.include?(?/) && partial.include?(?/) + def merge_prefix_into_object_path(prefix, object_path) + if prefix.include?(?/) && object_path.include?(?/) overlap = [] - path_array = File.dirname(path).split('/') - partial_array = partial.split('/')[0..-3] # skip model dir & partial + prefix_array = File.dirname(prefix).split('/') + object_path_array = object_path.split('/')[0..-3] # skip model dir & partial - path_array.each_with_index do |dir, index| - overlap << dir if dir == partial_array[index] + prefix_array.each_with_index do |dir, index| + overlap << dir if dir == object_path_array[index] end - partial.gsub!(/^#{overlap.join('/')}\//,'') - partial.insert(0, "#{File.dirname(path)}/") + object_path.gsub!(/^#{overlap.join('/')}\//,'') + object_path.insert(0, "#{File.dirname(prefix)}/") end end diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb index cc3d2cddf7..d80d48ac55 100644 --- a/actionpack/test/template/form_helper_test.rb +++ b/actionpack/test/template/form_helper_test.rb @@ -1874,6 +1874,17 @@ class FormHelperTest < ActionView::TestCase assert_equal LabelledFormBuilder, klass end + def test_form_for_with_labelled_builder_path + path = nil + + form_for(@post, :builder => LabelledFormBuilder) do |f| + path = f.to_path + '' + end + + assert_equal 'labelled_form', path + end + class LabelledFormBuilderSubclass < LabelledFormBuilder; end def test_form_for_with_labelled_builder_with_nested_fields_for_with_custom_builder diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb index 68b2ed45d1..0b91e55091 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionpack/test/template/render_test.rb @@ -201,6 +201,36 @@ module RenderTestCases @controller_view.render(customers, :greeting => "Hello") end + class CustomerWithDeprecatedPartialPath + attr_reader :name + + def self.model_name + Struct.new(:partial_path).new("customers/customer") + end + + def initialize(name) + @name = name + end + end + + def test_render_partial_using_object_with_deprecated_partial_path + assert_deprecated(/#model_name.*#partial_path.*#to_path/) do + assert_equal "Hello: nertzy", + @controller_view.render(CustomerWithDeprecatedPartialPath.new("nertzy"), :greeting => "Hello") + end + end + + def test_render_partial_using_collection_with_deprecated_partial_path + assert_deprecated(/#model_name.*#partial_path.*#to_path/) do + customers = [ + CustomerWithDeprecatedPartialPath.new("nertzy"), + CustomerWithDeprecatedPartialPath.new("peeja") + ] + assert_equal "Hello: nertzyHello: peeja", + @controller_view.render(customers, :greeting => "Hello") + end + end + # TODO: The reason for this test is unclear, improve documentation def test_render_partial_and_fallback_to_layout assert_equal "Before (Josh)\n\nAfter", @view.render(:partial => "test/layout_for_partial", :locals => { :name => "Josh" }) diff --git a/activemodel/lib/active_model/conversion.rb b/activemodel/lib/active_model/conversion.rb index 1405b1bfe3..dca1c1aa44 100644 --- a/activemodel/lib/active_model/conversion.rb +++ b/activemodel/lib/active_model/conversion.rb @@ -1,9 +1,12 @@ +require 'active_support/concern' +require 'active_support/inflector' + module ActiveModel # == Active Model Conversions # - # Handles default conversions: to_model, to_key and to_param. + # Handles default conversions: to_model, to_key, to_param, and to_path. # - # Let's take for example this non persisted object. + # Let's take for example this non-persisted object. # # class ContactMessage # include ActiveModel::Conversion @@ -18,8 +21,11 @@ module ActiveModel # cm.to_model == self # => true # cm.to_key # => nil # cm.to_param # => nil + # cm.to_path # => "contact_messages/contact_message" # module Conversion + extend ActiveSupport::Concern + # If your object is already designed to implement all of the Active Model # you can use the default :to_model implementation, which simply # returns self. @@ -45,5 +51,21 @@ module ActiveModel def to_param persisted? ? to_key.join('-') : nil end + + # Returns a string identifying the path associated with the object. + # ActionPack uses this to find a suitable partial to represent the object. + def to_path + self.class.to_path + end + + module ClassMethods + def to_path + @_to_path ||= begin + element = ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(self)) + collection = ActiveSupport::Inflector.tableize(self) + "#{collection}/#{element}".freeze + end + end + end end end diff --git a/activemodel/lib/active_model/lint.rb b/activemodel/lib/active_model/lint.rb index b71ef4b22e..08c2e5fcf3 100644 --- a/activemodel/lib/active_model/lint.rb +++ b/activemodel/lib/active_model/lint.rb @@ -43,6 +43,16 @@ module ActiveModel assert model.to_param.nil?, "to_param should return nil when `persisted?` returns false" end + # == Responds to to_path + # + # Returns a string giving a relative path. This is used for looking up + # partials. For example, a BlogPost model might return "blog_posts/blog_post" + # + def test_to_path + assert model.respond_to?(:to_path), "The model should respond to to_path" + assert_kind_of String, model.to_path + end + # == Responds to valid? # # Returns a boolean that specifies whether the object is in a valid or invalid @@ -66,15 +76,14 @@ module ActiveModel # == Naming # - # Model.model_name must return a string with some convenience methods as - # :human and :partial_path. Check ActiveModel::Naming for more information. + # Model.model_name must return a string with some convenience methods: + # :human, :singular, and :plural. Check ActiveModel::Naming for more information. # def test_model_naming assert model.class.respond_to?(:model_name), "The model should respond to model_name" model_name = model.class.model_name assert_kind_of String, model_name assert_kind_of String, model_name.human - assert_kind_of String, model_name.partial_path assert_kind_of String, model_name.singular assert_kind_of String, model_name.plural end diff --git a/activemodel/lib/active_model/naming.rb b/activemodel/lib/active_model/naming.rb index 4c1a82f413..26fa3062eb 100644 --- a/activemodel/lib/active_model/naming.rb +++ b/activemodel/lib/active_model/naming.rb @@ -1,12 +1,15 @@ require 'active_support/inflector' require 'active_support/core_ext/hash/except' require 'active_support/core_ext/module/introspection' +require 'active_support/core_ext/module/deprecation' module ActiveModel class Name < String attr_reader :singular, :plural, :element, :collection, :partial_path, :route_key, :param_key, :i18n_key alias_method :cache_key, :collection + deprecate :partial_path => "ActiveModel::Name#partial_path is deprecated. Call #to_path on model instances directly instead." + def initialize(klass, namespace = nil, name = nil) name ||= klass.name super(name) diff --git a/activemodel/test/cases/conversion_test.rb b/activemodel/test/cases/conversion_test.rb index 7669bf5f65..2eccc4e56d 100644 --- a/activemodel/test/cases/conversion_test.rb +++ b/activemodel/test/cases/conversion_test.rb @@ -1,5 +1,6 @@ require 'cases/helper' require 'models/contact' +require 'models/helicopter' class ConversionTest < ActiveModel::TestCase test "to_model default implementation returns self" do @@ -22,4 +23,10 @@ class ConversionTest < ActiveModel::TestCase test "to_param default implementation returns a string of ids for persisted records" do assert_equal "1", Contact.new(:id => 1).to_param end -end \ No newline at end of file + + test "to_path default implementation returns a string giving a relative path" do + assert_equal "contacts/contact", Contact.new.to_path + assert_equal "helicopters/helicopter", Helicopter.new.to_path, + "ActiveModel::Conversion#to_path caching should be class-specific" + end +end diff --git a/activemodel/test/cases/naming_test.rb b/activemodel/test/cases/naming_test.rb index f814fcc56c..bafe4f3c0c 100644 --- a/activemodel/test/cases/naming_test.rb +++ b/activemodel/test/cases/naming_test.rb @@ -26,7 +26,9 @@ class NamingTest < ActiveModel::TestCase end def test_partial_path - assert_equal 'post/track_backs/track_back', @model_name.partial_path + assert_deprecated(/#partial_path.*#to_path/) do + assert_equal 'post/track_backs/track_back', @model_name.partial_path + end end def test_human @@ -56,7 +58,9 @@ class NamingWithNamespacedModelInIsolatedNamespaceTest < ActiveModel::TestCase end def test_partial_path - assert_equal 'blog/posts/post', @model_name.partial_path + assert_deprecated(/#partial_path.*#to_path/) do + assert_equal 'blog/posts/post', @model_name.partial_path + end end def test_human @@ -98,7 +102,9 @@ class NamingWithNamespacedModelInSharedNamespaceTest < ActiveModel::TestCase end def test_partial_path - assert_equal 'blog/posts/post', @model_name.partial_path + assert_deprecated(/#partial_path.*#to_path/) do + assert_equal 'blog/posts/post', @model_name.partial_path + end end def test_human @@ -136,7 +142,9 @@ class NamingWithSuppliedModelNameTest < ActiveModel::TestCase end def test_partial_path - assert_equal 'articles/article', @model_name.partial_path + assert_deprecated(/#partial_path.*#to_path/) do + assert_equal 'articles/article', @model_name.partial_path + end end def test_human diff --git a/activemodel/test/models/helicopter.rb b/activemodel/test/models/helicopter.rb new file mode 100644 index 0000000000..a52b6fb4dd --- /dev/null +++ b/activemodel/test/models/helicopter.rb @@ -0,0 +1,3 @@ +class Helicopter + include ActiveModel::Conversion +end From c17254319b7fadb789cde24d1e72a233a33e4ac7 Mon Sep 17 00:00:00 2001 From: Erik Michaels-Ober Date: Mon, 25 Jul 2011 14:13:26 -0700 Subject: [PATCH 006/345] Add documentation for :format => true --- railties/guides/source/routing.textile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/railties/guides/source/routing.textile b/railties/guides/source/routing.textile index 68fb22f5d8..99dd9a1cd2 100644 --- a/railties/guides/source/routing.textile +++ b/railties/guides/source/routing.textile @@ -569,6 +569,12 @@ NOTE: By requesting +"/foo/bar.json"+, your +params[:pages]+ will be equals to + match '*pages' => 'pages#show', :format => false +NOTE: If you want to make the format segment mandatory, so it cannot be omitted, you can supply +:format => true+ like this: + + +match '*pages' => 'pages#show', :format => true + + h4. Redirection You can redirect any path to another path using the +redirect+ helper in your router: From ecd4f0b6ff8c54b9f247cd3c676c8d754baefdc3 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Mon, 25 Jul 2011 18:54:25 -0300 Subject: [PATCH 007/345] Don't use Rack::Sendfile middleware if x_sendfile_header is not present --- railties/lib/rails/application.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index 9e2f1a4b7a..fb60ddd9b5 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -163,7 +163,9 @@ module Rails middleware.use ::Rails::Rack::Logger # must come after Rack::MethodOverride to properly log overridden methods middleware.use ::ActionDispatch::ShowExceptions, config.consider_all_requests_local middleware.use ::ActionDispatch::RemoteIp, config.action_dispatch.ip_spoofing_check, config.action_dispatch.trusted_proxies - middleware.use ::Rack::Sendfile, config.action_dispatch.x_sendfile_header + if config.action_dispatch.x_sendfile_header.present? + middleware.use ::Rack::Sendfile, config.action_dispatch.x_sendfile_header + end middleware.use ::ActionDispatch::Reloader unless config.cache_classes middleware.use ::ActionDispatch::Callbacks middleware.use ::ActionDispatch::Cookies From cb85d70d61705381a57cb99d8dcd4d7083f0a143 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Mon, 25 Jul 2011 19:06:30 -0300 Subject: [PATCH 008/345] Remove unused use_sprockets config --- actionpack/lib/abstract_controller/asset_paths.rb | 2 +- actionpack/lib/sprockets/railtie.rb | 7 ------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/actionpack/lib/abstract_controller/asset_paths.rb b/actionpack/lib/abstract_controller/asset_paths.rb index ad14cd6d87..b104d34fb5 100644 --- a/actionpack/lib/abstract_controller/asset_paths.rb +++ b/actionpack/lib/abstract_controller/asset_paths.rb @@ -3,7 +3,7 @@ module AbstractController extend ActiveSupport::Concern included do - config_accessor :asset_host, :asset_path, :assets_dir, :javascripts_dir, :stylesheets_dir, :use_sprockets + config_accessor :asset_host, :asset_path, :assets_dir, :javascripts_dir, :stylesheets_dir end end end diff --git a/actionpack/lib/sprockets/railtie.rb b/actionpack/lib/sprockets/railtie.rb index c8d6af942d..83799d2b4d 100644 --- a/actionpack/lib/sprockets/railtie.rb +++ b/actionpack/lib/sprockets/railtie.rb @@ -11,13 +11,6 @@ module Sprockets load "sprockets/assets.rake" end - # Configure ActionController to use sprockets. - initializer "sprockets.set_configs", :after => "action_controller.set_configs" do |app| - ActiveSupport.on_load(:action_controller) do - self.use_sprockets = app.config.assets.enabled - end - end - # We need to configure this after initialization to ensure we collect # paths from all engines. This hook is invoked exactly before routes # are compiled, and so that other Railties have an opportunity to From 36ab1cd293f3dfaa60897e2751fef4f68f1b91d8 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Mon, 25 Jul 2011 23:02:12 -0300 Subject: [PATCH 009/345] Bump rack up. Closes #2107 --- actionpack/actionpack.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec index 15d104fd82..1766a9322d 100644 --- a/actionpack/actionpack.gemspec +++ b/actionpack/actionpack.gemspec @@ -21,7 +21,7 @@ Gem::Specification.new do |s| s.add_dependency('rack-cache', '~> 1.0.2') s.add_dependency('builder', '~> 3.0.0') s.add_dependency('i18n', '~> 0.6') - s.add_dependency('rack', '~> 1.3.1') + s.add_dependency('rack', '~> 1.3.2') s.add_dependency('rack-test', '~> 0.6.0') s.add_dependency('rack-mount', '~> 0.8.1') s.add_dependency('sprockets', '= 2.0.0.beta.10') From 4d13e90531c1de639acf39ef366f68db7305c1e1 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 26 Jul 2011 00:18:56 -0300 Subject: [PATCH 010/345] Check that Rack::Sendfile is not included unless config.action_dispatch.x_sendfile_header is set --- railties/test/application/middleware_test.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/railties/test/application/middleware_test.rb b/railties/test/application/middleware_test.rb index 6a0a272073..bed5ba503f 100644 --- a/railties/test/application/middleware_test.rb +++ b/railties/test/application/middleware_test.rb @@ -20,6 +20,8 @@ module ApplicationTests end test "default middleware stack" do + add_to_config "config.action_dispatch.x_sendfile_header = 'X-Sendfile'" + boot! assert_equal [ @@ -47,6 +49,12 @@ module ApplicationTests ], middleware end + test "Rack::Sendfile is not included by default" do + boot! + + assert !middleware.include?("Rack::Sendfile"), "Rack::Sendfile is not included in the default stack unless you set config.action_dispatch.x_sendfile_header" + end + test "Rack::Cache is present when action_controller.perform_caching is set" do add_to_config "config.action_controller.perform_caching = true" From 155bb7c75d3cf403c013a713d704267e284b5a14 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 26 Jul 2011 00:42:31 -0300 Subject: [PATCH 011/345] Bump sprockets up --- actionpack/actionpack.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec index 1766a9322d..620fdc4a72 100644 --- a/actionpack/actionpack.gemspec +++ b/actionpack/actionpack.gemspec @@ -24,7 +24,7 @@ Gem::Specification.new do |s| s.add_dependency('rack', '~> 1.3.2') s.add_dependency('rack-test', '~> 0.6.0') s.add_dependency('rack-mount', '~> 0.8.1') - s.add_dependency('sprockets', '= 2.0.0.beta.10') + s.add_dependency('sprockets', '~> 2.0.0.beta.12') s.add_dependency('erubis', '~> 2.7.0') s.add_development_dependency('tzinfo', '~> 0.3.29') From b4e577945b882594425082ae16e2076cc82bdc72 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 26 Jul 2011 01:00:00 -0300 Subject: [PATCH 012/345] use_sprockets is not used anymore --- .../helpers/asset_tag_helpers/javascript_tag_helpers.rb | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb index 0f8a63901e..25cc561608 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb @@ -83,11 +83,7 @@ module ActionView # javascript_path "http://www.example.com/js/xmlhr" # => http://www.example.com/js/xmlhr # javascript_path "http://www.example.com/js/xmlhr.js" # => http://www.example.com/js/xmlhr.js def javascript_path(source) - if config.use_sprockets - asset_path(source, 'js') - else - asset_paths.compute_public_path(source, 'javascripts', 'js') - end + asset_paths.compute_public_path(source, 'javascripts', 'js') end alias_method :path_to_javascript, :javascript_path # aliased to avoid conflicts with a javascript_path named route From 41902e6932d46e3142185ee8d75dd861d0424d4e Mon Sep 17 00:00:00 2001 From: Franck Verrot Date: Tue, 26 Jul 2011 11:36:18 +0200 Subject: [PATCH 013/345] Simplify the test by using id and name. `id` will be the only real sort criteria in any case as it's unique. --- activerecord/test/cases/relations_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index 6363cae371..821da91f0a 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -963,6 +963,6 @@ class RelationTest < ActiveRecord::TestCase end def test_ordering_with_extra_spaces - assert_equal authors(:david), Author.order('organization_id ASC , owned_essay_id DESC').last + assert_equal authors(:david), Author.order('id DESC , name DESC').last end end From 3bfcf5ffc8671f169e2435706709660b3b3cefbe Mon Sep 17 00:00:00 2001 From: thoefer Date: Tue, 26 Jul 2011 11:42:53 +0200 Subject: [PATCH 014/345] refactored 'assert_redirected_to': local call to validate_request! will be called in assert_response already. changed names of local variables in order to recognize the semantics a bit easier. --- .../lib/action_dispatch/testing/assertions/response.rb | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/actionpack/lib/action_dispatch/testing/assertions/response.rb b/actionpack/lib/action_dispatch/testing/assertions/response.rb index a2d639cd56..33c6cd5221 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/response.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/response.rb @@ -55,16 +55,15 @@ module ActionDispatch # assert_redirected_to @customer # def assert_redirected_to(options = {}, message=nil) - validate_request! assert_response(:redirect, message) return true if options == @response.location - redirected_to_after_normalization = normalize_argument_to_redirection(@response.location) - options_after_normalization = normalize_argument_to_redirection(options) + redirect_is = normalize_argument_to_redirection(@response.location) + redirect_expected = normalize_argument_to_redirection(options) - if redirected_to_after_normalization != options_after_normalization - flunk "Expected response to be a redirect to <#{options_after_normalization}> but was a redirect to <#{redirected_to_after_normalization}>" + if redirect_is != redirect_expected + flunk "Expected response to be a redirect to <#{redirect_expected}> but was a redirect to <#{redirect_is}>" end end From 04cc446d178653d362510e79a22db5300d463161 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C5=82awosz=20S=C5=82awi=C5=84ski?= Date: Sat, 23 Jul 2011 21:35:16 +0200 Subject: [PATCH 015/345] allow select to have multiple arguments --- activerecord/lib/active_record/relation/query_methods.rb | 9 ++++++--- activerecord/test/cases/base_test.rb | 5 +++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 1654ae1eac..792ffe1c5d 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -37,12 +37,15 @@ module ActiveRecord relation end - def select(value = Proc.new) + def select(*args, &blk) + if !block_given? && args.blank? + raise ArgumentError + end if block_given? - to_a.select {|*block_args| value.call(*block_args) } + to_a.select {|*block_args| blk.call(*block_args) } else relation = clone - relation.select_values += Array.wrap(value) + relation.select_values += args relation end end diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index f2f5b73626..84b66fdf49 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -123,6 +123,11 @@ class BasicsTest < ActiveRecord::TestCase assert_equal Topic.all.map(&:id).sort, topic_ids end + def test_select_symbol_for_many_arguments + topics = Topic.select(:id, :author_name).map{|topic| [topic.id, topic.author_name]}.sort + assert_equal Topic.all.map{|topic| [topic.id,topic.author_name]}.sort, topics + end + def test_table_exists assert !NonExistentTable.table_exists? assert Topic.table_exists? From 14c6fca9cd2353e3b949e2683b69fac7e356097e Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Tue, 26 Jul 2011 16:12:17 +0200 Subject: [PATCH 016/345] Revert "allow select to have multiple arguments" This reverts commit 04cc446d178653d362510e79a22db5300d463161. I reverted it because apparently we want to use: select([:a, :b]) instead of select(:a, :b), but there was no tests for that form. --- activerecord/lib/active_record/relation/query_methods.rb | 9 +++------ activerecord/test/cases/base_test.rb | 5 ----- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 792ffe1c5d..1654ae1eac 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -37,15 +37,12 @@ module ActiveRecord relation end - def select(*args, &blk) - if !block_given? && args.blank? - raise ArgumentError - end + def select(value = Proc.new) if block_given? - to_a.select {|*block_args| blk.call(*block_args) } + to_a.select {|*block_args| value.call(*block_args) } else relation = clone - relation.select_values += args + relation.select_values += Array.wrap(value) relation end end diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index 84b66fdf49..f2f5b73626 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -123,11 +123,6 @@ class BasicsTest < ActiveRecord::TestCase assert_equal Topic.all.map(&:id).sort, topic_ids end - def test_select_symbol_for_many_arguments - topics = Topic.select(:id, :author_name).map{|topic| [topic.id, topic.author_name]}.sort - assert_equal Topic.all.map{|topic| [topic.id,topic.author_name]}.sort, topics - end - def test_table_exists assert !NonExistentTable.table_exists? assert Topic.table_exists? From 945f0c82af75346c70da59539ee7d71f54bb7a12 Mon Sep 17 00:00:00 2001 From: Damien Mathieu <42@dmathieu.com> Date: Tue, 26 Jul 2011 16:58:24 +0200 Subject: [PATCH 017/345] use sprocket's append_path and assert_match --- .../test/template/sprockets_helper_test.rb | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/actionpack/test/template/sprockets_helper_test.rb b/actionpack/test/template/sprockets_helper_test.rb index 3d7abc7e2a..b9161b62c5 100644 --- a/actionpack/test/template/sprockets_helper_test.rb +++ b/actionpack/test/template/sprockets_helper_test.rb @@ -21,9 +21,9 @@ class SprocketsHelperTest < ActionView::TestCase @controller.request = MockRequest.new @assets = Sprockets::Environment.new - @assets.paths << FIXTURES.join("sprockets/app/javascripts") - @assets.paths << FIXTURES.join("sprockets/app/stylesheets") - @assets.paths << FIXTURES.join("sprockets/app/images") + @assets.append_path(FIXTURES.join("sprockets/app/javascripts")) + @assets.append_path(FIXTURES.join("sprockets/app/stylesheets")) + @assets.append_path(FIXTURES.join("sprockets/app/images")) application = Struct.new(:config, :assets).new(config, @assets) Rails.stubs(:application).returns(application) @@ -37,7 +37,7 @@ class SprocketsHelperTest < ActionView::TestCase end test "asset_path" do - assert_equal "/assets/logo-9c0a079bdd7701d7e729bd956823d153.png", + assert_match %r{/assets/logo-[0-9a-f]+.png}, asset_path("logo.png") end @@ -112,7 +112,7 @@ class SprocketsHelperTest < ActionView::TestCase @config.action_controller.default_asset_host_protocol = :request @config.action_controller.perform_caching = true - assert_equal "/assets/logo-9c0a079bdd7701d7e729bd956823d153.png", + assert_match %r{/assets/logo-[0-9a-f]+.png}, asset_path("logo.png") end @@ -123,12 +123,12 @@ class SprocketsHelperTest < ActionView::TestCase end test "javascript path" do - assert_equal "/assets/application-d41d8cd98f00b204e9800998ecf8427e.js", + assert_match %r{/assets/application-[0-9a-f]+.js}, asset_path(:application, "js") - assert_equal "/assets/xmlhr-d41d8cd98f00b204e9800998ecf8427e.js", + assert_match %r{/assets/xmlhr-[0-9a-f]+.js}, asset_path("xmlhr", "js") - assert_equal "/assets/dir/xmlhr-d41d8cd98f00b204e9800998ecf8427e.js", + assert_match %r{/assets/dir/xmlhr-[0-9a-f]+.js}, asset_path("dir/xmlhr.js", "js") assert_equal "/dir/xmlhr.js", @@ -141,28 +141,28 @@ class SprocketsHelperTest < ActionView::TestCase end test "javascript include tag" do - assert_equal '', + assert_match %r{}, javascript_include_tag(:application) - assert_equal '', + assert_match %r{}, javascript_include_tag("xmlhr") - assert_equal '', + assert_match %r{}, javascript_include_tag("xmlhr.js") assert_equal '', javascript_include_tag("http://www.example.com/xmlhr") - assert_equal "\n", + assert_match %r{\n}, javascript_include_tag(:application, :debug => true) - assert_equal "\n", + assert_match %r{\n}, javascript_include_tag("xmlhr", "extra") end test "stylesheet path" do - assert_equal "/assets/application-68b329da9893e34099c7d8ad5cb9c940.css", asset_path(:application, "css") + assert_match %r{/assets/application-[0-9a-f]+.css}, asset_path(:application, "css") - assert_equal "/assets/style-d41d8cd98f00b204e9800998ecf8427e.css", asset_path("style", "css") - assert_equal "/assets/dir/style-d41d8cd98f00b204e9800998ecf8427e.css", asset_path("dir/style.css", "css") + assert_match %r{/assets/style-[0-9a-f]+.css}, asset_path("style", "css") + assert_match %r{/assets/dir/style-[0-9a-f]+.css}, asset_path("dir/style.css", "css") assert_equal "/dir/style.css", asset_path("/dir/style.css", "css") assert_equal "http://www.example.com/css/style", @@ -172,37 +172,37 @@ class SprocketsHelperTest < ActionView::TestCase end test "stylesheet link tag" do - assert_equal '', + assert_match %r{}, stylesheet_link_tag(:application) - assert_equal '', + assert_match %r{}, stylesheet_link_tag("style") - assert_equal '', + assert_match %r{}, stylesheet_link_tag("style.css") assert_equal '', stylesheet_link_tag("http://www.example.com/style.css") - assert_equal '', + assert_match %r{}, stylesheet_link_tag("style", :media => "all") - assert_equal '', + assert_match %r{}, stylesheet_link_tag("style", :media => "print") - assert_equal "\n", + assert_match %r{\n}, stylesheet_link_tag(:application, :debug => true) - assert_equal "\n", + assert_match %r{\n}, stylesheet_link_tag("style", "extra") end test "alternate asset prefix" do stubs(:asset_prefix).returns("/themes/test") - assert_equal "/themes/test/style-d41d8cd98f00b204e9800998ecf8427e.css", asset_path("style", "css") + assert_match %r{/themes/test/style-[0-9a-f]+.css}, asset_path("style", "css") end test "alternate asset environment" do assets = Sprockets::Environment.new - assets.paths << FIXTURES.join("sprockets/alternate/stylesheets") + assets.append_path(FIXTURES.join("sprockets/alternate/stylesheets")) stubs(:asset_environment).returns(assets) - assert_equal "/assets/style-df0b97ad35a8e1f7f61097461f77c19a.css", asset_path("style", "css") + assert_match %r{/assets/style-[0-9a-f]+.css}, asset_path("style", "css") end end From f17ea60f98f9049f2b0aaeeaf40ce9ad79ce824c Mon Sep 17 00:00:00 2001 From: Jonathan del Strother Date: Tue, 26 Jul 2011 16:10:55 +0100 Subject: [PATCH 018/345] Constantize a regexp in Dependencies#load_missing_constant --- activesupport/lib/active_support/dependencies.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb index d1543c4c58..a60697cb12 100644 --- a/activesupport/lib/active_support/dependencies.rb +++ b/activesupport/lib/active_support/dependencies.rb @@ -466,6 +466,7 @@ module ActiveSupport #:nodoc: # Load the constant named +const_name+ which is missing from +from_mod+. If # it is not possible to load the constant into from_mod, try its parent module # using const_missing. + THIS_FILE = %r{#{Regexp.escape(__FILE__)}} def load_missing_constant(from_mod, const_name) log_call from_mod, const_name @@ -478,7 +479,7 @@ module ActiveSupport #:nodoc: qualified_name = qualified_name_for from_mod, const_name path_suffix = qualified_name.underscore - trace = caller.reject {|l| l =~ %r{#{Regexp.escape(__FILE__)}}} + trace = caller.reject {|l| l =~ THIS_FILE} name_error = NameError.new("uninitialized constant #{qualified_name}") name_error.set_backtrace(trace) From cf3f1c9ba8d7c663fedb9fad9895dea5c7675c1c Mon Sep 17 00:00:00 2001 From: Vishnu Atrai Date: Tue, 26 Jul 2011 22:33:23 +0530 Subject: [PATCH 019/345] remove deprication warning for ruby 1.9.3-head for unused variables --- .../lib/active_record/connection_adapters/mysql2_adapter.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb index d6c167ad36..f9602bbe77 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb @@ -577,7 +577,7 @@ module ActiveRecord def quoted_columns_for_index(column_names, options = {}) length = options[:length] if options.is_a?(Hash) - quoted_column_names = case length + case length when Hash column_names.map {|name| length[name] ? "#{quote_column_name(name)}(#{length[name]})" : quote_column_name(name) } when Fixnum From d4246e5bb3a446238f2b0683f24638bad669778f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 26 Jul 2011 10:58:16 -0700 Subject: [PATCH 020/345] fixing whitespace errors --- activesupport/test/xml_mini_test.rb | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/activesupport/test/xml_mini_test.rb b/activesupport/test/xml_mini_test.rb index e2b90ae16e..4450c1a0ae 100644 --- a/activesupport/test/xml_mini_test.rb +++ b/activesupport/test/xml_mini_test.rb @@ -50,49 +50,49 @@ module XmlMiniTest def test_rename_key_does_not_dasherize_multiple_trailing_underscores assert_equal "id__", ActiveSupport::XmlMini.rename_key("id__") - end + end end class ToTagTest < ActiveSupport::TestCase def assert_xml(xml) assert_equal xml, @options[:builder].target! end - + setup do @xml = ActiveSupport::XmlMini @options = {:skip_instruct => true, :builder => Builder::XmlMarkup.new} end - + test "#to_tag accepts a callable object and passes options with the builder" do @xml.to_tag(:some_tag, lambda {|o| o[:builder].br }, @options) assert_xml "
" end - + test "#to_tag accepts a callable object and passes options and tag name" do @xml.to_tag(:tag, lambda {|o, t| o[:builder].b(t) }, @options) assert_xml "tag" end - + test "#to_tag accepts an object responding to #to_xml and passes the options, where :root is key" do obj = Object.new obj.instance_eval do def to_xml(options) options[:builder].yo(options[:root].to_s) end end - + @xml.to_tag(:tag, obj, @options) assert_xml "tag" end - + test "#to_tag accepts arbitrary objects responding to #to_str" do @xml.to_tag(:b, "Howdy", @options) assert_xml "Howdy" end - + test "#to_tag should dasherize the space when passed a string with spaces as a key" do @xml.to_tag("New York", 33, @options) assert_xml "33" end - + test "#to_tag should dasherize the space when passed a symbol with spaces as a key" do @xml.to_tag(:"New York", 33, @options) assert_xml "33" From 64807b964f6b4d58d550608b6de84ebd5ec846f3 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 26 Jul 2011 11:02:41 -0700 Subject: [PATCH 021/345] fixing tests on ruby trunk --- activesupport/test/xml_mini_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activesupport/test/xml_mini_test.rb b/activesupport/test/xml_mini_test.rb index 4450c1a0ae..dde17ea403 100644 --- a/activesupport/test/xml_mini_test.rb +++ b/activesupport/test/xml_mini_test.rb @@ -58,7 +58,7 @@ module XmlMiniTest assert_equal xml, @options[:builder].target! end - setup do + def setup @xml = ActiveSupport::XmlMini @options = {:skip_instruct => true, :builder => Builder::XmlMarkup.new} end From 1e69f0b84a17fffdcb9aa2cba156117ae47fa92f Mon Sep 17 00:00:00 2001 From: Vishnu Atrai Date: Tue, 26 Jul 2011 23:39:17 +0530 Subject: [PATCH 022/345] remove deprication warning: ambiguous first argument; put parentheses or even spaces --- activerecord/test/cases/base_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index f2f5b73626..12101c1683 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -1867,6 +1867,6 @@ class BasicsTest < ActiveRecord::TestCase def test_cache_key_format_for_existing_record_with_nil_updated_at dev = Developer.first dev.update_attribute(:updated_at, nil) - assert_match /\/#{dev.id}$/, dev.cache_key + assert_match(/\/#{dev.id}$/, dev.cache_key) end end From 5a5d7ba973dbd833d27523e61d462ad598b0ae75 Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Tue, 26 Jul 2011 18:17:58 +0000 Subject: [PATCH 023/345] enable Travis CI irc notifications to #rails-contrib on irc.freenode.org --- .travis.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index d33c6a3c86..596611ecf4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,4 @@ script: 'ci/travis.rb' -notifications: - disabled: true rvm: - 1.8.7 - 1.9.2 @@ -9,4 +7,8 @@ env: - "GEM=ap,am,amo,ares,as" - "GEM=ar:mysql" - "GEM=ar:mysql2" - - "GEM=ar:sqlite3" \ No newline at end of file + - "GEM=ar:sqlite3" +notifications: + email: false + irc: + - "irc.freenode.org#rails-contrib" \ No newline at end of file From db34a652772a8549d5b2eb75cf3c7adab61f6507 Mon Sep 17 00:00:00 2001 From: Vishnu Atrai Date: Tue, 26 Jul 2011 23:53:54 +0530 Subject: [PATCH 024/345] remove unused variables warnings removed --- activesupport/test/safe_buffer_test.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/activesupport/test/safe_buffer_test.rb b/activesupport/test/safe_buffer_test.rb index 46bc0d7a34..7662e9b765 100644 --- a/activesupport/test/safe_buffer_test.rb +++ b/activesupport/test/safe_buffer_test.rb @@ -80,14 +80,12 @@ class SafeBufferTest < ActiveSupport::TestCase end test "Should escape dirty buffers on add" do - dirty = @buffer clean = "hello".html_safe @buffer.gsub!('', '<>') assert_equal "hello<>", clean + @buffer end test "Should concat as a normal string when dirty" do - dirty = @buffer clean = "hello".html_safe @buffer.gsub!('', '<>') assert_equal "<>hello", @buffer + clean From 17d0efb67965b0ce88b306fb577425e90cb99155 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 26 Jul 2011 18:11:03 -0300 Subject: [PATCH 025/345] Remove cruise files --- ci/ci_build.rb | 181 ------------------------------------------ ci/ci_setup_notes.txt | 140 -------------------------------- ci/cruise_config.rb | 9 --- ci/site.css | 13 --- ci/site_config.rb | 72 ----------------- 5 files changed, 415 deletions(-) delete mode 100755 ci/ci_build.rb delete mode 100644 ci/ci_setup_notes.txt delete mode 100644 ci/cruise_config.rb delete mode 100644 ci/site.css delete mode 100644 ci/site_config.rb diff --git a/ci/ci_build.rb b/ci/ci_build.rb deleted file mode 100755 index 50f7f410fa..0000000000 --- a/ci/ci_build.rb +++ /dev/null @@ -1,181 +0,0 @@ -#!/usr/bin/env ruby -require 'fileutils' -include FileUtils - -def root_dir - @root_dir ||= File.expand_path('../..', __FILE__) -end - -def rake(*tasks) - tasks.each do |task| - cmd = "bundle exec rake #{task}" - puts "Running command: #{cmd}" - return false unless system(cmd) - end - true -end - -puts "[CruiseControl] Rails build" -build_results = {} - -# Install required version of bundler. -bundler_install_cmd = "sudo gem install bundler --no-ri --no-rdoc" -puts "Running command: #{bundler_install_cmd}" -build_results[:install_bundler] = system bundler_install_cmd - -cd root_dir do - puts - puts "[CruiseControl] Bundling gems" - puts - build_results[:bundle] = system 'bundle update' -end - -cd "#{root_dir}/activesupport" do - puts - puts "[CruiseControl] Building Active Support" - puts - build_results[:activesupport] = rake 'test' - build_results[:activesupport_isolated] = rake 'test:isolated' -end - -system "sudo rm -R #{root_dir}/railties/tmp" -cd "#{root_dir}/railties" do - puts - puts "[CruiseControl] Building Railties" - puts - build_results[:railties] = rake 'test' -end - -cd "#{root_dir}/actionpack" do - puts - puts "[CruiseControl] Building Action Pack" - puts - build_results[:actionpack] = rake 'test' - build_results[:actionpack_isolated] = rake 'test:isolated' -end - -cd "#{root_dir}/actionmailer" do - puts - puts "[CruiseControl] Building Action Mailer" - puts - build_results[:actionmailer] = rake 'test' - build_results[:actionmailer_isolated] = rake 'test:isolated' -end - -cd "#{root_dir}/activemodel" do - puts - puts "[CruiseControl] Building Active Model" - puts - build_results[:activemodel] = rake 'test' - build_results[:activemodel_isolated] = rake 'test:isolated' -end - -rm_f "#{root_dir}/activeresource/debug.log" -cd "#{root_dir}/activeresource" do - puts - puts "[CruiseControl] Building Active Resource" - puts - build_results[:activeresource] = rake 'test' - build_results[:activeresource_isolated] = rake 'test:isolated' -end - -rm_f "#{root_dir}/activerecord/debug.log" -cd "#{root_dir}/activerecord" do - puts - puts "[CruiseControl] Building Active Record with MySQL IM enabled" - puts - ENV['IM'] = 'true' - build_results[:activerecord_mysql_IM] = rake 'mysql:rebuild_databases', 'mysql:test' - build_results[:activerecord_mysql_isolated_IM] = rake 'mysql:rebuild_databases', 'mysql:isolated_test' -end - -cd "#{root_dir}/activerecord" do - puts - puts "[CruiseControl] Building Active Record with MySQL IM disabled" - puts - ENV['IM'] = 'false' - build_results[:activerecord_mysql] = rake 'mysql:rebuild_databases', 'mysql:test' - build_results[:activerecord_mysql_isolated] = rake 'mysql:rebuild_databases', 'mysql:isolated_test' -end - -cd "#{root_dir}/activerecord" do - puts - puts "[CruiseControl] Building Active Record with MySQL2 IM enabled" - puts - ENV['IM'] = 'true' - build_results[:activerecord_mysql2_IM] = rake 'mysql:rebuild_databases', 'mysql2:test' - build_results[:activerecord_mysql2_isolated_IM] = rake 'mysql:rebuild_databases', 'mysql2:isolated_test' -end - -cd "#{root_dir}/activerecord" do - puts - puts "[CruiseControl] Building Active Record with MySQL2 IM disabled" - puts - ENV['IM'] = 'false' - build_results[:activerecord_mysql2] = rake 'mysql:rebuild_databases', 'mysql2:test' - build_results[:activerecord_mysql2_isolated] = rake 'mysql:rebuild_databases', 'mysql2:isolated_test' -end - -cd "#{root_dir}/activerecord" do - puts - puts "[CruiseControl] Building Active Record with PostgreSQL IM enabled" - puts - ENV['IM'] = 'true' - build_results[:activerecord_postgresql8_IM] = rake 'postgresql:rebuild_databases', 'postgresql:test' - build_results[:activerecord_postgresql8_isolated_IM] = rake 'postgresql:rebuild_databases', 'postgresql:isolated_test' -end - -cd "#{root_dir}/activerecord" do - puts - puts "[CruiseControl] Building Active Record with PostgreSQL IM disabled" - puts - ENV['IM'] = 'false' - build_results[:activerecord_postgresql8] = rake 'postgresql:rebuild_databases', 'postgresql:test' - build_results[:activerecord_postgresql8_isolated] = rake 'postgresql:rebuild_databases', 'postgresql:isolated_test' -end - -cd "#{root_dir}/activerecord" do - puts - puts "[CruiseControl] Building Active Record with SQLite 3 IM enabled" - puts - ENV['IM'] = 'true' - build_results[:activerecord_sqlite3_IM] = rake 'sqlite3:test' - build_results[:activerecord_sqlite3_isolated_IM] = rake 'sqlite3:isolated_test' -end - -cd "#{root_dir}/activerecord" do - puts - puts "[CruiseControl] Building Active Record with SQLite 3 IM disabled" - puts - ENV['IM'] = 'false' - build_results[:activerecord_sqlite3] = rake 'sqlite3:test' - build_results[:activerecord_sqlite3_isolated] = rake 'sqlite3:isolated_test' -end - - -puts -puts "[CruiseControl] Build environment:" -puts "[CruiseControl] #{`cat /etc/issue`}" -puts "[CruiseControl] #{`uname -a`}" -puts "[CruiseControl] #{`ruby -v`}" -puts "[CruiseControl] #{`mysql --version`}" -puts "[CruiseControl] #{`pg_config --version`}" -puts "[CruiseControl] SQLite3: #{`sqlite3 -version`}" -`gem env`.each_line {|line| print "[CruiseControl] #{line}"} -puts "[CruiseControl] Bundled gems:" -`bundle show`.each_line {|line| print "[CruiseControl] #{line}"} -puts "[CruiseControl] Local gems:" -`gem list`.each_line {|line| print "[CruiseControl] #{line}"} - -failures = build_results.select { |key, value| value == false } - -if failures.empty? - puts - puts "[CruiseControl] Rails build finished sucessfully" - exit(0) -else - puts - puts "[CruiseControl] Rails build FAILED" - puts "[CruiseControl] Failed components: #{failures.map { |component| component.first }.join(', ')}" - exit(-1) -end diff --git a/ci/ci_setup_notes.txt b/ci/ci_setup_notes.txt deleted file mode 100644 index 890f9e8ef6..0000000000 --- a/ci/ci_setup_notes.txt +++ /dev/null @@ -1,140 +0,0 @@ -# Rails Continuous Integration Server Setup Notes -# This procedure was used to set up http://ci.rubyonrails.org on Ubuntu 8.04 -# It can be used as a guideline for setting up your own CI server against your local rails branches - -* Set up ci user: -# log in as root -$ adduser ci -enter user info and password -$ visudo -# give ci user same sudo rights as root - -* Disable root login: -# log in as ci -$ sudo vi /etc/shadow -# overwrite and disable encrypted root password to disable root login: -root:*:14001:0:99999:7::: - -* Change Hostname: -$ sudo vi /etc/hostname -change to correct hostname -$ sudo vi /etc/hosts -replace old hostname with the correct hostname -# reboot to use new hostname (and test reboot) -$ sudo shutdown -r now - -* Update aptitude: -$ sudo aptitude update - -* Use cinabox to perform rest of ruby/ccrb setup: -* https://github.com/thewoolleyman/cinabox/tree/master/README.txt - -# This is not yet properly supported by RubyGems... -# * Configure RubyGems to not require root access for gem installation -# $ vi ~/.profile -# # add this line at bottom: -# PATH="$HOME/.gem/ruby/1.8/bin:$PATH" -# $ sudo vi /etc/init.d/cruise -# # edit the start_cruise line to source CRUISE_USER/.profile: -# start_cruise "cd #{CRUISE_HOME} && source /home/#{CRUISE_USER}/.profile && ./cruise start -d" -# $ vi ~/.gemrc -# # add these lines: -# --- -# gemhome: /home/ci/.gem/ruby/1.8 -# gempath: -# - /home/ci/.gem/ruby/1.8 - -* If you did not configure no-root-gem installation via ~/.gemrc as shown above, then allow no-password sudo for gem installation: -$ sudo visudo -# add this line to bottom: -ci ALL=(ALL) NOPASSWD: ALL - -* Start ccrb via init script and check for default homepage at port 3333 - -* Install/setup nginx: -$ sudo aptitude install nginx -$ sudo vi /etc/nginx/sites-available/default -# Add the following entry at the top of the file above the 'server {' line: -upstream mongrel { - server 127.0.0.1:3333; -} - -# Change server_name entry to match server name - -# replace the contents of the root 'location / {}' block with the following entries: - proxy_pass http://mongrel; - proxy_redirect off; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Client-Verify SUCCESS; - proxy_read_timeout 65; - -# also comment default locations for /doc and /images -$ sudo /etc/init.d/nginx start - -* Add project to cruise (It will still fail until everything is set up): -$ cd ~/ccrb -$ ./cruise add rails -s git -r git://github.com/rails/rails.git # or the URI of your branch - -* Copy and configure cruise site config file: -$ cp ~/.cruise/projects/rails/work/ci/site_config.rb ~/.cruise/site_config.rb -# Edit ~/.cruise/site_config.rb as desired, for example: -ActionMailer::Base.smtp_settings = { - :address => "localhost", - :domain => "ci.yourdomain.com", -} -Configuration.dashboard_refresh_interval = 60.seconds -Configuration.dashboard_url = 'http://ci.yourdomain.com/' -Configuration.serialize_builds = true -Configuration.serialized_build_timeout = 1.hours -BuildReaper.number_of_builds_to_keep = 100 - -* Copy and configure cruise project config file -$ cp ~/.cruise/projects/rails/work/ci/cruise_config.rb ~/.cruise/projects/rails -$ vi ~/.cruise/projects/rails/cruise_config.rb: -# Edit ~/.cruise/projects/rails/cruise_config.rb as desired, for example: -Project.configure do |project| - project.build_command = 'ruby ci/ci_build.rb' - project.email_notifier.emails = ['recipient@yourdomain.com'] - project.email_notifier.from = 'sender@yourdomain.com' -end - -* Set up mysql -$ sudo aptitude install mysql-server-5.0 libmysqlclient-dev -# no password for mysql root user - -* setup sqlite 3 -$ sudo aptitude install sqlite3 libsqlite3-dev -# Note: there's some installation bugs with sqlite3-ruby 1.2.2 gem file permissions: -# http://www.icoretech.org/2008/07/06/no-such-file-to-load-sqlite3-database -# cd /usr/local/lib/ruby/gems/1.8/gems/sqlite3-ruby-1.2.2 && sudo find . -perm 0662 -exec chmod 664 {} \; - -* setup postgres -$ sudo aptitude install postgresql postgresql-server-dev-8.3 -$ sudo su - postgres -c 'createuser -s ci' - -* Install fcgi libraries -$ sudo apt-get install libfcgi-dev - -* Install memcached and start for first time (should start on reboot automatically) -$ sudo aptitude install memcached -$ sudo /etc/init.d/memcached start - -* Install and run GemInstaller to get all dependency gems -$ sudo gem install geminstaller -$ cd ~/.cruise/projects/rails/work -$ sudo geminstaller --config=ci/geminstaller.yml # turn up debugging with these options: --geminstaller-output=all --rubygems-output=all - -* Create ActiveRecord test databases for mysql -$ mysql -uroot -e 'grant all on *.* to rails@localhost;' -$ mysql -urails -e 'create database activerecord_unittest;' -$ mysql -urails -e 'create database activerecord_unittest2;' - -* Create ActiveRecord test databases for postgres -# cd to rails activerecord dir -$ rake postgresql:build_databases - -* Reboot and make sure everything is working -$ sudo shutdown -r now -$ http://ci.yourdomain.com diff --git a/ci/cruise_config.rb b/ci/cruise_config.rb deleted file mode 100644 index b64cd8aaea..0000000000 --- a/ci/cruise_config.rb +++ /dev/null @@ -1,9 +0,0 @@ -Project.configure do |project| - project.build_command = 'sudo gem update --system && ruby ci/ci_build.rb' - project.email_notifier.from = 'rails-ci@wyeworks.com' - - # project.campfire_notifier.account = 'rails' - # project.campfire_notifier.token = '' - # project.campfire_notifier.room = 'Rails 3' - # project.campfire_notifier.ssl = true -end diff --git a/ci/site.css b/ci/site.css deleted file mode 100644 index e771c5d1fd..0000000000 --- a/ci/site.css +++ /dev/null @@ -1,13 +0,0 @@ -/* this is a copy of /home/ci/.cruise/site.css, please make any changes to it there */ - -/* this is a copy of /home/ci/.cruise/site.css, please make any changes to it there */ - -/* if you'd like to add custom styles to cruise, add them here */ -/* the following will make successful builds green */ -a.success, a.success:visited { - color: #0A0; -} - -.build_success { - background-image: url(/images/green_gradient.png); -} diff --git a/ci/site_config.rb b/ci/site_config.rb deleted file mode 100644 index f9db39ed57..0000000000 --- a/ci/site_config.rb +++ /dev/null @@ -1,72 +0,0 @@ -# site_config.rb contains examples of various configuration options for the local installation -# of CruiseControl.rb. - -# YOU MUST RESTART YOUR CRUISE CONTROL SERVER FOR ANY CHANGES MADE HERE TO TAKE EFFECT!!! - -# EMAIL NOTIFICATION -# ------------------ - -# CruiseControl.rb can notify you about build status via email. It uses the Action Mailer component of Ruby on Rails -# framework. Obviously, Action Mailer needs to know how to send out email messages. -# If you have an SMTP server on your network, and it needs no authentication, write this in your site_config.rb: -# -ActionMailer::Base.smtp_settings = { - :address => "localhost", - :domain => "ci.rubyonrails.org", -} -# -# If you have no SMTP server at hand, you can configure email notification to use GMail SMTP server, as follows -# (of course, you'll need to create a GMail account): -# -# ActionMailer::Base.smtp_settings = { -# :address => "smtp.gmail.com", -# :port => 587, -# :domain => "yourdomain.com", -# :authentication => :plain, -# :user_name => "yourgmailaccount", -# :password => "yourgmailpassword" -# } -# -# The same approach works for other SMTP servers thet require authentication. Note that GMail's SMTP server runs on a -# non-standard port 587 (standard port for SMTP is 25). -# -# For further details about configuration of outgoing email, see Ruby On Rails documentation for ActionMailer::Base. - -# Other site-wide options are available through Configuration class: - -# Change how often CC.rb pings Subversion for new requests. Default is 10.seconds, which should be OK for a local -# SVN repository, but probably isn't very polite for a public repository, such as RubyForge. This can also be set for -# each project individually, through project.scheduler.polling_interval option: -# Configuration.default_polling_interval = 1.minute - -# How often the dashboard page refreshes itself. If you have more than 10-20 dashboards open, -# it is advisable to set it to something higher than the default 5 seconds: -Configuration.dashboard_refresh_interval = 60.seconds - -# Site-wide setting for the email "from" field. This can also be set on per-project basis, -# through project.email.notifier.from attribute -Configuration.email_from = 'rails-ci@wyeworks.com' - -# Root URL of the dashboard application. Setting this attribute allows various notifiers to include a link to the -# build page in the notification message. -Configuration.dashboard_url = 'http://rails-ci.wyeworks.com/' - -# If you don't want to allow triggering builds through dashboard Build Now button. Useful when you host CC.rb as a -# public web site (such as http://cruisecontrolrb.thoughtworks.com/projects - try clicking on Build Now button there -# and see what happens): -Configuration.disable_build_now = true - -# If you want to only allow one project to build at a time, uncomment this line -# by default, cruise allows multiple projects to build at a time -Configuration.serialize_builds = true - -# Amount of time a project will wait to build before failing when build serialization is on -Configuration.serialized_build_timeout = 3.hours - -# To delete build when there are more than a certain number present, uncomment this line - it will make the dashboard -# perform better -BuildReaper.number_of_builds_to_keep = 100 - -# any files that you'd like to override in cruise, keep in ~/.cruise, and copy over when this file is loaded like this -site_css = CRUISE_DATA_ROOT + "/site.css" -FileUtils.cp site_css, Rails.root + "/public/stylesheets/site.css" if File.exists? site_css From b4efff4bac1c66e5af24de86cdb69a058ccf4147 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 26 Jul 2011 19:20:45 -0300 Subject: [PATCH 026/345] Remove blank line --- actionpack/lib/action_dispatch/testing/assertions/response.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/actionpack/lib/action_dispatch/testing/assertions/response.rb b/actionpack/lib/action_dispatch/testing/assertions/response.rb index 33c6cd5221..7381617dd7 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/response.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/response.rb @@ -55,7 +55,6 @@ module ActionDispatch # assert_redirected_to @customer # def assert_redirected_to(options = {}, message=nil) - assert_response(:redirect, message) return true if options == @response.location From 43ef635b95089ec7a6afb74f154286080aef8d5b Mon Sep 17 00:00:00 2001 From: Jonathan del Strother Date: Wed, 27 Jul 2011 00:06:19 +0100 Subject: [PATCH 027/345] Replace unnecessary regexp in Dependencies#load_missing_constant --- activesupport/lib/active_support/dependencies.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb index a60697cb12..8cd4d15e4c 100644 --- a/activesupport/lib/active_support/dependencies.rb +++ b/activesupport/lib/active_support/dependencies.rb @@ -466,7 +466,6 @@ module ActiveSupport #:nodoc: # Load the constant named +const_name+ which is missing from +from_mod+. If # it is not possible to load the constant into from_mod, try its parent module # using const_missing. - THIS_FILE = %r{#{Regexp.escape(__FILE__)}} def load_missing_constant(from_mod, const_name) log_call from_mod, const_name @@ -479,7 +478,7 @@ module ActiveSupport #:nodoc: qualified_name = qualified_name_for from_mod, const_name path_suffix = qualified_name.underscore - trace = caller.reject {|l| l =~ THIS_FILE} + trace = caller.reject {|l| l.starts_with? __FILE__ } name_error = NameError.new("uninitialized constant #{qualified_name}") name_error.set_backtrace(trace) From ba43b9bf5f8a85759939462944f4994c9b1e1ac9 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 26 Jul 2011 17:33:22 -0700 Subject: [PATCH 028/345] fixing wildcard path matching when wildcard is inside parenthesis --- actionpack/lib/action_dispatch/routing/mapper.rb | 2 +- actionpack/test/dispatch/mapper_test.rb | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 003bc1dc2c..ee4d405ce7 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -51,7 +51,7 @@ module ActionDispatch IGNORE_OPTIONS = [:to, :as, :via, :on, :constraints, :defaults, :only, :except, :anchor, :shallow, :shallow_path, :shallow_prefix] ANCHOR_CHARACTERS_REGEX = %r{\A(\\A|\^)|(\\Z|\\z|\$)\Z} SHORTHAND_REGEX = %r{^/[\w/]+$} - WILDCARD_PATH = %r{\*([^/]+)$} + WILDCARD_PATH = %r{\*([^/\)]+)\)?$} def initialize(set, scope, path, options) @set, @scope = set, scope diff --git a/actionpack/test/dispatch/mapper_test.rb b/actionpack/test/dispatch/mapper_test.rb index 81f0efb76e..3316dd03aa 100644 --- a/actionpack/test/dispatch/mapper_test.rb +++ b/actionpack/test/dispatch/mapper_test.rb @@ -35,6 +35,13 @@ module ActionDispatch Mapper.new FakeSet.new end + def test_mapping_requirements + options = { :controller => 'foo', :action => 'bar' } + m = Mapper::Mapping.new FakeSet.new, {}, '/store/:name(*rest)', options + _, _, requirements, _ = m.to_route + assert_equal(/.+?/, requirements[:rest]) + end + def test_map_slash fakeset = FakeSet.new mapper = Mapper.new fakeset From 7868cf8a655ede2003c00ce3a1351da2a01cae5c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 26 Jul 2011 17:45:34 -0700 Subject: [PATCH 029/345] use regular ruby rather than clever ruby --- actionpack/lib/action_dispatch/routing/mapper.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index ee4d405ce7..187e2a8a74 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -105,13 +105,13 @@ module ActionDispatch # controllers with default routes like :controller/:action/:id(.:format), e.g: # GET /admin/products/show/1 # => { :controller => 'admin/products', :action => 'show', :id => '1' } - @options.reverse_merge!(:controller => /.+?/) + @options[:controller] ||= /.+?/ end # Add a constraint for wildcard route to make it non-greedy and match the # optional format part of the route by default if path.match(WILDCARD_PATH) && @options[:format] != false - @options.reverse_merge!(:"#{$1}" => /.+?/) + @options[$1.to_sym] ||= /.+?/ end if @options[:format] == false @@ -264,7 +264,7 @@ module ActionDispatch # because this means it will be matched first. As this is the most popular route # of most Rails applications, this is beneficial. def root(options = {}) - match '/', options.reverse_merge(:as => :root) + match '/', { :as => :root }.merge(options) end # Matches a url pattern to one or more routes. Any symbols in a pattern From 0b987042bf611330609304a22465d0f30f026076 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 26 Jul 2011 17:49:19 -0700 Subject: [PATCH 030/345] simplify conditionals by assuming hash values will never be `false` --- actionpack/lib/action_dispatch/routing/mapper.rb | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 187e2a8a74..53374949ae 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -224,19 +224,11 @@ module ActionDispatch end def default_controller - if @options[:controller] - @options[:controller] - elsif @scope[:controller] - @scope[:controller] - end + @options[:controller] || @scope[:controller] end def default_action - if @options[:action] - @options[:action] - elsif @scope[:action] - @scope[:action] - end + @options[:action] || @scope[:action] end end From 7e1328464518e6cd85ab8a3c413bf811c87ffa48 Mon Sep 17 00:00:00 2001 From: Lachlan Sylvester Date: Wed, 27 Jul 2011 16:59:11 +1000 Subject: [PATCH 031/345] fix some types in schema_test.rb --- activeresource/test/cases/base/schema_test.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/activeresource/test/cases/base/schema_test.rb b/activeresource/test/cases/base/schema_test.rb index 48fdeb13df..d29eaf5fb6 100644 --- a/activeresource/test/cases/base/schema_test.rb +++ b/activeresource/test/cases/base/schema_test.rb @@ -139,7 +139,7 @@ class SchemaTest < ActiveModel::TestCase assert_nothing_raised { Person.schema = new_schema assert_equal new_schema, Person.schema, "should have saved the schema on the class" - assert_equal new_schema, Person.new.schema, "should have mde the schema available to every instance" + assert_equal new_schema, Person.new.schema, "should have made the schema available to every instance" } end @@ -283,8 +283,8 @@ class SchemaTest < ActiveModel::TestCase new_attr_name_two = :another_new_schema_attribute assert Person.schema.blank?, "sanity check - should have a blank class schema" - assert !Person.new.respond_do?(new_attr_name), "sanity check - should not respond to the brand-new attribute yet" - assert !Person.new.respond_do?(new_attr_name_two), "sanity check - should not respond to the brand-new attribute yet" + assert !Person.new.respond_to?(new_attr_name), "sanity check - should not respond to the brand-new attribute yet" + assert !Person.new.respond_to?(new_attr_name_two), "sanity check - should not respond to the brand-new attribute yet" assert_nothing_raised do Person.schema = {new_attr_name.to_s => 'string'} @@ -301,8 +301,8 @@ class SchemaTest < ActiveModel::TestCase assert Person.schema.blank?, "sanity check - should have a blank class schema" - assert !Person.new.respond_do?(new_attr_name), "sanity check - should not respond to the brand-new attribute yet" - assert !Person.new.respond_do?(new_attr_name_two), "sanity check - should not respond to the brand-new attribute yet" + assert !Person.new.respond_to?(new_attr_name), "sanity check - should not respond to the brand-new attribute yet" + assert !Person.new.respond_to?(new_attr_name_two), "sanity check - should not respond to the brand-new attribute yet" assert_nothing_raised do Person.schema { string new_attr_name_two } From 24f0a872e660647fe1abf187748660a77da3fe0a Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Wed, 27 Jul 2011 12:36:00 +0100 Subject: [PATCH 032/345] Add a proxy_association method to association proxies, which can be called by association extensions to access information about the association. This replaces proxy_owner etc with proxy_association.owner. --- activerecord/CHANGELOG | 6 ++++++ activerecord/lib/active_record/associations.rb | 6 ++++++ .../associations/collection_proxy.rb | 16 ++++++++++------ activerecord/test/cases/associations_test.rb | 5 +++++ 4 files changed, 27 insertions(+), 6 deletions(-) diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index e448609cf4..e8d4b9c04e 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -24,6 +24,12 @@ a URI that specifies the connection configuration. For example: *Rails 3.1.0 (unreleased)* +* Add a proxy_association method to association proxies, which can be called by association + extensions to access information about the association. This replaces proxy_owner etc with + proxy_association.owner. + + [Jon Leighton] + * ActiveRecord::MacroReflection::AssociationReflection#build_record has a new method signature. Before: def build_association(*options) diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 029d7a9b15..2605a54cb6 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -460,6 +460,12 @@ module ActiveRecord # * record.association(:items).target - Returns the associated object for +belongs_to+ and +has_one+, or # the collection of associated objects for +has_many+ and +has_and_belongs_to_many+. # + # However, inside the actual extension code, you will not have access to the record as + # above. In this case, you can access proxy_association. For example, + # record.association(:items) and record.items.proxy_association will return + # the same object, allowing you to make calls like proxy_association.owner inside + # association extensions. + # # === Association Join Models # # Has Many associations can be configured with the :through option to use an diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index 827dfb7ccb..6ba3d45aff 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -58,23 +58,27 @@ module ActiveRecord alias_method :new, :build + def proxy_association + @association + end + def respond_to?(name, include_private = false) super || (load_target && target.respond_to?(name, include_private)) || - @association.klass.respond_to?(name, include_private) + proxy_association.klass.respond_to?(name, include_private) end def method_missing(method, *args, &block) match = DynamicFinderMatch.match(method) if match && match.instantiator? send(:find_or_instantiator_by_attributes, match, match.attribute_names, *args) do |r| - @association.send :set_owner_attributes, r - @association.send :add_to_target, r + proxy_association.send :set_owner_attributes, r + proxy_association.send :add_to_target, r yield(r) if block_given? end end - if target.respond_to?(method) || (!@association.klass.respond_to?(method) && Class.respond_to?(method)) + if target.respond_to?(method) || (!proxy_association.klass.respond_to?(method) && Class.respond_to?(method)) if load_target if target.respond_to?(method) target.send(method, *args, &block) @@ -104,7 +108,7 @@ module ActiveRecord alias_method :to_a, :to_ary def <<(*records) - @association.concat(records) && self + proxy_association.concat(records) && self end alias_method :push, :<< @@ -114,7 +118,7 @@ module ActiveRecord end def reload - @association.reload + proxy_association.reload self end end diff --git a/activerecord/test/cases/associations_test.rb b/activerecord/test/cases/associations_test.rb index 49d82ba2df..ffe2993e0f 100644 --- a/activerecord/test/cases/associations_test.rb +++ b/activerecord/test/cases/associations_test.rb @@ -203,6 +203,11 @@ class AssociationProxyTest < ActiveRecord::TestCase assert_equal david.projects, david.projects.reload.reload end end + + def test_proxy_association_accessor + david = developers(:david) + assert_equal david.association(:projects), david.projects.proxy_association + end end class OverridingAssociationsTest < ActiveRecord::TestCase From 9a298a162c16e019fe6971e563e7f4916e86ced6 Mon Sep 17 00:00:00 2001 From: Dmitriy Kiriyenko Date: Tue, 5 Jul 2011 13:17:39 +0300 Subject: [PATCH 033/345] Fixed failing query when performing calculation with having based on select. --- activerecord/lib/active_record/relation/calculations.rb | 1 + activerecord/test/cases/calculations_test.rb | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb index 0ac821b2d7..9a7ff87e88 100644 --- a/activerecord/lib/active_record/relation/calculations.rb +++ b/activerecord/lib/active_record/relation/calculations.rb @@ -250,6 +250,7 @@ module ActiveRecord operation, distinct).as(aggregate_alias) ] + select_values += @select_values unless @having_values.empty? select_values.concat group_fields.zip(group_aliases).map { |field,aliaz| "#{field} AS #{aliaz}" diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb index 224b3f3d1f..42f98b3d42 100644 --- a/activerecord/test/cases/calculations_test.rb +++ b/activerecord/test/cases/calculations_test.rb @@ -170,6 +170,13 @@ class CalculationsTest < ActiveRecord::TestCase assert_equal 60, c[2] end + def test_should_group_by_summed_field_having_condition_from_select + c = Account.select("MIN(credit_limit) AS min_credit_limit").group(:firm_id).having("min_credit_limit > 50").sum(:credit_limit) + assert_nil c[1] + assert_equal 60, c[2] + assert_equal 53, c[9] + end + def test_should_group_by_summed_association c = Account.sum(:credit_limit, :group => :firm) assert_equal 50, c[companies(:first_firm)] From 8faeed1d7174cc9c357dbf55bb55d8a1a221eaca Mon Sep 17 00:00:00 2001 From: Christos Zisopoulos Date: Wed, 27 Jul 2011 16:12:22 +0200 Subject: [PATCH 034/345] Improve performance and memory usage for options_for_select with Ruby 1.8.7 --- actionpack/lib/action_view/helpers/form_options_helper.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb index 7c43dc04e0..c677257d60 100644 --- a/actionpack/lib/action_view/helpers/form_options_helper.rb +++ b/actionpack/lib/action_view/helpers/form_options_helper.rb @@ -323,12 +323,12 @@ module ActionView return container if String === container selected, disabled = extract_selected_and_disabled(selected).map do | r | - Array.wrap(r).map(&:to_s) + Array.wrap(r).map { |item| item.to_s } end container.map do |element| html_attributes = option_html_attributes(element) - text, value = option_text_and_value(element).map(&:to_s) + text, value = option_text_and_value(element).map { |item| item.to_s } selected_attribute = ' selected="selected"' if option_value_selected?(value, selected) disabled_attribute = ' disabled="disabled"' if disabled && option_value_selected?(value, disabled) %() From efe4cbe5f273dc5eb16dda9a9363a8dd7c6b3bad Mon Sep 17 00:00:00 2001 From: thedarkone Date: Wed, 27 Jul 2011 18:07:47 +0200 Subject: [PATCH 035/345] Handle the empty array correctly. --- activemodel/lib/active_model/errors.rb | 2 +- activemodel/test/cases/errors_test.rb | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb index 71ece15b71..1cf8144e98 100644 --- a/activemodel/lib/active_model/errors.rb +++ b/activemodel/lib/active_model/errors.rb @@ -86,7 +86,7 @@ module ActiveModel # Do the error messages include an error with key +error+? def include?(error) - messages.include? error + (v = messages[error]) && v.any? end # Get messages for +key+ diff --git a/activemodel/test/cases/errors_test.rb b/activemodel/test/cases/errors_test.rb index a24cac40ad..85ca8ca835 100644 --- a/activemodel/test/cases/errors_test.rb +++ b/activemodel/test/cases/errors_test.rb @@ -38,6 +38,7 @@ class ErrorsTest < ActiveModel::TestCase person.errors[:foo] assert person.errors.empty? assert person.errors.blank? + assert !person.errors.include?(:foo) end test "method validate! should work" do From 18d307ed94ee9a8cd2dca117597f9e6afd1b6faa Mon Sep 17 00:00:00 2001 From: Samer Masry Date: Wed, 27 Jul 2011 10:17:25 -0700 Subject: [PATCH 036/345] Reverse order fix when using function for ActiveRecord::QueryMethods Fixes #1697 --- activerecord/lib/active_record/relation/query_methods.rb | 2 +- activerecord/test/cases/relations_test.rb | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 1654ae1eac..3a7b245c51 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -312,7 +312,7 @@ module ActiveRecord when String, Symbol o.to_s.split(',').collect do |s| s.strip! - s.gsub!(/\sasc\Z/i, ' DESC') || s.gsub!(/\sdesc\Z/i, ' ASC') || s.concat(' DESC') + (s if s =~ /\(/) || s.gsub!(/\sasc\Z/i, ' DESC') || s.gsub!(/\sdesc\Z/i, ' ASC') || s.concat(' DESC') end else o diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index 821da91f0a..8a2cf0ef85 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -911,6 +911,11 @@ class RelationTest < ActiveRecord::TestCase assert_equal 'zyke', FastCar.order_using_old_style.limit(1).first.name end + def test_order_with_function_and_last + authors = Author.scoped + assert_equal authors(:bob), authors.order( "id asc, MAX( organization_id, owned_essay_id)" ).last + end + def test_order_using_scoping car1 = CoolCar.order('id DESC').scoping do CoolCar.find(:first, :order => 'id asc') From 5eeae68657e8d6db58f33b5c8629b94878e03990 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Wed, 27 Jul 2011 13:21:59 -0700 Subject: [PATCH 037/345] contrib app minor tweak --- actionpack/CHANGELOG | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 9888be07a9..3b323b3899 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -2270,7 +2270,7 @@ superclass' view_paths. [Rick Olson] * Update documentation for erb trim syntax. #5651 [matt@mattmargolis.net] -* Pass :id => nil or :class => nil to error_messages_for to supress that html attribute. #3586 [olivier_ansaldi@yahoo.com, sebastien@goetzilla.info] +* Pass :id => nil or :class => nil to error_messages_for to supress that html attribute. #3586 [olivier_ansaldi@yahoo.com] * Reset @html_document between requests so assert_tag works. #4810 [Jarkko Laine, easleydp@gmail.com] @@ -2867,7 +2867,7 @@ superclass' view_paths. [Rick Olson] * Provide support for decimal columns to form helpers. Closes #5672. [Dave Thomas] -* Pass :id => nil or :class => nil to error_messages_for to supress that html attribute. #3586 [olivier_ansaldi@yahoo.com, sebastien@goetzilla.info] +* Pass :id => nil or :class => nil to error_messages_for to supress that html attribute. #3586 [olivier_ansaldi@yahoo.com] * Reset @html_document between requests so assert_tag works. #4810 [Jarkko Laine, easleydp@gmail.com] From 8248052ee74465abfae5b202270e96c9fd93e785 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Wed, 27 Jul 2011 15:09:42 -0500 Subject: [PATCH 038/345] Make Rails.application.assets available in initializers --- actionpack/lib/sprockets/railtie.rb | 82 +++++++++++++---------------- 1 file changed, 37 insertions(+), 45 deletions(-) diff --git a/actionpack/lib/sprockets/railtie.rb b/actionpack/lib/sprockets/railtie.rb index 83799d2b4d..c8438e6043 100644 --- a/actionpack/lib/sprockets/railtie.rb +++ b/actionpack/lib/sprockets/railtie.rb @@ -11,15 +11,20 @@ module Sprockets load "sprockets/assets.rake" end - # We need to configure this after initialization to ensure we collect - # paths from all engines. This hook is invoked exactly before routes - # are compiled, and so that other Railties have an opportunity to - # register compressors. - config.after_initialize do |app| - assets = app.config.assets - next unless assets.enabled + initializer "sprockets.environment" do |app| + config = app.config + next unless config.assets.enabled - app.assets = asset_environment(app) + require 'sprockets' + + app.assets = Sprockets::Environment.new(app.root.to_s) do |env| + env.static_root = File.join(app.root.join('public'), config.assets.prefix) + env.logger = ::Rails.logger + + if config.assets.cache_store != false + env.cache = ActiveSupport::Cache.lookup_store(config.assets.cache_store) || ::Rails.cache + end + end ActiveSupport.on_load(:action_view) do include ::Sprockets::Helpers::RailsHelper @@ -28,9 +33,32 @@ module Sprockets include ::Sprockets::Helpers::RailsHelper end end + end + + # We need to configure this after initialization to ensure we collect + # paths from all engines. This hook is invoked exactly before routes + # are compiled, and so that other Railties have an opportunity to + # register compressors. + config.after_initialize do |app| + next unless app.assets + config = app.config + + config.assets.paths.each { |path| app.assets.append_path(path) } + + if config.assets.compress + # temporarily hardcode default JS compressor to uglify. Soon, it will work + # the same as SCSS, where a default plugin sets the default. + unless config.assets.js_compressor == false + app.assets.js_compressor = LazyCompressor.new { expand_js_compressor(config.assets.js_compressor || :uglifier) } + end + + unless config.assets.css_compressor == false + app.assets.css_compressor = LazyCompressor.new { expand_css_compressor(config.assets.css_compressor) } + end + end app.routes.prepend do - mount app.assets => assets.prefix + mount app.assets => config.assets.prefix end if config.action_controller.perform_caching @@ -39,42 +67,6 @@ module Sprockets end protected - def asset_environment(app) - require "sprockets" - - assets = app.config.assets - - env = Sprockets::Environment.new(app.root.to_s) - - env.static_root = File.join(app.root.join("public"), assets.prefix) - - if env.respond_to?(:append_path) - assets.paths.each { |path| env.append_path(path) } - else - env.paths.concat assets.paths - end - - env.logger = ::Rails.logger - - if env.respond_to?(:cache) && assets.cache_store != false - env.cache = ActiveSupport::Cache.lookup_store(assets.cache_store) || ::Rails.cache - end - - if assets.compress - # temporarily hardcode default JS compressor to uglify. Soon, it will work - # the same as SCSS, where a default plugin sets the default. - unless assets.js_compressor == false - env.js_compressor = LazyCompressor.new { expand_js_compressor(assets.js_compressor || :uglifier) } - end - - unless assets.css_compressor == false - env.css_compressor = LazyCompressor.new { expand_css_compressor(assets.css_compressor) } - end - end - - env - end - def expand_js_compressor(sym) case sym when :closure From dee81155395658880ea125426036425250849298 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 28 Jul 2011 09:56:42 +0200 Subject: [PATCH 039/345] Rename class method to_path to _to_path and make it explicit that it is an internal method. --- actionpack/lib/action_view/helpers/form_helper.rb | 4 ++-- activemodel/lib/active_model/conversion.rb | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index 7ea2ea2d5a..85dea96bbb 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -1227,12 +1227,12 @@ module ActionView parent_builder.multipart = multipart if parent_builder end - def self.to_path + def self._to_path @_to_path ||= name.demodulize.underscore.sub!(/_builder$/, '') end def to_path - self.class.to_path + self.class._to_path end def to_model diff --git a/activemodel/lib/active_model/conversion.rb b/activemodel/lib/active_model/conversion.rb index dca1c1aa44..39977f12c3 100644 --- a/activemodel/lib/active_model/conversion.rb +++ b/activemodel/lib/active_model/conversion.rb @@ -55,11 +55,13 @@ module ActiveModel # Returns a string identifying the path associated with the object. # ActionPack uses this to find a suitable partial to represent the object. def to_path - self.class.to_path + self.class._to_path end - module ClassMethods - def to_path + module ClassMethods #:nodoc: + # Provide a class level cache for the to_path. This is an + # internal method and should not be accessed directly. + def _to_path #:nodoc: @_to_path ||= begin element = ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(self)) collection = ActiveSupport::Inflector.tableize(self) From d5eeacc95f116d438210469b6be573913f562b08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 28 Jul 2011 10:01:55 +0200 Subject: [PATCH 040/345] Move the cache to a nested hash which performs better than a hash with array as keys. --- .../action_view/renderer/partial_renderer.rb | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/actionpack/lib/action_view/renderer/partial_renderer.rb b/actionpack/lib/action_view/renderer/partial_renderer.rb index fc8a6b3107..f67388b8cf 100644 --- a/actionpack/lib/action_view/renderer/partial_renderer.rb +++ b/actionpack/lib/action_view/renderer/partial_renderer.rb @@ -206,6 +206,14 @@ module ActionView # <%- end -%> # <% end %> class PartialRenderer < AbstractRenderer #:nodoc: + PARTIAL_NAMES = Hash.new { |h,k| h[k] = {} } + + def initialize(*) + super + @context_prefix = @lookup_context.prefixes.first + @partial_names = PARTIAL_NAMES[@context_prefix] + end + def render(context, options, block) setup(context, options, block) @@ -284,6 +292,7 @@ module ActionView else paths.map! { |path| retrieve_variable(path).unshift(path) } end + if String === partial && @variable.to_s !~ /^[a-z_][a-zA-Z_0-9]*$/ raise ArgumentError.new("The partial name (#{partial}) is not a valid Ruby identifier; " + "make sure your partial name starts with a letter or underscore, " + @@ -352,21 +361,18 @@ module ActionView segments end - PARTIAL_PATHS = {} - def partial_path(object = @object) object = object.to_model if object.respond_to?(:to_model) path = if object.respond_to?(:to_path) - object.to_path - else - ActiveSupport::Deprecation.warn "ActiveModel-compatible objects whose classes return a #model_name that responds to #partial_path are deprecated. Please respond to #to_path directly instead." - object.class.model_name.partial_path - end + object.to_path + else + ActiveSupport::Deprecation.warn "ActiveModel-compatible objects whose classes return a #model_name that responds to #partial_path are deprecated. Please respond to #to_path directly instead." + object.class.model_name.partial_path + end - prefix = @lookup_context.prefixes.first - PARTIAL_PATHS[ [path, prefix] ] ||= path.dup.tap do |object_path| - merge_prefix_into_object_path(prefix, object_path) + @partial_names[path] ||= path.dup.tap do |object_path| + merge_prefix_into_object_path(@context_prefix, object_path) end end From 30dae273c85a988a39d9b1dec701c0a48267cd5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 28 Jul 2011 10:05:17 +0200 Subject: [PATCH 041/345] Update CHANGELOG. --- activemodel/CHANGELOG | 2 ++ 1 file changed, 2 insertions(+) diff --git a/activemodel/CHANGELOG b/activemodel/CHANGELOG index c38349b95e..81386667c2 100644 --- a/activemodel/CHANGELOG +++ b/activemodel/CHANGELOG @@ -1,3 +1,5 @@ +* Deprecate "Model.model_name.partial_path" in favor of "model.to_path" [Grant Hutchins] + * Provide mass_assignment_sanitizer as an easy API to replace the sanitizer behavior. Also support both :logger (default) and :strict sanitizer behavior [Bogdan Gusiev] *Rails 3.1.0 (unreleased)* From b93a918337e99c3fe3ad059f093b1ee56b9e6a7d Mon Sep 17 00:00:00 2001 From: Bogdan Gusiev Date: Thu, 28 Jul 2011 11:56:08 +0300 Subject: [PATCH 042/345] MassAssignmentProtection: consider 'id' insensetive in StrictSanitizer In order to use StrictSanitizer in test mode Consider :id as not sensetive attribute that can be filtered from mass assignement without exception. --- .../active_model/mass_assignment_security/sanitizer.rb | 5 +++++ .../cases/mass_assignment_security/sanitizer_test.rb | 10 +++++++++- .../rails/app/templates/config/environments/test.rb.tt | 5 +++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/activemodel/lib/active_model/mass_assignment_security/sanitizer.rb b/activemodel/lib/active_model/mass_assignment_security/sanitizer.rb index bb0526adc3..bbdddfb50d 100644 --- a/activemodel/lib/active_model/mass_assignment_security/sanitizer.rb +++ b/activemodel/lib/active_model/mass_assignment_security/sanitizer.rb @@ -44,8 +44,13 @@ module ActiveModel class StrictSanitizer < Sanitizer def process_removed_attributes(attrs) + return if (attrs - insensitive_attributes).empty? raise ActiveModel::MassAssignmentSecurity::Error, "Can't mass-assign protected attributes: #{attrs.join(', ')}" end + + def insensitive_attributes + ['id'] + end end class Error < StandardError diff --git a/activemodel/test/cases/mass_assignment_security/sanitizer_test.rb b/activemodel/test/cases/mass_assignment_security/sanitizer_test.rb index 62a6ec9c9b..676937b5e1 100644 --- a/activemodel/test/cases/mass_assignment_security/sanitizer_test.rb +++ b/activemodel/test/cases/mass_assignment_security/sanitizer_test.rb @@ -7,7 +7,7 @@ class SanitizerTest < ActiveModel::TestCase class Authorizer < ActiveModel::MassAssignmentSecurity::PermissionSet def deny?(key) - key.in?(['admin']) + ['admin', 'id'].include?(key) end end @@ -40,4 +40,12 @@ class SanitizerTest < ActiveModel::TestCase end end + test "mass assignment insensitive attributes" do + original_attributes = {'id' => 1, 'first_name' => 'allowed'} + + assert_nothing_raised do + @strict_sanitizer.sanitize(original_attributes, @authorizer) + end + end + end diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt index ee068b0202..80198cc21e 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt @@ -34,6 +34,11 @@ # like if you have constraints or database-specific column types # config.active_record.schema_format = :sql + <%- unless options.skip_active_record? -%> + # Raise exception on mass assignment protection for ActiveRecord models + config.active_record.mass_assignment_sanitizer = :strict + <%- end -%> + # Print deprecation notices to the stderr config.active_support.deprecation = :stderr end From 971a74b81f37ec82e06056b738a7215185c51ee6 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Thu, 28 Jul 2011 13:14:11 +0100 Subject: [PATCH 043/345] Revert "Merge pull request #2309 from smasry/master" This reverts commit 9d396ee8195e31f646e0b89158ed96f4db4ab38f, reversing changes made to fa2bfd832c1d1e997d93c2269a485cc74782c86d. Reason: the change broke the build. --- activerecord/lib/active_record/relation/query_methods.rb | 2 +- activerecord/test/cases/relations_test.rb | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 3a7b245c51..1654ae1eac 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -312,7 +312,7 @@ module ActiveRecord when String, Symbol o.to_s.split(',').collect do |s| s.strip! - (s if s =~ /\(/) || s.gsub!(/\sasc\Z/i, ' DESC') || s.gsub!(/\sdesc\Z/i, ' ASC') || s.concat(' DESC') + s.gsub!(/\sasc\Z/i, ' DESC') || s.gsub!(/\sdesc\Z/i, ' ASC') || s.concat(' DESC') end else o diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index 8a2cf0ef85..821da91f0a 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -911,11 +911,6 @@ class RelationTest < ActiveRecord::TestCase assert_equal 'zyke', FastCar.order_using_old_style.limit(1).first.name end - def test_order_with_function_and_last - authors = Author.scoped - assert_equal authors(:bob), authors.order( "id asc, MAX( organization_id, owned_essay_id)" ).last - end - def test_order_using_scoping car1 = CoolCar.order('id DESC').scoping do CoolCar.find(:first, :order => 'id asc') From 5515a18aa52df3f71ed4d29fbcc0dc2819e39d5e Mon Sep 17 00:00:00 2001 From: Dan Gebhardt Date: Tue, 26 Jul 2011 17:25:32 -0400 Subject: [PATCH 044/345] Expanded meta-data in gemspec to include author, email, etc.; Defaults include "TODO" to prevent gems from being built without review. --- .../rails/plugin_new/templates/%name%.gemspec | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec b/railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec index eb1a1e5054..b469edd772 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec +++ b/railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec @@ -1,12 +1,16 @@ # Provide a simple gemspec so you can easily use your # project in your rails apps through git. Gem::Specification.new do |s| - s.name = "<%= name %>" - s.summary = "Insert <%= camelized %> summary." - s.description = "Insert <%= camelized %> description." + s.name = "<%= name %>" + s.version = "0.0.1" + s.authors = ["TODO: Your name"] + s.email = ["TODO: Your email"] + s.homepage = "TODO" + s.summary = "TODO: Summary of <%= camelized %>." + s.description = "TODO: Description of <%= camelized %>." + s.files = Dir["{app,config,db,lib}/**/*"] + ["MIT-LICENSE", "Rakefile", "README.rdoc"] <% unless options.skip_test_unit? -%> s.test_files = Dir["test/**/*"] <% end -%> - s.version = "0.0.1" end From d9b59c341c5cc5848a42e936588a67130bf7ff4a Mon Sep 17 00:00:00 2001 From: Dan Gebhardt Date: Tue, 26 Jul 2011 18:51:44 -0400 Subject: [PATCH 045/345] Extracted version from gemspec and placed it in its own file. This is consistent with the approach taken by "bundle gem", and is expected by gems such as svenfuchs/gem-release which can be used to bump / tag versions of gems. --- .../rails/plugin_new/plugin_new_generator.rb | 1 + .../rails/plugin_new/templates/%name%.gemspec | 10 +++++++--- .../rails/plugin_new/templates/lib/%name%/version.rb | 3 +++ 3 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%/version.rb diff --git a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb index 7c0a2b9cf4..56b1587760 100644 --- a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb +++ b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb @@ -46,6 +46,7 @@ module Rails def lib template "lib/%name%.rb" template "lib/tasks/%name%_tasks.rake" + template "lib/%name%/version.rb" if full? template "lib/%name%/engine.rb" end diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec b/railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec index b469edd772..736d114901 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec +++ b/railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec @@ -1,8 +1,12 @@ -# Provide a simple gemspec so you can easily use your -# project in your rails apps through git. +$:.push File.expand_path("../lib", __FILE__) + +# Maintain your gem's version: +require "<%= name %>/version" + +# Describe your gem and declare its dependencies: Gem::Specification.new do |s| s.name = "<%= name %>" - s.version = "0.0.1" + s.version = <%= camelized %>::VERSION s.authors = ["TODO: Your name"] s.email = ["TODO: Your email"] s.homepage = "TODO" diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%/version.rb b/railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%/version.rb new file mode 100644 index 0000000000..ef07ef2e19 --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin_new/templates/lib/%name%/version.rb @@ -0,0 +1,3 @@ +module <%= camelized %> + VERSION = "0.0.1" +end From a74e4736f95befa7a22c208019bf11a155ff7543 Mon Sep 17 00:00:00 2001 From: Dan Gebhardt Date: Tue, 26 Jul 2011 21:54:45 -0400 Subject: [PATCH 046/345] Moved dependencies from Gemfile to gemspec to eliminate redundant declarations. --- .../rails/plugin_new/templates/%name%.gemspec | 11 ++++++++++ .../rails/plugin_new/templates/Gemfile | 20 ++++++++++++------- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec b/railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec index 736d114901..b8d68ad0bc 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec +++ b/railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec @@ -17,4 +17,15 @@ Gem::Specification.new do |s| <% unless options.skip_test_unit? -%> s.test_files = Dir["test/**/*"] <% end -%> + + # If your gem is dependent on a specific version (or higher) of Rails: + <%= '# ' if options.dev? || options.edge? -%>s.add_dependency "rails", ">= <%= Rails::VERSION::STRING %>" + +<% unless options[:skip_javascript] || !full? -%> + # If your gem contains any <%= "#{options[:javascript]}-specific" %> javascript: + # s.add_dependency "<%= "#{options[:javascript]}-rails" %>" + +<% end -%> + # Declare development-specific dependencies: + s.add_development_dependency "<%= gem_for_database %>" end diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile b/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile index 7e6eb18341..160baa6906 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile +++ b/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile @@ -1,14 +1,20 @@ source "http://rubygems.org" +# Declare your gem's dependencies in <%= name %>.gemspec. +# Bundler will treat runtime dependencies like base dependencies, and +# development dependencies will be added by default to the :development group. +gemspec + +# Declare any dependencies that are still in development here instead of in +# your gemspec. These might include edge Rails or gems from your path or +# Git. Remember to move these dependencies to your gemspec before releasing +# your gem to rubygems.org. + +<% if options.dev? || options.edge? -%> +# Your gem is dependent on dev or edge Rails. Once you can lock this +# dependency down to a specific version, move it to your gemspec. <%= rails_gemfile_entry -%> -<% if full? -%> -<%= database_gemfile_entry -%> <% end -%> - -<% if mountable? -%> -<%= javascript_gemfile_entry -%> -<% end -%> - # To use debugger # <%= ruby_debugger_gemfile_entry %> \ No newline at end of file From d10f268d2057a4e9d46bd003afeceb4e910d1153 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 28 Jul 2011 11:48:21 -0300 Subject: [PATCH 047/345] Tidy up a bit plugin new gemspec --- .../rails/plugin_new/templates/%name%.gemspec | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec b/railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec index b8d68ad0bc..8588e88077 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec +++ b/railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec @@ -18,14 +18,10 @@ Gem::Specification.new do |s| s.test_files = Dir["test/**/*"] <% end -%> - # If your gem is dependent on a specific version (or higher) of Rails: - <%= '# ' if options.dev? || options.edge? -%>s.add_dependency "rails", ">= <%= Rails::VERSION::STRING %>" - -<% unless options[:skip_javascript] || !full? -%> - # If your gem contains any <%= "#{options[:javascript]}-specific" %> javascript: + <%= '# ' if options.dev? || options.edge? -%>s.add_dependency "rails", "~> <%= Rails::VERSION::STRING %>" +<% if full? && !options[:skip_javascript] -%> # s.add_dependency "<%= "#{options[:javascript]}-rails" %>" - <% end -%> - # Declare development-specific dependencies: + s.add_development_dependency "<%= gem_for_database %>" end From 5a4e8f5514a65c583f54d52e476d1bebcd5785e3 Mon Sep 17 00:00:00 2001 From: Vishnu Atrai Date: Thu, 28 Jul 2011 21:14:29 +0530 Subject: [PATCH 048/345] pluging generator test fix --- .../test/generators/plugin_new_generator_test.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_new_generator_test.rb index 0ccb2ae9da..e6ea1cbc33 100644 --- a/railties/test/generators/plugin_new_generator_test.rb +++ b/railties/test/generators/plugin_new_generator_test.rb @@ -69,13 +69,13 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase def test_database_entry_is_generated_for_sqlite3_by_default_in_full_mode run_generator([destination_root, "--full"]) assert_file "test/dummy/config/database.yml", /sqlite/ - assert_file "Gemfile", /^gem\s+["']sqlite3["']$/ + assert_file "bukkits.gemspec", /sqlite3/ end def test_config_another_database run_generator([destination_root, "-d", "mysql", "--full"]) assert_file "test/dummy/config/database.yml", /mysql/ - assert_file "Gemfile", /^gem\s+["']mysql2["']$/ + assert_file "bukkits.gemspec", /mysql/ end def test_active_record_is_removed_from_frameworks_if_skip_active_record_is_given @@ -117,8 +117,8 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase assert_match %r{^//= require jquery}, contents assert_match %r{^//= require jquery_ujs}, contents end - assert_file 'Gemfile' do |contents| - assert_match(/^gem 'jquery-rails'/, contents) + assert_file 'bukkits.gemspec' do |contents| + assert_match(/jquery-rails/, contents) end end @@ -128,8 +128,8 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase assert_match %r{^//= require prototype}, contents assert_match %r{^//= require prototype_ujs}, contents end - assert_file 'Gemfile' do |contents| - assert_match(/^gem 'prototype-rails'/, contents) + assert_file 'bukkits.gemspec' do |contents| + assert_match(/prototype-rails/, contents) end end @@ -205,10 +205,10 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase def test_creating_gemspec run_generator - assert_file "bukkits.gemspec", /s.name = "bukkits"/ + assert_file "bukkits.gemspec", /s.name\s+= "bukkits"/ assert_file "bukkits.gemspec", /s.files = Dir\["\{app,config,db,lib\}\/\*\*\/\*"\]/ assert_file "bukkits.gemspec", /s.test_files = Dir\["test\/\*\*\/\*"\]/ - assert_file "bukkits.gemspec", /s.version = "0.0.1"/ + assert_file "bukkits.gemspec", /s.version\s+ = Bukkits::VERSION/ end def test_usage_of_engine_commands From ad0772f2683792a656d084ce676775f272158801 Mon Sep 17 00:00:00 2001 From: Franck Verrot Date: Thu, 28 Jul 2011 18:45:43 +0300 Subject: [PATCH 049/345] We don't need to require erb here. --- actionpack/lib/action_dispatch/routing/mapper.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 53374949ae..95273ec2fd 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -1,4 +1,3 @@ -require 'erb' require 'active_support/core_ext/hash/except' require 'active_support/core_ext/object/blank' require 'active_support/core_ext/object/inclusion' From b407034c9daf8103c99739bc6b96ed9b3ea13eaa Mon Sep 17 00:00:00 2001 From: Grant Hutchins Date: Thu, 28 Jul 2011 13:38:28 -0300 Subject: [PATCH 050/345] Give attribution to Peter Jaros for the patch we paired on. --- activemodel/CHANGELOG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activemodel/CHANGELOG b/activemodel/CHANGELOG index 81386667c2..597f5ab395 100644 --- a/activemodel/CHANGELOG +++ b/activemodel/CHANGELOG @@ -1,4 +1,4 @@ -* Deprecate "Model.model_name.partial_path" in favor of "model.to_path" [Grant Hutchins] +* Deprecate "Model.model_name.partial_path" in favor of "model.to_path" [Grant Hutchins, Peter Jaros] * Provide mass_assignment_sanitizer as an easy API to replace the sanitizer behavior. Also support both :logger (default) and :strict sanitizer behavior [Bogdan Gusiev] From 4d4d2179f68ecda5736feb6cccd897b73653bce9 Mon Sep 17 00:00:00 2001 From: thedarkone Date: Thu, 28 Jul 2011 20:00:48 +0200 Subject: [PATCH 051/345] There is no need to be destructive with the passed-in options. This fixes a bug that is caused by Resource/SingletonResource mangling resource options when using inline "multi"-resource declarations. --- actionpack/lib/action_dispatch/routing/mapper.rb | 12 ++++++------ actionpack/test/controller/resources_test.rb | 9 +++++++++ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 8d071b2061..36d878aee9 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -879,9 +879,9 @@ module ActionDispatch def initialize(entities, options = {}) @name = entities.to_s - @path = (options.delete(:path) || @name).to_s - @controller = (options.delete(:controller) || @name).to_s - @as = options.delete(:as) + @path = (options[:path] || @name).to_s + @controller = (options[:controller] || @name).to_s + @as = options[:as] @options = options end @@ -945,9 +945,9 @@ module ActionDispatch def initialize(entities, options) @as = nil @name = entities.to_s - @path = (options.delete(:path) || @name).to_s - @controller = (options.delete(:controller) || plural).to_s - @as = options.delete(:as) + @path = (options[:path] || @name).to_s + @controller = (options[:controller] || plural).to_s + @as = options[:as] @options = options end diff --git a/actionpack/test/controller/resources_test.rb b/actionpack/test/controller/resources_test.rb index 6ea492cf8b..3b1b5fc3ec 100644 --- a/actionpack/test/controller/resources_test.rb +++ b/actionpack/test/controller/resources_test.rb @@ -91,6 +91,15 @@ class ResourcesTest < ActionController::TestCase end end + def test_multiple_resources_with_options + expected_options = {:controller => 'threads', :action => 'index'} + + with_restful_routing :messages, :comments, expected_options.slice(:controller) do + assert_recognizes(expected_options, :path => 'comments') + assert_recognizes(expected_options, :path => 'messages') + end + end + def test_with_custom_conditions with_restful_routing :messages, :conditions => { :subdomain => 'app' } do assert @routes.recognize_path("/messages", :method => :get, :subdomain => 'app') From a5f57a7ef2af05ac1f7b919040e10c1b21de8e56 Mon Sep 17 00:00:00 2001 From: thedarkone Date: Thu, 28 Jul 2011 20:02:21 +0200 Subject: [PATCH 052/345] Make use of the inherited initializer. --- actionpack/lib/action_dispatch/routing/mapper.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 36d878aee9..cbf97f1b6a 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -943,12 +943,11 @@ module ActionDispatch DEFAULT_ACTIONS = [:show, :create, :update, :destroy, :new, :edit] def initialize(entities, options) + super + @as = nil - @name = entities.to_s - @path = (options[:path] || @name).to_s @controller = (options[:controller] || plural).to_s @as = options[:as] - @options = options end def plural From 54463592cbfd78e1eb03bc1ac90e044dd30900a0 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 28 Jul 2011 16:46:39 -0300 Subject: [PATCH 053/345] Tidy up --- railties/lib/rails/generators/app_base.rb | 6 ++++-- railties/lib/rails/generators/rails/app/templates/Gemfile | 3 --- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index bbdd000ad9..21a2ae4e28 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -200,9 +200,11 @@ module Rails def assets_gemfile_entry <<-GEMFILE.strip_heredoc + # Gems used only for assets and not required + # in production environments by default. group :assets do - gem 'sass-rails', :git => 'git://github.com/rails/sass-rails' - gem 'coffee-rails', :git => 'git://github.com/rails/coffee-rails' + gem 'sass-rails', :git => 'git://github.com/rails/sass-rails.git' + gem 'coffee-rails', :git => 'git://github.com/rails/coffee-rails.git' gem 'uglifier' end GEMFILE diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile index 88eea40b1b..c83e7ddf80 100644 --- a/railties/lib/rails/generators/rails/app/templates/Gemfile +++ b/railties/lib/rails/generators/rails/app/templates/Gemfile @@ -7,10 +7,7 @@ source 'http://rubygems.org' <%= "gem 'jruby-openssl'\n" if defined?(JRUBY_VERSION) -%> <%= "gem 'json'\n" if RUBY_VERSION < "1.9.2" -%> -# Gems used only for assets and not required -# in production environments by default. <%= assets_gemfile_entry %> - <%= javascript_gemfile_entry %> # Use unicorn as the web server From d8e62a93e388c674aa95b32b8688ba6e8366a643 Mon Sep 17 00:00:00 2001 From: Dan Gebhardt Date: Tue, 26 Jul 2011 15:41:08 -0400 Subject: [PATCH 054/345] Include empty app/mailers directory in mountable and full plugins --- .../rails/generators/rails/plugin_new/plugin_new_generator.rb | 1 + .../rails/plugin_new/templates/app/mailers/.empty_directory | 0 2 files changed, 1 insertion(+) create mode 100644 railties/lib/rails/generators/rails/plugin_new/templates/app/mailers/.empty_directory diff --git a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb index 56b1587760..c46422437d 100644 --- a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb +++ b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb @@ -19,6 +19,7 @@ module Rails empty_directory_with_gitkeep "app/controllers" empty_directory_with_gitkeep "app/views" empty_directory_with_gitkeep "app/helpers" + empty_directory_with_gitkeep "app/mailers" empty_directory_with_gitkeep "app/assets/images/#{name}" end end diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/app/mailers/.empty_directory b/railties/lib/rails/generators/rails/plugin_new/templates/app/mailers/.empty_directory new file mode 100644 index 0000000000..e69de29bb2 From 1c94ba03328775a79541e3240ff2469d237b9f3b Mon Sep 17 00:00:00 2001 From: Brian Cardarella Date: Fri, 29 Jul 2011 12:08:35 -0400 Subject: [PATCH 055/345] Instead of removing the instance variable just set it to nil, resolves the warnings because of a missing instance variable --- actionpack/test/template/sprockets_helper_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/actionpack/test/template/sprockets_helper_test.rb b/actionpack/test/template/sprockets_helper_test.rb index b9161b62c5..f4b5344d63 100644 --- a/actionpack/test/template/sprockets_helper_test.rb +++ b/actionpack/test/template/sprockets_helper_test.rb @@ -97,7 +97,7 @@ class SprocketsHelperTest < ActionView::TestCase end test "stylesheets served without a controller in scope cannot access the request" do - remove_instance_variable("@controller") + @controller = nil @config.action_controller.asset_host = Proc.new do |asset, request| fail "This should not have been called." end @@ -107,7 +107,7 @@ class SprocketsHelperTest < ActionView::TestCase end test "stylesheets served without a controller in do not use asset hosts when the default protocol is :request" do - remove_instance_variable("@controller") + @controller = nil @config.action_controller.asset_host = "assets-%d.example.com" @config.action_controller.default_asset_host_protocol = :request @config.action_controller.perform_caching = true From 4fe2c99052928a8669d7bbc70bfdfe059eba67bc Mon Sep 17 00:00:00 2001 From: Arun Agrawal Date: Fri, 29 Jul 2011 22:06:36 +0530 Subject: [PATCH 056/345] Test add for plugin new generator generate mailer --- railties/test/generators/plugin_new_generator_test.rb | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_new_generator_test.rb index e6ea1cbc33..19e80eee89 100644 --- a/railties/test/generators/plugin_new_generator_test.rb +++ b/railties/test/generators/plugin_new_generator_test.rb @@ -25,10 +25,6 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase # brings setup, teardown, and some tests include SharedGeneratorTests - def default_files - ::DEFAULT_PLUGIN_FILES - end - def test_invalid_plugin_name_raises_an_error content = capture(:stderr){ run_generator [File.join(destination_root, "43-things")] } assert_equal "Invalid plugin name 43-things. Please give a name which does not start with numbers.\n", content @@ -176,6 +172,7 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase assert_file "app/controllers" assert_file "app/views" assert_file "app/helpers" + assert_file "app/mailers" assert_file "config/routes.rb", /Rails.application.routes.draw do/ assert_file "lib/bukkits/engine.rb", /module Bukkits\n class Engine < ::Rails::Engine\n end\nend/ assert_file "lib/bukkits.rb", /require "bukkits\/engine"/ @@ -257,6 +254,10 @@ protected silence(:stdout){ generator.send(*args, &block) } end +protected + def default_files + ::DEFAULT_PLUGIN_FILES + end end class CustomPluginGeneratorTest < Rails::Generators::TestCase From 6ef1079e0ed093e54a0e1dc9cb3b97d5e1330caf Mon Sep 17 00:00:00 2001 From: Brian Cardarella Date: Fri, 29 Jul 2011 13:06:45 -0400 Subject: [PATCH 057/345] Reset @dirty to false when slicing an instance of SafeBuffer --- .../lib/active_support/core_ext/string/output_safety.rb | 6 ++++++ activesupport/test/safe_buffer_test.rb | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/activesupport/lib/active_support/core_ext/string/output_safety.rb b/activesupport/lib/active_support/core_ext/string/output_safety.rb index 3bf4edbdef..6d6c4912bb 100644 --- a/activesupport/lib/active_support/core_ext/string/output_safety.rb +++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb @@ -86,6 +86,12 @@ module ActiveSupport #:nodoc: end end + def[](*args) + new_safe_buffer = super + new_safe_buffer.instance_eval { @dirty = false } + new_safe_buffer + end + def safe_concat(value) raise SafeConcatError if dirty? original_concat(value) diff --git a/activesupport/test/safe_buffer_test.rb b/activesupport/test/safe_buffer_test.rb index 7662e9b765..8f77999d25 100644 --- a/activesupport/test/safe_buffer_test.rb +++ b/activesupport/test/safe_buffer_test.rb @@ -106,4 +106,10 @@ class SafeBufferTest < ActiveSupport::TestCase test "should not fail if the returned object is not a string" do assert_kind_of NilClass, @buffer.slice("chipchop") end + + test "Should initialize @dirty to false for new instance when sliced" do + dirty = @buffer[0,0].send(:dirty?) + assert_not_nil dirty + assert !dirty + end end From 6969638020ae04cc4bf63605f603f6fdab9e4b39 Mon Sep 17 00:00:00 2001 From: Vishnu Atrai Date: Fri, 29 Jul 2011 23:05:40 +0530 Subject: [PATCH 058/345] Covering more files in test for plugin new generator. --- railties/test/generators/plugin_new_generator_test.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_new_generator_test.rb index 19e80eee89..b49945f153 100644 --- a/railties/test/generators/plugin_new_generator_test.rb +++ b/railties/test/generators/plugin_new_generator_test.rb @@ -7,11 +7,13 @@ DEFAULT_PLUGIN_FILES = %w( .gitignore Gemfile Rakefile + README.rdoc bukkits.gemspec MIT-LICENSE lib lib/bukkits.rb lib/tasks/bukkits_tasks.rake + lib/bukkits/version.rb test/bukkits_test.rb test/test_helper.rb test/dummy From 3d6e1872550f284dd387ffc87a984a9036376062 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 29 Jul 2011 12:23:37 -0700 Subject: [PATCH 059/345] dump IO encoding value along with schema.rb so the file can be reloaded. fixes #1592 --- activerecord/lib/active_record/schema_dumper.rb | 4 ++++ activerecord/test/cases/schema_dumper_test.rb | 15 ++++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/activerecord/lib/active_record/schema_dumper.rb b/activerecord/lib/active_record/schema_dumper.rb index 19585f6214..6fe305f843 100644 --- a/activerecord/lib/active_record/schema_dumper.rb +++ b/activerecord/lib/active_record/schema_dumper.rb @@ -40,6 +40,10 @@ module ActiveRecord def header(stream) define_params = @version ? ":version => #{@version}" : "" + if stream.respond_to?(:external_encoding) + stream.puts "# encoding: #{stream.external_encoding.name}" + end + stream.puts <
Date: Fri, 29 Jul 2011 12:28:12 -0700 Subject: [PATCH 060/345] default writing the schema file as utf-8 --- activerecord/lib/active_record/railties/databases.rake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index 0ee7e20cf1..ec00f7faad 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -341,7 +341,8 @@ db_namespace = namespace :db do desc 'Create a db/schema.rb file that can be portably used against any DB supported by AR' task :dump => :load_config do require 'active_record/schema_dumper' - File.open(ENV['SCHEMA'] || "#{Rails.root}/db/schema.rb", "w") do |file| + filename = ENV['SCHEMA'] || "#{Rails.root}/db/schema.rb" + File.open(filename, "w:utf-8") do |file| ActiveRecord::Base.establish_connection(Rails.env) ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file) end From ea7f50863d3a1e58a28921b15da3927ad7d18f4a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 29 Jul 2011 14:38:57 -0700 Subject: [PATCH 061/345] delay backtrace scrubbing until we actually raise an exception. fixes #1936 --- activesupport/lib/active_support/dependencies.rb | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb index 8cd4d15e4c..3f6c93e860 100644 --- a/activesupport/lib/active_support/dependencies.rb +++ b/activesupport/lib/active_support/dependencies.rb @@ -478,10 +478,6 @@ module ActiveSupport #:nodoc: qualified_name = qualified_name_for from_mod, const_name path_suffix = qualified_name.underscore - trace = caller.reject {|l| l.starts_with? __FILE__ } - name_error = NameError.new("uninitialized constant #{qualified_name}") - name_error.set_backtrace(trace) - file_path = search_for_file(path_suffix) if file_path && ! loaded.include?(File.expand_path(file_path)) # We found a matching file to load @@ -500,11 +496,12 @@ module ActiveSupport #:nodoc: return parent.const_missing(const_name) rescue NameError => e raise unless e.missing_name? qualified_name_for(parent, const_name) - raise name_error end - else - raise name_error end + + raise NameError, + "uninitialized constant #{qualified_name}", + caller.reject {|l| l.starts_with? __FILE__ } end # Remove the constants that have been autoloaded, and those that have been From a263f377978fc07515b42808ebc1f7894fafaa3a Mon Sep 17 00:00:00 2001 From: Brian Durand Date: Fri, 29 Jul 2011 17:27:45 -0500 Subject: [PATCH 062/345] Change ActiveSupport::Cache behavior to always return duplicate objects instead of frozen objects. --- activesupport/lib/active_support/cache.rb | 27 +++++++++-------------- activesupport/test/caching_test.rb | 17 ++++++++------ 2 files changed, 20 insertions(+), 24 deletions(-) diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb index ac88c82709..2d2264e58a 100644 --- a/activesupport/lib/active_support/cache.rb +++ b/activesupport/lib/active_support/cache.rb @@ -557,15 +557,14 @@ module ActiveSupport @expires_in = options[:expires_in] @expires_in = @expires_in.to_f if @expires_in @created_at = Time.now.to_f - if defined?(value) - if should_compress?(value, options) - @value = Zlib::Deflate.deflate(Marshal.dump(value)) - @compressed = true - else - @value = value - end - else + if value.nil? @value = nil + else + @value = Marshal.dump(value) + if should_compress?(value, options) + @value = Zlib::Deflate.deflate(@value) + @compressed = true + end end end @@ -576,12 +575,8 @@ module ActiveSupport # Get the value stored in the cache. def value - if defined?(@value) - val = compressed? ? Marshal.load(Zlib::Inflate.inflate(@value)) : @value - unless val.frozen? - val.freeze rescue nil - end - val + if @value + Marshal.load(compressed? ? Zlib::Inflate.inflate(@value) : @value) end end @@ -614,10 +609,8 @@ module ActiveSupport def size if @value.nil? 0 - elsif @value.respond_to?(:bytesize) - @value.bytesize else - Marshal.dump(@value).bytesize + @value.bytesize end end diff --git a/activesupport/test/caching_test.rb b/activesupport/test/caching_test.rb index 402c6695aa..dff3d6ef0d 100644 --- a/activesupport/test/caching_test.rb +++ b/activesupport/test/caching_test.rb @@ -204,7 +204,7 @@ module CacheStoreBehavior @cache.write('foo', 'bar', :compress => true) raw_value = @cache.send(:read_entry, 'foo', {}).raw_value assert_equal 'bar', @cache.read('foo') - assert_equal 'bar', raw_value + assert_equal 'bar', Marshal.load(raw_value) end def test_read_and_write_compressed_large_data @@ -270,10 +270,12 @@ module CacheStoreBehavior assert !@cache.exist?('foo') end - def test_store_objects_should_be_immutable + def test_read_should_return_a_different_object_id_each_time_it_is_called @cache.write('foo', 'bar') - assert_raise(ActiveSupport::FrozenObjectError) { @cache.read('foo').gsub!(/.*/, 'baz') } - assert_equal 'bar', @cache.read('foo') + assert_not_equal @cache.read('foo').object_id, @cache.read('foo').object_id + value = @cache.read('foo') + value << 'bingo' + assert_not_equal value, @cache.read('foo') end def test_original_store_objects_should_not_be_immutable @@ -551,7 +553,8 @@ end class MemoryStoreTest < ActiveSupport::TestCase def setup - @cache = ActiveSupport::Cache.lookup_store(:memory_store, :expires_in => 60, :size => 100) + @record_size = Marshal.dump("aaaaaaaaaa").bytesize + @cache = ActiveSupport::Cache.lookup_store(:memory_store, :expires_in => 60, :size => @record_size * 10) end include CacheStoreBehavior @@ -566,7 +569,7 @@ class MemoryStoreTest < ActiveSupport::TestCase @cache.write(5, "eeeeeeeeee") && sleep(0.001) @cache.read(2) && sleep(0.001) @cache.read(4) - @cache.prune(30) + @cache.prune(@record_size * 3) assert_equal true, @cache.exist?(5) assert_equal true, @cache.exist?(4) assert_equal false, @cache.exist?(3) @@ -719,7 +722,7 @@ class CacheEntryTest < ActiveSupport::TestCase def test_non_compress_values entry = ActiveSupport::Cache::Entry.new("value") assert_equal "value", entry.value - assert_equal "value", entry.raw_value + assert_equal "value", Marshal.load(entry.raw_value) assert_equal false, entry.compressed? end end From 1f270e80e61570faafc7cc01c1ed19c1c5359ef3 Mon Sep 17 00:00:00 2001 From: Waynn Lue Date: Fri, 29 Jul 2011 17:07:27 -0700 Subject: [PATCH 063/345] remove redundant calls to stringify_keys --- actionpack/lib/action_view/helpers/form_tag_helper.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index 822686b09d..79f07400b2 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -417,7 +417,7 @@ module ActionView options["data-confirm"] = confirm end - tag :input, { "type" => "submit", "name" => "commit", "value" => value }.update(options.stringify_keys) + tag :input, { "type" => "submit", "name" => "commit", "value" => value }.update(options) end # Creates a button element that defines a submit button, @@ -503,7 +503,7 @@ module ActionView options["data-confirm"] = confirm end - tag :input, { "type" => "image", "src" => path_to_image(source) }.update(options.stringify_keys) + tag :input, { "type" => "image", "src" => path_to_image(source) }.update(options) end # Creates a field set for grouping HTML form elements. From e7330f3d4fa97c683a49457239402f826d8016b7 Mon Sep 17 00:00:00 2001 From: Brian Cardarella Date: Sat, 30 Jul 2011 12:08:26 -0400 Subject: [PATCH 064/345] Resolve warnings by instantizing @attrubtes as nil --- activerecord/test/cases/attribute_methods_test.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb index b0896fb236..dbf5a1ba76 100644 --- a/activerecord/test/cases/attribute_methods_test.rb +++ b/activerecord/test/cases/attribute_methods_test.rb @@ -113,6 +113,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase # by inspecting it. def test_allocated_object_can_be_inspected topic = Topic.allocate + topic.instance_eval { @attributes = nil } assert_nothing_raised { topic.inspect } assert topic.inspect, "#" end From 329409decdcbaa80695b7b65a6252e70a829091d Mon Sep 17 00:00:00 2001 From: Arun Agrawal Date: Sat, 30 Jul 2011 09:19:58 +0530 Subject: [PATCH 065/345] magic comment test only if encoding_aware?. --- activerecord/test/cases/schema_dumper_test.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb index 5da3f59a1f..99e7ef6c03 100644 --- a/activerecord/test/cases/schema_dumper_test.rb +++ b/activerecord/test/cases/schema_dumper_test.rb @@ -14,9 +14,10 @@ class SchemaDumperTest < ActiveRecord::TestCase @stream.string end - def test_magic_comment - skip "only test magic comments on 1.9" if RUBY_VERSION < '1.9' - assert_match "# encoding: #{@stream.external_encoding.name}", standard_dump + if "string".encoding_aware? + def test_magic_comment + assert_match "# encoding: #{@stream.external_encoding.name}", standard_dump + end end def test_schema_dump From 624c4571fd364bc71e2d9f5de20a664cfc8f7e15 Mon Sep 17 00:00:00 2001 From: Vishnu Atrai Date: Sun, 31 Jul 2011 18:05:05 +0530 Subject: [PATCH 066/345] remove extra require for 'stringio' as it is required in helper.rb --- activerecord/test/cases/schema_dumper_test.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb index 99e7ef6c03..71ff727b7f 100644 --- a/activerecord/test/cases/schema_dumper_test.rb +++ b/activerecord/test/cases/schema_dumper_test.rb @@ -1,5 +1,4 @@ require "cases/helper" -require 'stringio' class SchemaDumperTest < ActiveRecord::TestCase From 7f885390876a3acdfa962e42b2bf2c73241e8702 Mon Sep 17 00:00:00 2001 From: Brad Ediger Date: Sun, 31 Jul 2011 07:38:38 -0500 Subject: [PATCH 067/345] remove_possible_method: test if method exists This speeds up remove_possible_method substantially since it doesn't have to rescue a NameError in the common case. Closes #2346. --- .../lib/active_support/core_ext/module/remove_method.rb | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/activesupport/lib/active_support/core_ext/module/remove_method.rb b/activesupport/lib/active_support/core_ext/module/remove_method.rb index 07d7c9b018..b76bc16ee1 100644 --- a/activesupport/lib/active_support/core_ext/module/remove_method.rb +++ b/activesupport/lib/active_support/core_ext/module/remove_method.rb @@ -1,11 +1,16 @@ class Module def remove_possible_method(method) - remove_method(method) + if method_defined?(method) || private_method_defined?(method) + remove_method(method) + end rescue NameError + # If the requested method is defined on a superclass or included module, + # method_defined? returns true but remove_method throws a NameError. + # Ignore this. end def redefine_method(method, &block) remove_possible_method(method) define_method(method, &block) end -end \ No newline at end of file +end From 040f65b0913793bd6f2f03500e6e6a50b83f3e56 Mon Sep 17 00:00:00 2001 From: Vijay Dev Date: Sun, 31 Jul 2011 21:39:10 +0530 Subject: [PATCH 068/345] fixes #2368. rake about not showing the middleware, db adapter and db schema version --- railties/lib/rails/tasks/misc.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/lib/rails/tasks/misc.rake b/railties/lib/rails/tasks/misc.rake index 833fcb6f72..8b4775d1d3 100644 --- a/railties/lib/rails/tasks/misc.rake +++ b/railties/lib/rails/tasks/misc.rake @@ -14,7 +14,7 @@ task :secret do end desc 'List versions of all Rails frameworks and the environment' -task :about do +task :about => :environment do puts Rails::Info end From 070513016f5999fbd135285731d5f4b2e0c1b434 Mon Sep 17 00:00:00 2001 From: Vishnu Atrai Date: Sun, 31 Jul 2011 23:12:28 +0530 Subject: [PATCH 069/345] remove extra require for 'active_support/dependencies' as it is required in abstract_unit.rb --- actionpack/test/controller/routing_test.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb index aa9d193436..b693fbec2b 100644 --- a/actionpack/test/controller/routing_test.rb +++ b/actionpack/test/controller/routing_test.rb @@ -1,7 +1,6 @@ # encoding: utf-8 require 'abstract_unit' require 'controller/fake_controllers' -require 'active_support/dependencies' require 'active_support/core_ext/object/with_options' class MilestonesController < ActionController::Base From ec7457ed2a2c8e7bd0db951673324d8e316fbbf6 Mon Sep 17 00:00:00 2001 From: Arun Agrawal Date: Sun, 31 Jul 2011 23:36:21 +0530 Subject: [PATCH 070/345] Removing extra requires from the test. Already loaded in abstract_unit. --- actionpack/test/controller/helper_test.rb | 1 - activesupport/test/core_ext/string_ext_test.rb | 1 - activesupport/test/dependencies_test.rb | 1 - activesupport/test/json/decoding_test.rb | 1 - activesupport/test/multibyte_utils_test.rb | 1 - activesupport/test/test_test.rb | 1 - 6 files changed, 6 deletions(-) diff --git a/actionpack/test/controller/helper_test.rb b/actionpack/test/controller/helper_test.rb index 584d73668a..35a87c1aae 100644 --- a/actionpack/test/controller/helper_test.rb +++ b/actionpack/test/controller/helper_test.rb @@ -1,5 +1,4 @@ require 'abstract_unit' -require 'active_support/core_ext/kernel/reporting' ActionController::Base.helpers_path = File.expand_path('../../fixtures/helpers', __FILE__) diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb index 18a86e08f5..a4bba056df 100644 --- a/activesupport/test/core_ext/string_ext_test.rb +++ b/activesupport/test/core_ext/string_ext_test.rb @@ -6,7 +6,6 @@ require 'inflector_test_cases' require 'active_support/inflector' require 'active_support/core_ext/string' require 'active_support/time' -require 'active_support/core_ext/kernel/reporting' require 'active_support/core_ext/string/strip' class StringInflectionsTest < Test::Unit::TestCase diff --git a/activesupport/test/dependencies_test.rb b/activesupport/test/dependencies_test.rb index b4edf0f51d..b0e96731cc 100644 --- a/activesupport/test/dependencies_test.rb +++ b/activesupport/test/dependencies_test.rb @@ -1,7 +1,6 @@ require 'abstract_unit' require 'pp' require 'active_support/dependencies' -require 'active_support/core_ext/kernel/reporting' module ModuleWithMissing mattr_accessor :missing_count diff --git a/activesupport/test/json/decoding_test.rb b/activesupport/test/json/decoding_test.rb index 201729a6c2..d1454902e5 100644 --- a/activesupport/test/json/decoding_test.rb +++ b/activesupport/test/json/decoding_test.rb @@ -2,7 +2,6 @@ require 'abstract_unit' require 'active_support/json' require 'active_support/time' -require 'active_support/core_ext/kernel/reporting' class TestJSONDecoding < ActiveSupport::TestCase TESTS = { diff --git a/activesupport/test/multibyte_utils_test.rb b/activesupport/test/multibyte_utils_test.rb index 1dff944922..0a2f20d282 100644 --- a/activesupport/test/multibyte_utils_test.rb +++ b/activesupport/test/multibyte_utils_test.rb @@ -2,7 +2,6 @@ require 'abstract_unit' require 'multibyte_test_helpers' -require 'active_support/core_ext/kernel/reporting' class MultibyteUtilsTest < ActiveSupport::TestCase include MultibyteTestHelpers diff --git a/activesupport/test/test_test.rb b/activesupport/test/test_test.rb index 5bd995aa32..f880052786 100644 --- a/activesupport/test/test_test.rb +++ b/activesupport/test/test_test.rb @@ -1,5 +1,4 @@ require 'abstract_unit' -require 'active_support/core_ext/kernel/reporting' class AssertDifferenceTest < ActiveSupport::TestCase def setup From dc8773b19f61af2ba818d66923fc65e17bad6c20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 1 Aug 2011 11:42:00 +0200 Subject: [PATCH 071/345] Rename new method to_path to to_partial_path to avoid conflicts with File#to_path and similar. --- actionpack/lib/action_view/helpers/form_helper.rb | 8 ++++---- .../lib/action_view/renderer/partial_renderer.rb | 6 +++--- actionpack/test/template/form_helper_test.rb | 2 +- actionpack/test/template/render_test.rb | 4 ++-- activemodel/CHANGELOG | 2 +- activemodel/lib/active_model/conversion.rb | 10 +++++----- activemodel/lib/active_model/lint.rb | 8 ++++---- activemodel/lib/active_model/naming.rb | 2 +- activemodel/test/cases/conversion_test.rb | 6 +++--- activemodel/test/cases/naming_test.rb | 8 ++++---- 10 files changed, 28 insertions(+), 28 deletions(-) diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index 85dea96bbb..f22c466666 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -1227,12 +1227,12 @@ module ActionView parent_builder.multipart = multipart if parent_builder end - def self._to_path - @_to_path ||= name.demodulize.underscore.sub!(/_builder$/, '') + def self._to_partial_path + @_to_partial_path ||= name.demodulize.underscore.sub!(/_builder$/, '') end - def to_path - self.class._to_path + def to_partial_path + self.class._to_partial_path end def to_model diff --git a/actionpack/lib/action_view/renderer/partial_renderer.rb b/actionpack/lib/action_view/renderer/partial_renderer.rb index f67388b8cf..cd0f7054a9 100644 --- a/actionpack/lib/action_view/renderer/partial_renderer.rb +++ b/actionpack/lib/action_view/renderer/partial_renderer.rb @@ -364,10 +364,10 @@ module ActionView def partial_path(object = @object) object = object.to_model if object.respond_to?(:to_model) - path = if object.respond_to?(:to_path) - object.to_path + path = if object.respond_to?(:to_partial_path) + object.to_partial_path else - ActiveSupport::Deprecation.warn "ActiveModel-compatible objects whose classes return a #model_name that responds to #partial_path are deprecated. Please respond to #to_path directly instead." + ActiveSupport::Deprecation.warn "ActiveModel-compatible objects whose classes return a #model_name that responds to #partial_path are deprecated. Please respond to #to_partial_path directly instead." object.class.model_name.partial_path end diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb index 71a2c46d92..f898c22e1e 100644 --- a/actionpack/test/template/form_helper_test.rb +++ b/actionpack/test/template/form_helper_test.rb @@ -1895,7 +1895,7 @@ class FormHelperTest < ActionView::TestCase path = nil form_for(@post, :builder => LabelledFormBuilder) do |f| - path = f.to_path + path = f.to_partial_path '' end diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb index 0b91e55091..6f02f8662d 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionpack/test/template/render_test.rb @@ -214,14 +214,14 @@ module RenderTestCases end def test_render_partial_using_object_with_deprecated_partial_path - assert_deprecated(/#model_name.*#partial_path.*#to_path/) do + assert_deprecated(/#model_name.*#partial_path.*#to_partial_path/) do assert_equal "Hello: nertzy", @controller_view.render(CustomerWithDeprecatedPartialPath.new("nertzy"), :greeting => "Hello") end end def test_render_partial_using_collection_with_deprecated_partial_path - assert_deprecated(/#model_name.*#partial_path.*#to_path/) do + assert_deprecated(/#model_name.*#partial_path.*#to_partial_path/) do customers = [ CustomerWithDeprecatedPartialPath.new("nertzy"), CustomerWithDeprecatedPartialPath.new("peeja") diff --git a/activemodel/CHANGELOG b/activemodel/CHANGELOG index 597f5ab395..9b7d2d026d 100644 --- a/activemodel/CHANGELOG +++ b/activemodel/CHANGELOG @@ -1,4 +1,4 @@ -* Deprecate "Model.model_name.partial_path" in favor of "model.to_path" [Grant Hutchins, Peter Jaros] +* Deprecate "Model.model_name.partial_path" in favor of "model.to_partial_path" [Grant Hutchins, Peter Jaros] * Provide mass_assignment_sanitizer as an easy API to replace the sanitizer behavior. Also support both :logger (default) and :strict sanitizer behavior [Bogdan Gusiev] diff --git a/activemodel/lib/active_model/conversion.rb b/activemodel/lib/active_model/conversion.rb index 39977f12c3..80a3ba51c3 100644 --- a/activemodel/lib/active_model/conversion.rb +++ b/activemodel/lib/active_model/conversion.rb @@ -4,7 +4,7 @@ require 'active_support/inflector' module ActiveModel # == Active Model Conversions # - # Handles default conversions: to_model, to_key, to_param, and to_path. + # Handles default conversions: to_model, to_key, to_param, and to_partial_path. # # Let's take for example this non-persisted object. # @@ -54,15 +54,15 @@ module ActiveModel # Returns a string identifying the path associated with the object. # ActionPack uses this to find a suitable partial to represent the object. - def to_path - self.class._to_path + def to_partial_path + self.class._to_partial_path end module ClassMethods #:nodoc: # Provide a class level cache for the to_path. This is an # internal method and should not be accessed directly. - def _to_path #:nodoc: - @_to_path ||= begin + def _to_partial_path #:nodoc: + @_to_partial_path ||= begin element = ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(self)) collection = ActiveSupport::Inflector.tableize(self) "#{collection}/#{element}".freeze diff --git a/activemodel/lib/active_model/lint.rb b/activemodel/lib/active_model/lint.rb index 08c2e5fcf3..bfe7ea1869 100644 --- a/activemodel/lib/active_model/lint.rb +++ b/activemodel/lib/active_model/lint.rb @@ -43,14 +43,14 @@ module ActiveModel assert model.to_param.nil?, "to_param should return nil when `persisted?` returns false" end - # == Responds to to_path + # == Responds to to_partial_path # # Returns a string giving a relative path. This is used for looking up # partials. For example, a BlogPost model might return "blog_posts/blog_post" # - def test_to_path - assert model.respond_to?(:to_path), "The model should respond to to_path" - assert_kind_of String, model.to_path + def test_to_partial_path + assert model.respond_to?(:to_partial_path), "The model should respond to to_partial_path" + assert_kind_of String, model.to_partial_path end # == Responds to valid? diff --git a/activemodel/lib/active_model/naming.rb b/activemodel/lib/active_model/naming.rb index 26fa3062eb..f16459ede2 100644 --- a/activemodel/lib/active_model/naming.rb +++ b/activemodel/lib/active_model/naming.rb @@ -8,7 +8,7 @@ module ActiveModel attr_reader :singular, :plural, :element, :collection, :partial_path, :route_key, :param_key, :i18n_key alias_method :cache_key, :collection - deprecate :partial_path => "ActiveModel::Name#partial_path is deprecated. Call #to_path on model instances directly instead." + deprecate :partial_path => "ActiveModel::Name#partial_path is deprecated. Call #to_partial_path on model instances directly instead." def initialize(klass, namespace = nil, name = nil) name ||= klass.name diff --git a/activemodel/test/cases/conversion_test.rb b/activemodel/test/cases/conversion_test.rb index 2eccc4e56d..24552bcaf2 100644 --- a/activemodel/test/cases/conversion_test.rb +++ b/activemodel/test/cases/conversion_test.rb @@ -25,8 +25,8 @@ class ConversionTest < ActiveModel::TestCase end test "to_path default implementation returns a string giving a relative path" do - assert_equal "contacts/contact", Contact.new.to_path - assert_equal "helicopters/helicopter", Helicopter.new.to_path, - "ActiveModel::Conversion#to_path caching should be class-specific" + assert_equal "contacts/contact", Contact.new.to_partial_path + assert_equal "helicopters/helicopter", Helicopter.new.to_partial_path, + "ActiveModel::Conversion#to_partial_path caching should be class-specific" end end diff --git a/activemodel/test/cases/naming_test.rb b/activemodel/test/cases/naming_test.rb index bafe4f3c0c..1777ce2aae 100644 --- a/activemodel/test/cases/naming_test.rb +++ b/activemodel/test/cases/naming_test.rb @@ -26,7 +26,7 @@ class NamingTest < ActiveModel::TestCase end def test_partial_path - assert_deprecated(/#partial_path.*#to_path/) do + assert_deprecated(/#partial_path.*#to_partial_path/) do assert_equal 'post/track_backs/track_back', @model_name.partial_path end end @@ -58,7 +58,7 @@ class NamingWithNamespacedModelInIsolatedNamespaceTest < ActiveModel::TestCase end def test_partial_path - assert_deprecated(/#partial_path.*#to_path/) do + assert_deprecated(/#partial_path.*#to_partial_path/) do assert_equal 'blog/posts/post', @model_name.partial_path end end @@ -102,7 +102,7 @@ class NamingWithNamespacedModelInSharedNamespaceTest < ActiveModel::TestCase end def test_partial_path - assert_deprecated(/#partial_path.*#to_path/) do + assert_deprecated(/#partial_path.*#to_partial_path/) do assert_equal 'blog/posts/post', @model_name.partial_path end end @@ -142,7 +142,7 @@ class NamingWithSuppliedModelNameTest < ActiveModel::TestCase end def test_partial_path - assert_deprecated(/#partial_path.*#to_path/) do + assert_deprecated(/#partial_path.*#to_partial_path/) do assert_equal 'articles/article', @model_name.partial_path end end From 860202e8b2e3579402d48d7e56fa738a9529a340 Mon Sep 17 00:00:00 2001 From: thoefer Date: Mon, 1 Aug 2011 11:28:31 +0200 Subject: [PATCH 072/345] Fix the issue where default_url_options is being cached on test cases. Closes #1872. Closes #2031. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- .../lib/action_controller/metal/testing.rb | 5 ++++ actionpack/lib/action_controller/test_case.rb | 1 + .../default_url_options_with_filter_test.rb | 29 +++++++++++++++++++ 3 files changed, 35 insertions(+) create mode 100644 actionpack/test/controller/default_url_options_with_filter_test.rb diff --git a/actionpack/lib/action_controller/metal/testing.rb b/actionpack/lib/action_controller/metal/testing.rb index f4efeb33ba..d1813ee745 100644 --- a/actionpack/lib/action_controller/metal/testing.rb +++ b/actionpack/lib/action_controller/metal/testing.rb @@ -4,6 +4,11 @@ module ActionController include RackDelegation + def recycle! + @_url_options = nil + end + + # TODO: Clean this up def process_with_new_base_test(request, response) @_request = request diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb index 45bb641aee..c8cf04bb69 100644 --- a/actionpack/lib/action_controller/test_case.rb +++ b/actionpack/lib/action_controller/test_case.rb @@ -450,6 +450,7 @@ module ActionController @controller.params.merge!(parameters) build_request_uri(action, parameters) @controller.class.class_eval { include Testing } + @controller.recycle! @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? diff --git a/actionpack/test/controller/default_url_options_with_filter_test.rb b/actionpack/test/controller/default_url_options_with_filter_test.rb new file mode 100644 index 0000000000..3bbb981040 --- /dev/null +++ b/actionpack/test/controller/default_url_options_with_filter_test.rb @@ -0,0 +1,29 @@ +require 'abstract_unit' + + +class ControllerWithBeforeFilterAndDefaultUrlOptions < ActionController::Base + + before_filter { I18n.locale = params[:locale] } + after_filter { I18n.locale = "en" } + + def target + render :text => "final response" + end + + def redirect + redirect_to :action => "target" + end + + def default_url_options + {:locale => "de"} + end +end + +class ControllerWithBeforeFilterAndDefaultUrlOptionsTest < ActionController::TestCase + + # This test has it´s roots in issue #1872 + test "should redirect with correct locale :de" do + get :redirect, :locale => "de" + assert_redirected_to "/controller_with_before_filter_and_default_url_options/target?locale=de" + end +end From 6244a53a073fcf12abddd9eaaecf1191cd2b5446 Mon Sep 17 00:00:00 2001 From: Dmitriy Kiriyenko Date: Mon, 1 Aug 2011 18:00:41 +0300 Subject: [PATCH 073/345] Remove unnecessary require (happened after fcbde454f6) --- activesupport/lib/active_support/core_ext/module/delegation.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/activesupport/lib/active_support/core_ext/module/delegation.rb b/activesupport/lib/active_support/core_ext/module/delegation.rb index 41f9a76b13..149b849b12 100644 --- a/activesupport/lib/active_support/core_ext/module/delegation.rb +++ b/activesupport/lib/active_support/core_ext/module/delegation.rb @@ -1,5 +1,3 @@ -require "active_support/core_ext/module/remove_method" - class Module # Provides a delegate class method to easily expose contained objects' methods # as your own. Pass one or more methods (specified as symbols or strings) From fec4c5ad76a4955364e091296b68bb7ac12bc928 Mon Sep 17 00:00:00 2001 From: Brian Durand Date: Mon, 1 Aug 2011 12:05:29 -0500 Subject: [PATCH 074/345] Pass options in ActiveSupport::Cache::CacheStore#read_multi through to the delete_entry call. --- activesupport/lib/active_support/cache.rb | 2 +- activesupport/test/caching_test.rb | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb index ac88c82709..a5aacb60ee 100644 --- a/activesupport/lib/active_support/cache.rb +++ b/activesupport/lib/active_support/cache.rb @@ -347,7 +347,7 @@ module ActiveSupport entry = read_entry(key, options) if entry if entry.expired? - delete_entry(key) + delete_entry(key, options) else results[name] = entry.value end diff --git a/activesupport/test/caching_test.rb b/activesupport/test/caching_test.rb index 402c6695aa..5e6a2102e0 100644 --- a/activesupport/test/caching_test.rb +++ b/activesupport/test/caching_test.rb @@ -199,6 +199,14 @@ module CacheStoreBehavior @cache.write('fud', 'biz') assert_equal({"foo" => "bar", "fu" => "baz"}, @cache.read_multi('foo', 'fu')) end + + def test_read_multi_with_expires + @cache.write('foo', 'bar', :expires_in => 0.001) + @cache.write('fu', 'baz') + @cache.write('fud', 'biz') + sleep(0.002) + assert_equal({"fu" => "baz"}, @cache.read_multi('foo', 'fu')) + end def test_read_and_write_compressed_small_data @cache.write('foo', 'bar', :compress => true) From 6dda2167154c856e8776a192e90118c3b3129b78 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Mon, 1 Aug 2011 12:32:17 -0700 Subject: [PATCH 075/345] Merge pull request #2324 from zenapsis/3-1-stable Rails 3.1 throws a Errno::ENOTDIR if files are put in assets directories --- railties/lib/rails/engine.rb | 6 +++--- railties/lib/rails/paths.rb | 4 ++++ railties/test/application/assets_test.rb | 14 ++++++++++++++ 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index c41f7d7c2e..2c3f61f404 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -542,9 +542,9 @@ module Rails end initializer :append_assets_path do |app| - app.config.assets.paths.unshift(*paths["vendor/assets"].existent) - app.config.assets.paths.unshift(*paths["lib/assets"].existent) - app.config.assets.paths.unshift(*paths["app/assets"].existent) + app.config.assets.paths.unshift(*paths["vendor/assets"].existent_directories) + app.config.assets.paths.unshift(*paths["lib/assets"].existent_directories) + app.config.assets.paths.unshift(*paths["app/assets"].existent_directories) end initializer :prepend_helpers_path do |app| diff --git a/railties/lib/rails/paths.rb b/railties/lib/rails/paths.rb index de3d0b6fc5..55b820b12e 100644 --- a/railties/lib/rails/paths.rb +++ b/railties/lib/rails/paths.rb @@ -171,6 +171,10 @@ module Rails def existent expanded.select { |f| File.exists?(f) } end + + def existent_directories + expanded.select {|d| Dir.exists?(d) } + end alias to_a expanded end diff --git a/railties/test/application/assets_test.rb b/railties/test/application/assets_test.rb index 7fb930bd99..802b737483 100644 --- a/railties/test/application/assets_test.rb +++ b/railties/test/application/assets_test.rb @@ -109,5 +109,19 @@ module ApplicationTests assert_match "alert()", last_response.body assert_equal nil, last_response.headers["Set-Cookie"] end + + test "files in any assets/ directories are not added to Sprockets" do + %w[app lib vendor].each do |dir| + app_file "#{dir}/assets/#{dir}_test.erb", "testing" + end + + app_file "app/assets/javascripts/demo.js", "alert();" + + require "#{app_path}/config/environment" + + get "/assets/demo.js" + assert_match "alert();", last_response.body + assert_equal 200, last_response.status + end end end From 3a4dc9d34c1cde8bf34dfa4b4600fb8bcef9eb45 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 1 Aug 2011 17:29:03 -0700 Subject: [PATCH 076/345] use File.directory? as Dir.exists? is only 1.9.2+ --- railties/lib/rails/paths.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/railties/lib/rails/paths.rb b/railties/lib/rails/paths.rb index 55b820b12e..b37421c09c 100644 --- a/railties/lib/rails/paths.rb +++ b/railties/lib/rails/paths.rb @@ -171,9 +171,9 @@ module Rails def existent expanded.select { |f| File.exists?(f) } end - + def existent_directories - expanded.select {|d| Dir.exists?(d) } + expanded.select { |d| File.directory?(d) } end alias to_a expanded From 74d7bfb200e4590e244558554e147a31d30990df Mon Sep 17 00:00:00 2001 From: Christopher Meiklejohn Date: Fri, 29 Jul 2011 21:26:21 -0400 Subject: [PATCH 077/345] Support backwards compatible interface for migration down/up with rails 3.0.x. --- activerecord/lib/active_record/migration.rb | 1 + .../test/cases/invertible_migration_test.rb | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 507f345ef5..9307d7ef24 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -329,6 +329,7 @@ module ActiveRecord end def self.method_missing(name, *args, &block) # :nodoc: + self.delegate = self.new (delegate || superclass.delegate).send(name, *args, &block) end diff --git a/activerecord/test/cases/invertible_migration_test.rb b/activerecord/test/cases/invertible_migration_test.rb index afec64750e..acba4a134e 100644 --- a/activerecord/test/cases/invertible_migration_test.rb +++ b/activerecord/test/cases/invertible_migration_test.rb @@ -27,6 +27,19 @@ module ActiveRecord end end + class LegacyMigration < ActiveRecord::Migration + def self.up + create_table("horses") do |t| + t.column :content, :text + t.column :remind_at, :datetime + end + end + + def self.down + drop_table("horses") + end + end + def teardown if ActiveRecord::Base.connection.table_exists?("horses") ActiveRecord::Base.connection.drop_table("horses") @@ -53,5 +66,16 @@ module ActiveRecord migration.migrate :down assert !migration.connection.table_exists?("horses") end + + def test_legacy_up + LegacyMigration.migrate :up + assert ActiveRecord::Base.connection.table_exists?("horses"), "horses should exist" + end + + def test_legacy_down + LegacyMigration.migrate :up + LegacyMigration.migrate :down + assert !ActiveRecord::Base.connection.table_exists?("horses"), "horses should not exist" + end end end From 43fc81407495a31465bc3559bc0703fd328f2308 Mon Sep 17 00:00:00 2001 From: Christopher Meiklejohn Date: Fri, 29 Jul 2011 23:17:12 -0400 Subject: [PATCH 078/345] Ensure that .up and .down work as well. --- .../test/cases/invertible_migration_test.rb | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/activerecord/test/cases/invertible_migration_test.rb b/activerecord/test/cases/invertible_migration_test.rb index acba4a134e..3ae7b63dff 100644 --- a/activerecord/test/cases/invertible_migration_test.rb +++ b/activerecord/test/cases/invertible_migration_test.rb @@ -54,13 +54,13 @@ module ActiveRecord end end - def test_up + def test_migrate_up migration = InvertibleMigration.new migration.migrate(:up) assert migration.connection.table_exists?("horses"), "horses should exist" end - def test_down + def test_migrate_down migration = InvertibleMigration.new migration.migrate :up migration.migrate :down @@ -77,5 +77,16 @@ module ActiveRecord LegacyMigration.migrate :down assert !ActiveRecord::Base.connection.table_exists?("horses"), "horses should not exist" end + + def test_up + LegacyMigration.up + assert ActiveRecord::Base.connection.table_exists?("horses"), "horses should exist" + end + + def test_down + LegacyMigration.up + LegacyMigration.down + assert !ActiveRecord::Base.connection.table_exists?("horses"), "horses should not exist" + end end end From 3a29cc341205b7da30c537f31eefb18ede51bb4d Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 2 Aug 2011 20:01:38 -0700 Subject: [PATCH 079/345] add a migrate class method and delegate to the new instance --- activerecord/lib/active_record/migration.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 9307d7ef24..fa1b303fc7 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -329,10 +329,13 @@ module ActiveRecord end def self.method_missing(name, *args, &block) # :nodoc: - self.delegate = self.new (delegate || superclass.delegate).send(name, *args, &block) end + def self.migrate(direction) + new.migrate direction + end + cattr_accessor :verbose attr_accessor :name, :version From 3c7b29da1b1fff83fb72a19426193332eaf63577 Mon Sep 17 00:00:00 2001 From: Arun Agrawal Date: Mon, 1 Aug 2011 20:31:19 +0530 Subject: [PATCH 080/345] Test added to check mass_assignment_sanitizer is not present if --skip-active-record provided. --- railties/test/generators/app_generator_test.rb | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index fb7ebaa1fa..0db9b99234 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -314,6 +314,15 @@ class AppGeneratorTest < Rails::Generators::TestCase end end + def test_generated_environments_file_for_sanitizer + run_generator [destination_root, "--skip-active-record"] + ["config/environments/development.rb", "config/environments/test.rb"].each do |env_file| + assert_file env_file do |file| + assert_no_match(/config.active_record.mass_assignment_sanitizer = :strict/, file) + end + end + end + protected def action(*args, &block) From 86b7d83f1ce81284cad37781667a5f204be22273 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 3 Aug 2011 08:57:52 -0700 Subject: [PATCH 081/345] initializing @open_transactions in the initialize method --- .../active_record/connection_adapters/abstract_adapter.rb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index 65024d76f8..bde31d1cda 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -43,6 +43,7 @@ module ActiveRecord @connection, @logger = connection, logger @query_cache_enabled = false @query_cache = Hash.new { |h,sql| h[sql] = {} } + @open_transactions = 0 @instrumenter = ActiveSupport::Notifications.instrumenter end @@ -177,12 +178,9 @@ module ActiveRecord @connection end - def open_transactions - @open_transactions ||= 0 - end + attr_reader :open_transactions def increment_open_transactions - @open_transactions ||= 0 @open_transactions += 1 end From 8962e96e3926a0c8d11d57eb583d5879dab0637c Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 3 Aug 2011 18:14:11 -0300 Subject: [PATCH 082/345] This dep is already defined in activerecord.gemspec --- Gemfile | 2 -- 1 file changed, 2 deletions(-) diff --git a/Gemfile b/Gemfile index ec064bbda8..f6caa1ee65 100644 --- a/Gemfile +++ b/Gemfile @@ -4,8 +4,6 @@ gemspec if ENV['AREL'] gem "arel", :path => ENV['AREL'] -else - gem "arel", '~> 2.1.3' end gem "jquery-rails" From b386951e4281f1a393a7448d5cccf84843ddac30 Mon Sep 17 00:00:00 2001 From: artemk Date: Thu, 4 Aug 2011 00:34:13 +0300 Subject: [PATCH 083/345] accept option for recreate db for postgres (same as mysql now) --- .../active_record/connection_adapters/postgresql_adapter.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index a84f73c73f..aefe69f8ed 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -614,9 +614,11 @@ module ActiveRecord # SCHEMA STATEMENTS ======================================== - def recreate_database(name) #:nodoc: + # Drops the database specified on the +name+ attribute + # and creates it again using the provided +options+. + def recreate_database(name, options = {}) #:nodoc: drop_database(name) - create_database(name) + create_database(name, options) end # Create a new PostgreSQL database. Options include :owner, :template, From bf5d1d46623d478bb4371a60bead97022cef11ed Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 3 Aug 2011 19:18:34 -0300 Subject: [PATCH 084/345] Don't require assets group in production by default, you can change this default in the application.rb anyways --- .../rails/app/templates/config/application.rb | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) 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 7687b1beac..dd0cf64650 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/application.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/application.rb @@ -13,9 +13,13 @@ require "active_resource/railtie" <% end -%> # If you have a Gemfile, require the default gems, the ones in the -# current environment and also include :assets gems if in development -# or test environments. -Bundler.require *Rails.groups(:assets) if defined?(Bundler) +# current environment and also include :assets gems if you ... +if defined?(Bundler) + # ... precompile your assets + Bundler.require *Rails.groups(:assets => %w(development test)) + # ... want your assets to be lazily compiled also in production + # Bundler.require(:default, :assets, Rails.env) +end module <%= app_const_base %> class Application < Rails::Application From 171881f610fdff1903b2bdd1c8894cbe1ab98303 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 3 Aug 2011 16:55:00 -0700 Subject: [PATCH 085/345] make assert_difference error message not suck --- .../lib/active_support/testing/assertions.rb | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/activesupport/lib/active_support/testing/assertions.rb b/activesupport/lib/active_support/testing/assertions.rb index 3864b1f5a6..ba34e9853c 100644 --- a/activesupport/lib/active_support/testing/assertions.rb +++ b/activesupport/lib/active_support/testing/assertions.rb @@ -46,16 +46,17 @@ module ActiveSupport # end def assert_difference(expression, difference = 1, message = nil, &block) exps = Array.wrap(expression).map { |e| - e.respond_to?(:call) ? e : lambda { eval(e, block.binding) } + callee = e.respond_to?(:call) ? e : lambda { eval(e, block.binding) } + [e, callee] } - before = exps.map { |e| e.call } + before = exps.map { |_, block| block.call } yield - exps.each_with_index do |e, i| - error = "#{e.inspect} didn't change by #{difference}" + exps.each_with_index do |(code, block), i| + error = "#{code.inspect} didn't change by #{difference}" error = "#{message}.\n#{error}" if message - assert_equal(before[i] + difference, e.call, error) + assert_equal(before[i] + difference, block.call, error) end end From 7d4321711ebb99d2669c02b2030ade0de69655af Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 3 Aug 2011 21:04:32 -0300 Subject: [PATCH 086/345] Fix a bit precompile and lazy compile comments --- .../generators/rails/app/templates/config/application.rb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) 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 dd0cf64650..86c9bd2d1d 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/application.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/application.rb @@ -12,12 +12,10 @@ require "active_resource/railtie" <%= comment_if :skip_test_unit %>require "rails/test_unit/railtie" <% end -%> -# If you have a Gemfile, require the default gems, the ones in the -# current environment and also include :assets gems if you ... if defined?(Bundler) - # ... precompile your assets + # If you precompile assets before deploying to production, use this line Bundler.require *Rails.groups(:assets => %w(development test)) - # ... want your assets to be lazily compiled also in production + # If you want your assets lazily compiled in production, use this line # Bundler.require(:default, :assets, Rails.env) end From f000d4e5faeabafece59a46911a74e876785b785 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Thu, 4 Aug 2011 00:23:58 +0100 Subject: [PATCH 087/345] Quote these dates to prevent intermittent test failure. Suppose local time is 00:50 GMT+1. Without the quoting, the YAML parser would parse this as 00:50 UTC, into the local time of 01:50 GMT+1. Then, it would get written into the database in local time as 01:50. When it came back out the UTC date from the database and the UTC date of two weeks ago would be compared. The former would be 23:50, and the latter would be 00:50, so the two dates would differ, causing the assertion to fail. Quoting it prevents the YAML parser from getting involved. --- activerecord/test/cases/fixtures_test.rb | 4 ++-- activerecord/test/fixtures/pirates.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb index 842e8a0049..913f6a3340 100644 --- a/activerecord/test/cases/fixtures_test.rb +++ b/activerecord/test/cases/fixtures_test.rb @@ -587,8 +587,8 @@ class FoxyFixturesTest < ActiveRecord::TestCase end def test_preserves_existing_fixture_data - assert_equal(2.weeks.ago.utc.to_date, pirates(:redbeard).created_on.utc.to_date) - assert_equal(2.weeks.ago.utc.to_date, pirates(:redbeard).updated_on.utc.to_date) + assert_equal(2.weeks.ago.to_date, pirates(:redbeard).created_on.to_date) + assert_equal(2.weeks.ago.to_date, pirates(:redbeard).updated_on.to_date) end def test_generates_unique_ids diff --git a/activerecord/test/fixtures/pirates.yml b/activerecord/test/fixtures/pirates.yml index abb91101da..6004f390a4 100644 --- a/activerecord/test/fixtures/pirates.yml +++ b/activerecord/test/fixtures/pirates.yml @@ -5,5 +5,5 @@ blackbeard: redbeard: catchphrase: "Avast!" parrot: louis - created_on: <%= 2.weeks.ago.to_s(:db) %> - updated_on: <%= 2.weeks.ago.to_s(:db) %> + created_on: "<%= 2.weeks.ago.to_s(:db) %>" + updated_on: "<%= 2.weeks.ago.to_s(:db) %>" From 54b83566ccb55ae4a9bdb163a6224fa946814457 Mon Sep 17 00:00:00 2001 From: Waynn Lue Date: Fri, 29 Jul 2011 17:43:05 -0700 Subject: [PATCH 088/345] fix stringify_keys destructive behavior for most FormTagHelper functions add four new tests to verify that the other three methods that called stringify_keys! are fixed. verified that the tests break in master without the code patch. Closes #2355 --- .../action_view/helpers/form_tag_helper.rb | 8 +++---- .../test/template/form_tag_helper_test.rb | 24 +++++++++++++++++++ 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index 79f07400b2..2bbe0c175f 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -304,7 +304,7 @@ module ActionView # text_area_tag 'comment', nil, :class => 'comment_input' # # => def text_area_tag(name, content = nil, options = {}) - options.stringify_keys! + options = options.stringify_keys if size = options.delete("size") options["cols"], options["rows"] = size.split("x") if size.respond_to?(:split) @@ -407,7 +407,7 @@ module ActionView # data-confirm="Are you sure?" /> # def submit_tag(value = "Save changes", options = {}) - options.stringify_keys! + options = options.stringify_keys if disable_with = options.delete("disable_with") options["data-disable-with"] = disable_with @@ -458,7 +458,7 @@ module ActionView def button_tag(content_or_options = nil, options = nil, &block) options = content_or_options if block_given? && content_or_options.is_a?(Hash) options ||= {} - options.stringify_keys! + options = options.stringify_keys if disable_with = options.delete("disable_with") options["data-disable-with"] = disable_with @@ -497,7 +497,7 @@ module ActionView # image_submit_tag("agree.png", :disabled => true, :class => "agree_disagree_button") # # => def image_submit_tag(source, options = {}) - options.stringify_keys! + options = options.stringify_keys if confirm = options.delete("confirm") options["data-confirm"] = confirm diff --git a/actionpack/test/template/form_tag_helper_test.rb b/actionpack/test/template/form_tag_helper_test.rb index 979251bfd1..ad31812273 100644 --- a/actionpack/test/template/form_tag_helper_test.rb +++ b/actionpack/test/template/form_tag_helper_test.rb @@ -505,6 +505,30 @@ class FormTagHelperTest < ActionView::TestCase expected = %(
Hello world!
) assert_dom_equal expected, output_buffer end + + def test_text_area_tag_options_symbolize_keys_side_effects + options = { :option => "random_option" } + actual = text_area_tag "body", "hello world", options + assert_equal options, { :option => "random_option" } + end + + def test_submit_tag_options_symbolize_keys_side_effects + options = { :option => "random_option" } + actual = submit_tag "submit value", options + assert_equal options, { :option => "random_option" } + end + + def test_button_tag_options_symbolize_keys_side_effects + options = { :option => "random_option" } + actual = button_tag "button value", options + assert_equal options, { :option => "random_option" } + end + + def test_image_submit_tag_options_symbolize_keys_side_effects + options = { :option => "random_option" } + actual = image_submit_tag "submit source", options + assert_equal options, { :option => "random_option" } + end def protect_against_forgery? false From f0034c75d5a9bc5065652c2fedf39250a6f1847b Mon Sep 17 00:00:00 2001 From: Casebook Developer Date: Thu, 4 Aug 2011 13:34:47 -0400 Subject: [PATCH 089/345] ActionView::Helpers::TextHelper#simple_format should not change the text in place. Now it duplicates it. --- actionpack/lib/action_view/helpers/text_helper.rb | 2 +- actionpack/test/template/text_helper_test.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb index ae71ade588..21074efe86 100644 --- a/actionpack/lib/action_view/helpers/text_helper.rb +++ b/actionpack/lib/action_view/helpers/text_helper.rb @@ -256,7 +256,7 @@ module ActionView # # => "

I'm allowed! It's true.

" def simple_format(text, html_options={}, options={}) text = '' if text.nil? - text = text.dup if text.frozen? + text = text.dup start_tag = tag('p', html_options, true) text = sanitize(text) unless options[:sanitize] == false text = text.to_str diff --git a/actionpack/test/template/text_helper_test.rb b/actionpack/test/template/text_helper_test.rb index f7c3986bb1..02f9609483 100644 --- a/actionpack/test/template/text_helper_test.rb +++ b/actionpack/test/template/text_helper_test.rb @@ -48,10 +48,10 @@ class TextHelperTest < ActionView::TestCase assert_equal "

test with unsafe string

", simple_format(" test with unsafe string ", {}, :sanitize => false) end - def test_simple_format_should_not_change_the_frozen_text_passed + def test_simple_format_should_not_change_the_text_passed text = "Ok" text_clone = text.dup - simple_format(text.freeze) + simple_format(text) assert_equal text_clone, text end From bf5b4c0055df4a02a57c53620badfcab48fc0cba Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 4 Aug 2011 11:27:26 -0700 Subject: [PATCH 090/345] adding my brain dump of the release process --- RELEASING_RAILS.rdoc | 163 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 RELEASING_RAILS.rdoc diff --git a/RELEASING_RAILS.rdoc b/RELEASING_RAILS.rdoc new file mode 100644 index 0000000000..2d8d8c5f95 --- /dev/null +++ b/RELEASING_RAILS.rdoc @@ -0,0 +1,163 @@ += Releasing Rails + +In this document, we'll cover the steps necessary to release Rails. Each +section contains steps to take during that time before the release. The times +suggested in each header are just that: suggestions. However, they should +really be considered as minimums. + +== 10 Days before release + +Today is mostly coordination tasks. Here are the things you must do today: + +=== Contact the security team (either Koz or tenderlove) + +Let them know of your plans to release. There may be security issues to be +addressed, and that can impact your release date. + +=== Is the CI green? If not, make it green. (See "Fixing the CI") + +Do not release with a Red CI. You can find the CI status here: + + http://travis-ci.org/#!/rails/rails + +=== Is Sam Ruby happy? If not, make him happy. + +Sam Ruby keeps a test suite that makes sure the code samples in his book (Agile +Web Development with Rails) all work. These are valuable integration tests +for Rails. You can check the status of his tests here: + + http://intertwingly.net/projects/dashboard.html + +Do not release with Red AWDwR tests. + +=== Do we have any git dependencies? If so, contact those authors. + +Having git dependencies indicates that we depend on unreleased code. +Obviously rails cannot be released when it depends on unreleased code. +Contact the authors of those particular gems and work out a release date that +suites them. + +== 3 Days before release + +This is when you should release the release candidate. Here are your tasks +for today: + +=== Is the CI green? If not, make it green. + +=== Is Sam Ruby happy? If not, make him happy. + +=== Contact the security team. CVE emails must be sent on this day. + +=== Create a release branch. + +From the stable branch, create a release branch. For example, if you're +releasing Rails 3.0.10, do this: + + [aaron@higgins rails (3-0-stable)]$ git checkout -b 3-0-10 + Switched to a new branch '3-0-10' + [aaron@higgins rails (3-0-10)]$ + +=== Update each CHANGELOG. + +Many times commits are made without the CHANGELOG being updated. You should +review the commits since the last release, and fill in any missing information +for each CHANGELOG. + +You can review the commits for the 3.0.10 release like this: + + [aaron@higgins rails (3-0-10)]$ git log v3.0.9.. + +=== Update the RAILS_VERSION file to include the RC. + +=== Release the gem. + +IMPORTANT: Due to YAML parse problems on the rubygems.org server, it is safest +to use Ruby 1.8 when releasing. + +Run `rake release`. This will populate the gemspecs with data from +RAILS_VERSION, commit the changes, tag it, and push the gems to rubygems.org. +Here are the commands that `rake release` should use, so you can understand +what to do in case anything goes wrong: + + $ rake all:build + $ git commit -am'updating RAILS_VERSION' + $ git tag -m'tagging rc release' v3.0.10.rc1 + $ for i in $(ls dist); do gem push $i; done + +=== Send Rails release announcements + +Write a release announcement that includes the version, changes, and links to +github where people can find the specific commit list. Here are the mailing +lists where you should announce: + +* rubyonrails-core@googlegroups.com +* rubyonrails-talk@googlegroups.com +* ruby-talk@ruby-lang.org + +Use markdown format for your announcement. Remember to ask people to report +issues with the release candidate to the rails-core mailing list. + +IMPORTANT: If anything users experience regressions when using the release +candidate, you *must* postpone the release. Bugfix releases *should not* +break existing applications. + +=== Post the announcement to the Rails blog. + +If you used markdown format for your email, you can just paste it in to the +blog. + +* http://weblog.rubyonrails.org + +=== Post the announcement to the Rails twitter account. + +== Time between release candidate and actual release + +Check the rails-core mailing list and the github issue list for regressions in +the RC. + +If any regressions are found, fix the regressions and repeat the release +candidate process. We will not release the final until 72 hours after the +last release candidate has been pushed. This means that if users find +regressions, the scheduled release date must be postponed. + +When you fix the regressions, do not create a new branch. Fix them on the +stable branch, then cherry pick the commit to your release branch. No other +commits should be added to the release branch besides regression fixing commits. + +== Day of release + +Many of these steps are the same as for the release candidate, so if you need +more explanation on a particular step, so the RC steps. + +=== Email the rails security announce list, once for each vulnerability fixed. + +You can do this, or ask the security team to do it. + +FIXME: I can't remember the email addresses, but we should list them here. +FIXME: Possibly we should do this the day of the RC? + +* Apply security patches to the release branch +* Update CHANGELOG with security fixes. +* Update RAILS_VERSION to remove the rc +* Release the gems +* Email announcement + +Be sure to note the security fixes in your announcement along with CVE numbers +and links to each patch. Some people may not be able to upgrade right away, +so we need to give them the security fixes in patch form. + +* Blog announcements +* Twitter announcements +* Merge the release branch to the stable branch. +* Drink beer (or other cocktail) + +== Misc + +=== Fixing the CI + +There are two simple steps for fixing the CI: + +1. Identify the problem +2. Fix it + +Repeat these steps until the CI is green. From 19ab8e4bc92bfbd04231bbac3f90cd3baa697ccc Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 4 Aug 2011 12:00:06 -0700 Subject: [PATCH 091/345] fixing wrong words. thanks @jbrown --- RELEASING_RAILS.rdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASING_RAILS.rdoc b/RELEASING_RAILS.rdoc index 2d8d8c5f95..98453db549 100644 --- a/RELEASING_RAILS.rdoc +++ b/RELEASING_RAILS.rdoc @@ -97,7 +97,7 @@ lists where you should announce: Use markdown format for your announcement. Remember to ask people to report issues with the release candidate to the rails-core mailing list. -IMPORTANT: If anything users experience regressions when using the release +IMPORTANT: If any users experience regressions when using the release candidate, you *must* postpone the release. Bugfix releases *should not* break existing applications. From 2d2c9179adcd64e2125ea49d5d9517985bbccb01 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 4 Aug 2011 14:07:23 -0700 Subject: [PATCH 092/345] fixing assert_difference issues on ruby 1.8 --- .../lib/active_support/testing/assertions.rb | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/activesupport/lib/active_support/testing/assertions.rb b/activesupport/lib/active_support/testing/assertions.rb index ba34e9853c..f3629ada5b 100644 --- a/activesupport/lib/active_support/testing/assertions.rb +++ b/activesupport/lib/active_support/testing/assertions.rb @@ -45,18 +45,19 @@ module ActiveSupport # post :delete, :id => ... # end def assert_difference(expression, difference = 1, message = nil, &block) - exps = Array.wrap(expression).map { |e| - callee = e.respond_to?(:call) ? e : lambda { eval(e, block.binding) } - [e, callee] + expressions = Array.wrap expression + + exps = expressions.map { |e| + e.respond_to?(:call) ? e : lambda { eval(e, block.binding) } } - before = exps.map { |_, block| block.call } + before = exps.map { |e| e.call } yield - exps.each_with_index do |(code, block), i| + expressions.zip(exps).each_with_index do |(code, e), i| error = "#{code.inspect} didn't change by #{difference}" error = "#{message}.\n#{error}" if message - assert_equal(before[i] + difference, block.call, error) + assert_equal(before[i] + difference, e.call, error) end end From 879dcada2ec33daaa371955604746ca0ffad67f7 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 4 Aug 2011 14:13:41 -0700 Subject: [PATCH 093/345] add section about notifying implementors --- RELEASING_RAILS.rdoc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/RELEASING_RAILS.rdoc b/RELEASING_RAILS.rdoc index 98453db549..f780f58f2f 100644 --- a/RELEASING_RAILS.rdoc +++ b/RELEASING_RAILS.rdoc @@ -14,6 +14,20 @@ Today is mostly coordination tasks. Here are the things you must do today: Let them know of your plans to release. There may be security issues to be addressed, and that can impact your release date. +=== Notify implementors. + +Ruby implementors have high stakes in making sure Rails works. Be kind and +give them a heads up that Rails will be released soonish. + +Send an email just giving a heads up about the upcoming release to these +lists: + +* team@jruby.org +* community@rubini.us +* rubyonrails-core@googlegroups.com + +Implementors will love you and help you. + === Is the CI green? If not, make it green. (See "Fixing the CI") Do not release with a Red CI. You can find the CI status here: From cb6a082fee1a984ce91476a48c2af57d32960080 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 4 Aug 2011 14:15:45 -0700 Subject: [PATCH 094/345] moving CI and Sam Ruby to the top of the list. I :heart: CI and Sam --- RELEASING_RAILS.rdoc | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/RELEASING_RAILS.rdoc b/RELEASING_RAILS.rdoc index f780f58f2f..22fc58516e 100644 --- a/RELEASING_RAILS.rdoc +++ b/RELEASING_RAILS.rdoc @@ -9,25 +9,6 @@ really be considered as minimums. Today is mostly coordination tasks. Here are the things you must do today: -=== Contact the security team (either Koz or tenderlove) - -Let them know of your plans to release. There may be security issues to be -addressed, and that can impact your release date. - -=== Notify implementors. - -Ruby implementors have high stakes in making sure Rails works. Be kind and -give them a heads up that Rails will be released soonish. - -Send an email just giving a heads up about the upcoming release to these -lists: - -* team@jruby.org -* community@rubini.us -* rubyonrails-core@googlegroups.com - -Implementors will love you and help you. - === Is the CI green? If not, make it green. (See "Fixing the CI") Do not release with a Red CI. You can find the CI status here: @@ -51,6 +32,25 @@ Obviously rails cannot be released when it depends on unreleased code. Contact the authors of those particular gems and work out a release date that suites them. +=== Contact the security team (either Koz or tenderlove) + +Let them know of your plans to release. There may be security issues to be +addressed, and that can impact your release date. + +=== Notify implementors. + +Ruby implementors have high stakes in making sure Rails works. Be kind and +give them a heads up that Rails will be released soonish. + +Send an email just giving a heads up about the upcoming release to these +lists: + +* team@jruby.org +* community@rubini.us +* rubyonrails-core@googlegroups.com + +Implementors will love you and help you. + == 3 Days before release This is when you should release the release candidate. Here are your tasks From 343daf309b88ac861032faaabe9f209b6c97118d Mon Sep 17 00:00:00 2001 From: Andrew Marshall & Sean Moon Date: Thu, 4 Aug 2011 17:29:37 -0400 Subject: [PATCH 095/345] Make rails gem build directory consistent with actionpack, etc. --- tasks/release.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tasks/release.rb b/tasks/release.rb index 01950b227d..2422efa786 100644 --- a/tasks/release.rb +++ b/tasks/release.rb @@ -4,11 +4,11 @@ root = File.expand_path('../../', __FILE__) version = File.read("#{root}/RAILS_VERSION").strip tag = "v#{version}" -directory "dist" +directory "pkg" (FRAMEWORKS + ['rails']).each do |framework| namespace framework do - gem = "dist/#{framework}-#{version}.gem" + gem = "pkg/#{framework}-#{version}.gem" gemspec = "#{framework}.gemspec" task :clean do @@ -41,10 +41,10 @@ directory "dist" File.open(file, 'w') { |f| f.write ruby } end - task gem => %w(update_version_rb dist) do + task gem => %w(update_version_rb pkg) do cmd = "" cmd << "cd #{framework} && " unless framework == "rails" - cmd << "gem build #{gemspec} && mv #{framework}-#{version}.gem #{root}/dist/" + cmd << "gem build #{gemspec} && mv #{framework}-#{version}.gem #{root}/pkg/" sh cmd end @@ -104,14 +104,14 @@ namespace :all do end task :commit do - File.open('dist/commit_message.txt', 'w') do |f| + File.open('pkg/commit_message.txt', 'w') do |f| f.puts "# Preparing for #{version} release\n" f.puts f.puts "# UNCOMMENT THE LINE ABOVE TO APPROVE THIS COMMIT" end - sh "git add . && git commit --verbose --template=dist/commit_message.txt" - rm_f "dist/commit_message.txt" + sh "git add . && git commit --verbose --template=pkg/commit_message.txt" + rm_f "pkg/commit_message.txt" end task :tag do From d338e8976f7975c40c87a09b0e36ee6ac67807e1 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 4 Aug 2011 18:43:13 -0300 Subject: [PATCH 096/345] Add git push and git push --tags to RELEASING_RAILS.rdoc --- RELEASING_RAILS.rdoc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RELEASING_RAILS.rdoc b/RELEASING_RAILS.rdoc index 22fc58516e..e3d3f67237 100644 --- a/RELEASING_RAILS.rdoc +++ b/RELEASING_RAILS.rdoc @@ -96,6 +96,8 @@ what to do in case anything goes wrong: $ rake all:build $ git commit -am'updating RAILS_VERSION' $ git tag -m'tagging rc release' v3.0.10.rc1 + $ git push + $ git push --tags $ for i in $(ls dist); do gem push $i; done === Send Rails release announcements From c7af6cf58e34926b3f8d39867482c974c30fd9cb Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 4 Aug 2011 16:31:57 -0700 Subject: [PATCH 097/345] we should not ignore all gems in here --- .gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index be764143aa..2d3c39d885 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -*.gem pkg .bundle Gemfile.lock @@ -22,4 +21,4 @@ railties/doc railties/guides/output railties/tmp .rvmrc -RDOC_MAIN.rdoc \ No newline at end of file +RDOC_MAIN.rdoc From 4265f2eaa50b9783059bc84c3f8d2d4001fa9b7a Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Mon, 25 Jul 2011 15:10:13 -0700 Subject: [PATCH 098/345] sync the getting started guide with master --- railties/guides/source/getting_started.textile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/railties/guides/source/getting_started.textile b/railties/guides/source/getting_started.textile index 0b89021392..6c8aa668b2 100644 --- a/railties/guides/source/getting_started.textile +++ b/railties/guides/source/getting_started.textile @@ -197,9 +197,10 @@ For example, the following HTTP request: DELETE /photos/17 -refers to a photo resource with an ID of 17 and indicates an action to be taken -upon it: deletion. REST is a natural web application architecture which Rails -abstracts, shielding you from RESTful complexities and browser quirks. +would be understood to refer to a photo resource with the ID of 17, and to +indicate a desired action - deleting that resource. REST is a natural style for +the architecture of web applications, and Rails hooks into this shielding you +from many of the RESTful complexities and browser quirks. If you'd like more details on REST as an architectural style, these resources are more approachable than Fielding's thesis: From 2dc6cca773380e55d2afe0d3de34fa7c68f9f7d7 Mon Sep 17 00:00:00 2001 From: Vijay Dev Date: Tue, 26 Jul 2011 19:35:16 +0530 Subject: [PATCH 099/345] move the note after the scaffold files listing --- .../guides/source/getting_started.textile | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/railties/guides/source/getting_started.textile b/railties/guides/source/getting_started.textile index 6c8aa668b2..3cca383616 100644 --- a/railties/guides/source/getting_started.textile +++ b/railties/guides/source/getting_started.textile @@ -536,21 +536,8 @@ command in your terminal: $ rails generate scaffold Post name:string title:string content:text -This will create a new database table called posts (plural of Post). The table -will have three columns, name (type string), title (type string) and content -(type text). It will also hook this new database up to Rails (details below). - -NOTE. While scaffolding will get you up and running quickly, the code it -generates is unlikely to be a perfect fit for your application. You'll most -probably want to customize the generated code. Many experienced Rails developers -avoid scaffolding entirely, preferring to write all or most of their source code -from scratch. Rails, however, makes it really simple to customize templates for -generated models, controllers, views and other source files. You'll find more -information in the "Creating and Customizing Rails Generators & -Templates":generators.html guide. - -The scaffold generator will build 17 files in your application, along with some -folders, and edit one more. Here's a quick overview of what it creates: +The scaffold generator will build several files in your application, along with some +folders, and edit config/routes.rb. Here's a quick overview of what it creates: |_.File |_.Purpose| |db/migrate/20100207214725_create_posts.rb |Migration to create the posts table in your database (your name will include a different timestamp)| @@ -571,6 +558,15 @@ folders, and edit one more. Here's a quick overview of what it creates: |test/unit/helpers/posts_helper_test.rb |Unit testing harness for the posts helper| |config/routes.rb |Edited to include routing information for posts| +NOTE. While scaffolding will get you up and running quickly, the code it +generates is unlikely to be a perfect fit for your application. You'll most +probably want to customize the generated code. Many experienced Rails developers +avoid scaffolding entirely, preferring to write all or most of their source code +from scratch. Rails, however, makes it really simple to customize templates for +generated models, controllers, views and other source files. You'll find more +information in the "Creating and Customizing Rails Generators & +Templates":generators.html guide. + h4. Running a Migration One of the products of the +rails generate scaffold+ command is a _database From a45c2d59343a27bdef51118f10faf180ee4ca3d1 Mon Sep 17 00:00:00 2001 From: Hendy Tanata Date: Wed, 27 Jul 2011 17:30:35 +0700 Subject: [PATCH 100/345] Fix two spaces between sententes on README.rdoc. --- README.rdoc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.rdoc b/README.rdoc index bca2126559..f87d6e9edb 100644 --- a/README.rdoc +++ b/README.rdoc @@ -3,11 +3,11 @@ Rails is a web-application framework that includes everything needed to create database-backed web applications according to the {Model-View-Controller (MVC)}[http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller] pattern. -Understanding the MVC pattern is key to understanding Rails. MVC divides your application +Understanding the MVC pattern is key to understanding Rails. MVC divides your application into three layers, each with a specific responsibility. The View layer is composed of "templates" that are responsible for providing -appropriate representations of your application's resources. Templates +appropriate representations of your application's resources. Templates can come in a variety of formats, but most view templates are HTML with embedded Ruby code (.erb files). @@ -21,7 +21,7 @@ provided by the ActiveModel module. You can read more about Active Record in its {README}[link:blob/master/activerecord/README.rdoc]. The Controller layer is responsible for handling incoming HTTP requests and providing a -suitable response. Usually this means returning HTML, but Rails controllers can also +suitable response. Usually this means returning HTML, but Rails controllers can also generate XML, JSON, PDFs, mobile-specific views, and more. Controllers manipulate models and render view templates in order to generate the appropriate HTTP response. From e84ea65e71062109d9e95e36ea0c5640fb0d6d6f Mon Sep 17 00:00:00 2001 From: Alberto Perdomo Date: Thu, 28 Jul 2011 00:51:14 +0100 Subject: [PATCH 101/345] Association and Callbacks guide: Added section on shortcut syntax 'validates'. --- ...ctive_record_validations_callbacks.textile | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/railties/guides/source/active_record_validations_callbacks.textile b/railties/guides/source/active_record_validations_callbacks.textile index ce0b5416de..e2ec874190 100644 --- a/railties/guides/source/active_record_validations_callbacks.textile +++ b/railties/guides/source/active_record_validations_callbacks.textile @@ -612,6 +612,61 @@ class Movie < ActiveRecord::Base end +h3. Shortcut helper + +There is a special method +validates+ that is a shortcut to all default validators and any custom validator classes ending in 'Validator'. Note that Rails default validators can be overridden inside specific classes by creating custom validator classes in their place such as +PresenceValidator+. + +h4. Multiple validations for a single attribue + +In cases where you want multiple validations for a single attribute you can do it with a one-liner. + + +class User < ActiveRecord::Base + validates :password, :presence => true, :confirmation => true, :length => { :minimum => 6 } +end + + +h4. Combining standard validations with custom validators + +You can also combine standard validations with your own custom validators. + + +class EmailValidator < ActiveModel::EachValidator + def validate_each(record, attribute, value) + record.errors[attribute] << (options[:message] || "is not an email") unless + value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i + end +end + +class Person + include ActiveModel::Validations + attr_accessor :name, :email + + validates :name, :presence => true, :uniqueness => true, :length => { :maximum => 100 } + validates :email, :presence => true, :email => true +end + + +h4. Validating multiple attributes with the same criteria + +If you have a case where you want to apply the same validations to multiple attributes you can do that as well. + + +class BlogPost < ActiveRecord::Base + validates :title, :body, :presence => true +end + + +h4. Using the standard options + +The shortcut syntax is also compatible with the standard options +:allow_nil+, +:allow_blank+, etc. as well as the conditional options +:if+ and +unless+. + + +class User < ActiveRecord::Base + validates :password, :presence => { :if => :password_required? }, :confirmation => true +end + + h3. Working with Validation Errors In addition to the +valid?+ and +invalid?+ methods covered earlier, Rails provides a number of methods for working with the +errors+ collection and inquiring about the validity of objects. From 3c3f8087647a15a5e88dd18a45d41358eacce142 Mon Sep 17 00:00:00 2001 From: Pete Campbell Date: Thu, 28 Jul 2011 09:44:51 -0400 Subject: [PATCH 102/345] Explicitly included hashes in sentence regarding SQL-injection-safe forms --- activerecord/lib/active_record/base.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 4136868b39..461df0555f 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -63,9 +63,9 @@ module ActiveRecord #:nodoc: # == Conditions # # Conditions can either be specified as a string, array, or hash representing the WHERE-part of an SQL statement. - # The array form is to be used when the condition input is tainted and requires sanitization. The string form can - # be used for statements that don't involve tainted data. The hash form works much like the array form, except - # only equality and range is possible. Examples: + # The array form is to be used when the condition input is tainted and requires sanitization. The string and hash + # forms can be used for statements that don't involve tainted data. The hash form works much like the array form, + # except only equality and range is possible. Examples: # # class User < ActiveRecord::Base # def self.authenticate_unsafely(user_name, password) From 07f172ff83a763b33215515bbf37646e61a96fb1 Mon Sep 17 00:00:00 2001 From: ejy Date: Thu, 28 Jul 2011 18:40:35 +0200 Subject: [PATCH 103/345] Removed trailing slash of 'Download and installation' Github URL as per convention --- activerecord/README.rdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/README.rdoc b/activerecord/README.rdoc index 822276589b..8c5c544773 100644 --- a/activerecord/README.rdoc +++ b/activerecord/README.rdoc @@ -203,7 +203,7 @@ The latest version of Active Record can be installed with Rubygems: Source code can be downloaded as part of the Rails project on GitHub -* https://github.com/rails/rails/tree/master/activerecord/ +* https://github.com/rails/rails/tree/master/activerecord == License From d8c77fa16c96f566cf0ba39c9d4d49257d03e21a Mon Sep 17 00:00:00 2001 From: Vijay Dev Date: Fri, 29 Jul 2011 01:13:58 +0530 Subject: [PATCH 104/345] document meta method --- actionpack/lib/action_dispatch/http/request.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index b80574f497..37d0a3e0b8 100644 --- a/actionpack/lib/action_dispatch/http/request.rb +++ b/actionpack/lib/action_dispatch/http/request.rb @@ -29,9 +29,9 @@ module ActionDispatch ENV_METHODS.each do |env| class_eval <<-METHOD, __FILE__, __LINE__ + 1 - def #{env.sub(/^HTTP_/n, '').downcase} - @env["#{env}"] - end + def #{env.sub(/^HTTP_/n, '').downcase} # def accept_charset + @env["#{env}"] # @env["HTTP_ACCEPT_CHARSET"] + end # end METHOD end From 60af023107c8b11e2a07b8950d9fea8849fe2c32 Mon Sep 17 00:00:00 2001 From: Arun Agrawal Date: Fri, 19 Aug 2011 09:47:46 +0000 Subject: [PATCH 105/345] Extra "l" removed before h2. --- railties/guides/source/i18n.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/guides/source/i18n.textile b/railties/guides/source/i18n.textile index 0c8e4e974d..5a6343472c 100644 --- a/railties/guides/source/i18n.textile +++ b/railties/guides/source/i18n.textile @@ -1,4 +1,4 @@ -lh2. Rails Internationalization (I18n) API +h2. Rails Internationalization (I18n) API The Ruby I18n (shorthand for _internationalization_) gem which is shipped with Ruby on Rails (starting from Rails 2.2) provides an easy-to-use and extensible framework for *translating your application to a single custom language* other than English or for *providing multi-language support* in your application. From e23bc8ac9b2e42e3bfd55c22d12f368325dba6c5 Mon Sep 17 00:00:00 2001 From: Bratish Goswami Date: Fri, 29 Jul 2011 21:49:43 +0530 Subject: [PATCH 106/345] extra '/' removed from url, which was not linked --- activeresource/README.rdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activeresource/README.rdoc b/activeresource/README.rdoc index b03e8c4c25..b7cf0292f0 100644 --- a/activeresource/README.rdoc +++ b/activeresource/README.rdoc @@ -28,7 +28,7 @@ The latest version of Active Support can be installed with Rubygems: Source code can be downloaded as part of the Rails project on GitHub -* https://github.com/rails/rails/tree/master/activeresource/ +* https://github.com/rails/rails/tree/master/activeresource === Configuration and Usage From b15cc2e8ec50188d14a840c1bb70d87c7e3cc6d3 Mon Sep 17 00:00:00 2001 From: Waynn Lue Date: Fri, 29 Jul 2011 16:01:20 -0700 Subject: [PATCH 107/345] Superfluous "the". --- README.rdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rdoc b/README.rdoc index f87d6e9edb..288a7a3c55 100644 --- a/README.rdoc +++ b/README.rdoc @@ -27,7 +27,7 @@ and render view templates in order to generate the appropriate HTTP response. In Rails, the Controller and View layers are handled together by Action Pack. These two layers are bundled in a single package due to their heavy interdependence. -This is unlike the relationship between the Active Record and Action Pack which are +This is unlike the relationship between Active Record and Action Pack which are independent. Each of these packages can be used independently outside of Rails. You can read more about Action Pack in its {README}[link:blob/master/actionpack/README.rdoc]. From 2350185e40af76c44eac79182fc143f965a998fd Mon Sep 17 00:00:00 2001 From: Bratish Goswami Date: Sat, 30 Jul 2011 12:53:21 +0530 Subject: [PATCH 108/345] '/' was outside of anchor tag. --- README.rdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rdoc b/README.rdoc index 288a7a3c55..5d1e3f5c5d 100644 --- a/README.rdoc +++ b/README.rdoc @@ -49,7 +49,7 @@ can read more about Action Pack in its {README}[link:blob/master/actionpack/READ Run with --help for options. -4. Go to http://localhost:3000/ and you'll see: +4. Go to http://localhost:3000 and you'll see: "Welcome aboard: You're riding Ruby on Rails!" From f56c2b88c58c33643050551c6824dfbf2b7b421e Mon Sep 17 00:00:00 2001 From: Vishnu Atrai Date: Sat, 30 Jul 2011 18:19:43 +0530 Subject: [PATCH 109/345] Active Resouce guide initial load --- railties/guides/source/active_resource_basics.textile | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 railties/guides/source/active_resource_basics.textile diff --git a/railties/guides/source/active_resource_basics.textile b/railties/guides/source/active_resource_basics.textile new file mode 100644 index 0000000000..5df8b6612d --- /dev/null +++ b/railties/guides/source/active_resource_basics.textile @@ -0,0 +1,11 @@ +h2. Active Resource Basics + +This guide should provide you with all you need to get started managing the connection between business objects and RESTful web services. It implements a way to map web-based resources to local objects with CRUD semantics. + +endprologue. + +WARNING. This Guide is based on Rails 3.0. Some of the code shown here will not work in earlier versions of Rails. + +h3. Changelog + +* July 30, 2011: Initial version by "Vishnu Atrai":http://github.com/vatrai \ No newline at end of file From e898556543fbfcbaeed88420590d555c857315cc Mon Sep 17 00:00:00 2001 From: Vishnu Atrai Date: Sat, 30 Jul 2011 18:21:21 +0530 Subject: [PATCH 110/345] Introduction for active resource --- railties/guides/source/active_resource_basics.textile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/railties/guides/source/active_resource_basics.textile b/railties/guides/source/active_resource_basics.textile index 5df8b6612d..5cf22f8e39 100644 --- a/railties/guides/source/active_resource_basics.textile +++ b/railties/guides/source/active_resource_basics.textile @@ -6,6 +6,10 @@ endprologue. WARNING. This Guide is based on Rails 3.0. Some of the code shown here will not work in earlier versions of Rails. +h3. Introduction + +Active Resource allows you to connect with RESTful web services. So, in Rails, Resource classes inherited from +ActiveResource::Base+ and live in +app/models+. + h3. Changelog * July 30, 2011: Initial version by "Vishnu Atrai":http://github.com/vatrai \ No newline at end of file From 8d1c642cae05cbf4c4fa44b9f7afb7c7a3727bd3 Mon Sep 17 00:00:00 2001 From: Vishnu Atrai Date: Sat, 30 Jul 2011 18:23:05 +0530 Subject: [PATCH 111/345] configuration for active resource --- railties/guides/source/active_resource_basics.textile | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/railties/guides/source/active_resource_basics.textile b/railties/guides/source/active_resource_basics.textile index 5cf22f8e39..f0cd25bfc2 100644 --- a/railties/guides/source/active_resource_basics.textile +++ b/railties/guides/source/active_resource_basics.textile @@ -10,6 +10,17 @@ h3. Introduction Active Resource allows you to connect with RESTful web services. So, in Rails, Resource classes inherited from +ActiveResource::Base+ and live in +app/models+. +h3. Configuration and Usage + +Putting Active Resource to use is very similar to Active Record. It's as simple as creating a model class +that inherits from ActiveResource::Base and providing a site class variable to it: + + +class Person < ActiveResource::Base + self.site = "http://api.people.com:3000/" +end + + h3. Changelog * July 30, 2011: Initial version by "Vishnu Atrai":http://github.com/vatrai \ No newline at end of file From c62cb2f2fbbd7987a4e09e9ffd63b60560785e6f Mon Sep 17 00:00:00 2001 From: Vishnu Atrai Date: Sat, 30 Jul 2011 18:24:18 +0530 Subject: [PATCH 112/345] usages of active resouce --- railties/guides/source/active_resource_basics.textile | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/railties/guides/source/active_resource_basics.textile b/railties/guides/source/active_resource_basics.textile index f0cd25bfc2..64f0949475 100644 --- a/railties/guides/source/active_resource_basics.textile +++ b/railties/guides/source/active_resource_basics.textile @@ -21,6 +21,15 @@ class Person < ActiveResource::Base end +Now the Person class is REST enabled and can invoke REST services very similarly to how Active Record invokes +life cycle methods that operate against a persistent store. + + +# Find a person with id = 1 +ryan = Person.find(1) +Person.exists?(1) # => true + + h3. Changelog * July 30, 2011: Initial version by "Vishnu Atrai":http://github.com/vatrai \ No newline at end of file From 38bfcffc596a6feb822af50bfd3cab93f7cf74a2 Mon Sep 17 00:00:00 2001 From: Vijay Dev Date: Sat, 30 Jul 2011 23:16:07 +0530 Subject: [PATCH 113/345] make the warning clear about the effect of using validates_associated on both sides on an association. --- .../lib/active_record/validations/associated.rb | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/activerecord/lib/active_record/validations/associated.rb b/activerecord/lib/active_record/validations/associated.rb index 5df85304a2..7af0352a31 100644 --- a/activerecord/lib/active_record/validations/associated.rb +++ b/activerecord/lib/active_record/validations/associated.rb @@ -17,15 +17,7 @@ module ActiveRecord # validates_associated :pages, :library # end # - # Warning: If, after the above definition, you then wrote: - # - # class Page < ActiveRecord::Base - # belongs_to :book - # - # validates_associated :book - # end - # - # this would specify a circular dependency and cause infinite recursion. + # WARNING: This validation must not be used on both ends of an association. Doing so will lead to a circular dependency and cause infinite recursion. # # NOTE: This validation will not fail if the association hasn't been assigned. If you want to # ensure that the association is both present and guaranteed to be valid, you also need to From 29772a136a6f148f3cc27ddfccc29bd9ddc672e3 Mon Sep 17 00:00:00 2001 From: Vijay Dev Date: Sat, 30 Jul 2011 23:50:31 +0530 Subject: [PATCH 114/345] remove some parts of the section on shortcut helpers, document custom validators --- ...ctive_record_validations_callbacks.textile | 110 ++++++++---------- 1 file changed, 48 insertions(+), 62 deletions(-) diff --git a/railties/guides/source/active_record_validations_callbacks.textile b/railties/guides/source/active_record_validations_callbacks.textile index e2ec874190..5789d36c6d 100644 --- a/railties/guides/source/active_record_validations_callbacks.textile +++ b/railties/guides/source/active_record_validations_callbacks.textile @@ -569,11 +569,50 @@ end All validations inside of +with_options+ block will have automatically passed the condition +:if => :is_admin?+ -h3. Creating Custom Validation Methods +h3. Performing Custom Validations -When the built-in validation helpers are not enough for your needs, you can write your own validation methods. +When the built-in validation helpers are not enough for your needs, you can write your own validators or validation methods as you prefer. -Simply create methods that verify the state of your models and add messages to the +errors+ collection when they are invalid. You must then register these methods by using one or more of the +validate+, +validate_on_create+ or +validate_on_update+ class methods, passing in the symbols for the validation methods' names. +h4. Custom Validators + +Custom validators are classes that extend ActiveModel::Validator. These classes must implement a +validate+ method which takes a record as an argument and performs the validation on it. The custom validator is called using the +validates_with+ method. + + +class MyValidator < ActiveModel::Validator + def validate(record) + if record.name.starts_with? 'X' + record.errors[:name] << 'Need a name starting with X please!' + end + end +end + +class Person + include ActiveModel::Validations + validates_with MyValidator +end + + +The easiest way to add custom validators for validating individual attributes is with the convenient ActiveModel::EachValidator. In this case, the custom validator class must implement a +validate_each+ method which takes three arguments: record, attribute and value which correspond to the instance, the attribute to be validated and the value of the attribute in the passed instance. + + +class EmailValidator < ActiveModel::EachValidator + def validate_each(record, attribute, value) + unless value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i + record.errors[attribute] << (options[:message] || "is not an email") + end + end +end + +class Person < ActiveRecord::Base + validates :email, :presence => true, :email => true +end + + +As shown in the example, you can also combine standard validations with your own custom validators. + +h4. Custom Methods + +You can also create methods that verify the state of your models and add messages to the +errors+ collection when they are invalid. You must then register these methods by using one or more of the +validate+, +validate_on_create+ or +validate_on_update+ class methods, passing in the symbols for the validation methods' names. You can pass more than one symbol for each class method and the respective validations will be run in the same order as they were registered. @@ -583,13 +622,15 @@ class Invoice < ActiveRecord::Base :discount_cannot_be_greater_than_total_value def expiration_date_cannot_be_in_the_past - errors.add(:expiration_date, "can't be in the past") if - !expiration_date.blank? and expiration_date < Date.today + if !expiration_date.blank? and expiration_date < Date.today + errors.add(:expiration_date, "can't be in the past") + end end def discount_cannot_be_greater_than_total_value - errors.add(:discount, "can't be greater than total value") if - discount > total_value + if discount > total_value + errors.add(:discount, "can't be greater than total value") + end end end @@ -612,61 +653,6 @@ class Movie < ActiveRecord::Base end -h3. Shortcut helper - -There is a special method +validates+ that is a shortcut to all default validators and any custom validator classes ending in 'Validator'. Note that Rails default validators can be overridden inside specific classes by creating custom validator classes in their place such as +PresenceValidator+. - -h4. Multiple validations for a single attribue - -In cases where you want multiple validations for a single attribute you can do it with a one-liner. - - -class User < ActiveRecord::Base - validates :password, :presence => true, :confirmation => true, :length => { :minimum => 6 } -end - - -h4. Combining standard validations with custom validators - -You can also combine standard validations with your own custom validators. - - -class EmailValidator < ActiveModel::EachValidator - def validate_each(record, attribute, value) - record.errors[attribute] << (options[:message] || "is not an email") unless - value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i - end -end - -class Person - include ActiveModel::Validations - attr_accessor :name, :email - - validates :name, :presence => true, :uniqueness => true, :length => { :maximum => 100 } - validates :email, :presence => true, :email => true -end - - -h4. Validating multiple attributes with the same criteria - -If you have a case where you want to apply the same validations to multiple attributes you can do that as well. - - -class BlogPost < ActiveRecord::Base - validates :title, :body, :presence => true -end - - -h4. Using the standard options - -The shortcut syntax is also compatible with the standard options +:allow_nil+, +:allow_blank+, etc. as well as the conditional options +:if+ and +unless+. - - -class User < ActiveRecord::Base - validates :password, :presence => { :if => :password_required? }, :confirmation => true -end - - h3. Working with Validation Errors In addition to the +valid?+ and +invalid?+ methods covered earlier, Rails provides a number of methods for working with the +errors+ collection and inquiring about the validity of objects. From 54e7694982510e22810c064ae3594f74209c94b9 Mon Sep 17 00:00:00 2001 From: Vijay Dev Date: Sat, 30 Jul 2011 23:53:11 +0530 Subject: [PATCH 115/345] prefer to use if..end unless the condition is simple/compact --- .../source/active_record_validations_callbacks.textile | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/railties/guides/source/active_record_validations_callbacks.textile b/railties/guides/source/active_record_validations_callbacks.textile index 5789d36c6d..977e736d25 100644 --- a/railties/guides/source/active_record_validations_callbacks.textile +++ b/railties/guides/source/active_record_validations_callbacks.textile @@ -1143,8 +1143,9 @@ Here's an example where we create a class with an +after_destroy+ callback for a class PictureFileCallbacks def after_destroy(picture_file) - File.delete(picture_file.filepath) - if File.exists?(picture_file.filepath) + if File.exists?(picture_file.filepath) + File.delete(picture_file.filepath) + end end end @@ -1162,8 +1163,9 @@ Note that we needed to instantiate a new +PictureFileCallbacks+ object, since we class PictureFileCallbacks def self.after_destroy(picture_file) - File.delete(picture_file.filepath) - if File.exists?(picture_file.filepath) + if File.exists?(picture_file.filepath) + File.delete(picture_file.filepath) + end end end From 4e28c40bfd16a1d9f41c8c713f2b4cc19d5dd1f7 Mon Sep 17 00:00:00 2001 From: Vijay Dev Date: Sun, 31 Jul 2011 01:32:20 +0530 Subject: [PATCH 116/345] 3.1 release notes draft --- .../guides/source/3_1_release_notes.textile | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 railties/guides/source/3_1_release_notes.textile diff --git a/railties/guides/source/3_1_release_notes.textile b/railties/guides/source/3_1_release_notes.textile new file mode 100644 index 0000000000..0348259668 --- /dev/null +++ b/railties/guides/source/3_1_release_notes.textile @@ -0,0 +1,136 @@ +h2. Ruby on Rails 3.1 Release Notes + +Highlights in Rails 3.1: + +* Streaming +* Reversible Migrations +* Assets Pipeline +* jQuery as the default JavaScript library + +This release notes cover the major changes, but don't include every little bug fix and change. If you want to see everything, check out the "list of commits":https://github.com/rails/rails/commits/master in the main Rails repository on GitHub. + +endprologue. + +h3. Upgrading to Rails 3.1 + +If you're upgrading an existing application, it's a great idea to have good test coverage before going in. You should also first upgrade to Rails 3 and make sure your application still runs as expected before attempting to update to Rails 3.1. Then take heed of the following changes: + +h4. Rails 3.1 requires at least Ruby 1.8.7 + +Rails 3.1 requires Ruby 1.8.7 or higher. Support for all of the previous Ruby versions has been dropped officially and you should upgrade as early as possible. Rails 3.1 is also compatible with Ruby 1.9.2. + +TIP: Note that Ruby 1.8.7 p248 and p249 have marshaling bugs that crash Rails. Ruby Enterprise Edition have these fixed since release 1.8.7-2010.02 though. On the 1.9 front, Ruby 1.9.1 is not usable because it outright segfaults, so if you want to use 1.9.x jump on 1.9.2 for smooth sailing. + +TODO. What else? + +h3. Creating a Rails 3.1 application + + +# You should have the 'rails' rubygem installed +$ rails new myapp +$ cd myapp + + +h4. Vendoring Gems + +Rails now uses a +Gemfile+ in the application root to determine the gems you require for your application to start. This +Gemfile+ is processed by the "Bundler":https://github.com/carlhuda/bundler, which then installs all your dependencies. It can even install all the dependencies locally to your application so that it doesn't depend on the system gems. + +More information: - "bundler homepage":http://gembundler.com + +h4. Living on the Edge + ++Bundler+ and +Gemfile+ makes freezing your Rails application easy as pie with the new dedicated bundle command. If you want to bundle straight from the Git repository, you can pass the +--edge+ flag: + + +$ rails new myapp --edge + + +If you have a local checkout of the Rails repository and want to generate an application using that, you can pass the +--dev+ flag: + + +$ ruby /path/to/rails/bin/rails new myapp --dev + + +h3. Rails Architectural Changes + +h4. Assets Pipeline + +h3. Documentation + +The documentation in the Rails tree is being updated with all the API changes, additionally, the "Rails Edge Guides":http://edgeguides.rubyonrails.org/ are being updated one by one to reflect the changes in Rails 3.0. The guides at "guides.rubyonrails.org":http://guides.rubyonrails.org/ however will continue to contain only the stable version of Rails (at this point, version 2.3.5, until 3.0 is released). + +More Information: - "Rails Documentation Projects":http://weblog.rubyonrails.org/2009/1/15/rails-documentation-projects. + +h3. Internationalization + +h3. Railties + +h3. Action Pack + +h4. Abstract Controller + +h4. Action Controller + +h4. Action Dispatch + +h4. Action View + +h3. Active Record + +h3. Active Model + +The major changes in Active Model are: + +* +attr_accessible+ accepts an option +:as+ to specify a role. + +* +InclusionValidator+, +ExclusionValidator+, and +FormatValidator+ now accepts an option which can be a proc, a lambda, or anything that respond to +call+. This option will be called with the current record as an argument and returns an object which respond to +include?+ for +InclusionValidator+ and +ExclusionValidator+, and returns a regular expression object for +FormatValidator+. + +* Added ActiveModel::SecurePassword to encapsulate dead-simple password usage with BCrypt encryption and salting. + +* ActiveModel::AttributeMethods allows attributes to be defined on demand. + +h3. Active Resource + +The changes in Active Resource are: + +* The default format has been changed to JSON for all requests. If you want to continue to use XML you will need to set self.format = :xml in the class. For example, + + +class User < ActiveResource::Base + self.format = :xml +end + + +h3. Active Support + +The main changes in Active Support are: + +* ActiveSupport::Dependencies now raises +NameError+ if it finds an existing constant in load_missing_constant. + +* Added a new reporting method Kernel#quietly which silences both STDOUT and STDERR. + +* Added String#inquiry as a convenience method for turning a String into a +StringInquirer+ object. + +* Added Object#in? to test if an object is included in another object. + +* LocalCache strategy is now a real middleware class and no longer an anonymous class. + +* ActiveSupport::Dependencies::ClassCache class has been introduced for holding references to reloadable classes. + +* ActiveSupport::Dependencies::Reference has been refactored to take direct advantage of the new ClassCache. + +* Backports Range#cover? as an alias for Range#include? in Ruby 1.8. + +* Added +weeks_ago+ and +prev_week+ to Date/DateTime/Time. + +* Added +before_remove_const+ callback to ActiveSupport::Dependencies.remove_unloadable_constants! + +Deprecations: + +* ActiveSupport::SecureRandom is deprecated in favor of +SecureRandom+ from the Ruby standard library. + +h3. Credits + +See the "full list of contributors to Rails":http://contributors.rubyonrails.org/ for the many people who spent many hours making Rails, the stable and robust framework it is. Kudos to all of them. + +Rails 3.1 Release Notes were compiled by "Vijay Dev":https://github.com/vijaydev. From fe6b967aea0c562a5bcae54225dbce29013991b9 Mon Sep 17 00:00:00 2001 From: Vijay Dev Date: Sun, 31 Jul 2011 03:05:24 +0530 Subject: [PATCH 117/345] 3.1 release notes - added AP and Railties sections --- .../guides/source/3_1_release_notes.textile | 142 ++++++++++++++++++ 1 file changed, 142 insertions(+) diff --git a/railties/guides/source/3_1_release_notes.textile b/railties/guides/source/3_1_release_notes.textile index 0348259668..f520e4dfea 100644 --- a/railties/guides/source/3_1_release_notes.textile +++ b/railties/guides/source/3_1_release_notes.textile @@ -55,6 +55,8 @@ h3. Rails Architectural Changes h4. Assets Pipeline +TODO. point to assets guide, talk about rake assets:* tasks + h3. Documentation The documentation in the Rails tree is being updated with all the API changes, additionally, the "Rails Edge Guides":http://edgeguides.rubyonrails.org/ are being updated one by one to reflect the changes in Rails 3.0. The guides at "guides.rubyonrails.org":http://guides.rubyonrails.org/ however will continue to contain only the stable version of Rails (at this point, version 2.3.5, until 3.0 is released). @@ -65,8 +67,148 @@ h3. Internationalization h3. Railties +* jQuery is the new default JavaScript library. + +* jQuery and prototype are no longer vendored and is provided from now on by the jquery-rails and prototype-rails gems. + +* The application generator accepts an option -j which can be an arbitrary string. If passed "foo", the gem "foo-rails" is added to the Gemfile, and the application JavaScript manifest requires "foo" and "foo_ujs". Currently only "prototype-rails" and "jquery-rails" exist and provide those files via the asset pipeline. + +* Generating an application or a plugin runs bundle install unless --skip-gemfile or --skip-bundle is specified. + +* The controller and resource generators will now automatically produce asset stubs (this can be turned off with --skip-assets). These stubs will use CoffeeScript and Sass, if those libraries are available. + +* Scaffold and app generators use the Ruby 1.9 style hash when running on Ruby 1.9. To generate old style hash, --old-style-hash can be passed. + +* Scaffold controller generator creates format block for JSON instead of XML. + +* Active Record logging is directed to STDOUT and shown inline in the console. + +* Added +config.force_ssl+ configuration which loads Rack::SSL middleware and force all requests to be under HTTPS protocol. + +* Added +rails plugin new+ command which generates a Rails plugin with gemspec, tests and a dummy application for testing. + +* Added Rack::Etag and Rack::ConditionalGet to the default middleware stack. + +* Added Rack::Cache to the default middleware stack. + +* TODO Engine related changes + h3. Action Pack +TODO split items into controller/view sections. + +* A warning is given out if the CSRF token authenticity cannot be verified. + +* Allows AM/PM format in datetime selectors. + +* auto_link has been removed from Rails and extracted into the "rails_autolink gem":https://github.com/tenderlove/rails_autolink + +* Added streaming support, you can enable it with: + + +class PostsController < ActionController::Base + stream :only => :index +end + + +Please read the docs at ActionController::Streaming for more information. TODO add links to api docs. + +* Added ActionDispatch::Request.ignore_accept_header to ignore accept headers. + +* Created ActionView::Renderer and specified an API for ActionView::Context. + +* Added ActionController::ParamsWrapper to wrap parameters into a nested hash, and will be turned on for JSON request in new applications by default. This can be customized by setting ActionController::Base.wrap_parameters in config/initializer/wrap_parameters.rb. + +* Added Base.http_basic_authenticate_with to do simple http basic authentication with a single class method call. + + +class PostsController < ApplicationController + USER_NAME, PASSWORD = "dhh", "secret" + + before_filter :authenticate, :except => [ :index ] + + def index + render :text => "Everyone can see me!" + end + + def edit + render :text => "I'm only accessible if you know the password" + end + + private + def authenticate + authenticate_or_request_with_http_basic do |user_name, password| + user_name == USER_NAME && password == PASSWORD + end + end +end + + +..can now be written as + + +class PostsController < ApplicationController + http_basic_authenticate_with :name => "dhh", :password => "secret", :except => :index + + def index + render :text => "Everyone can see me!" + end + + def edit + render :text => "I'm only accessible if you know the password" + end +end + + +* Specify +force_ssl+ in a controller to force the browser to transfer data via HTTPS protocol on that particular controller. To limit to specific actions, :only or :except can be used. + +* Allows FormHelper#form_for to specify the :method as a direct option instead of through the :html hash. form_for(@post, remote: true, method: :delete) instead of form_for(@post, remote: true, html: { method: :delete }) + +* Provided JavaScriptHelper#j() as an alias for JavaScriptHelper#escape_javascript(). This supersedes the Object#j() method that the JSON gem adds within templates using the JavaScriptHelper. + +* Sensitive query string parameters specified in config.filter_parameters will now be filtered out from the request paths in the log. + +* URL parameters which return nil for +to_param+ are now removed from the query string. + +* ActionDispatch::MiddlewareStack now uses composition over inheritance and is no longer an array. + +* Added an :authenticity_token option to +form_tag+ for custom handling or to omit the token by passing :authenticity_token => false. + +* Added HTML5 button_tag helper. + +* Template lookup now searches further up in the inheritance chain. + +* config.action_view.cache_template_loading is brought back which allows to decide whether templates should be cached or not. TODO from which version? + +* url_for and named url helpers now accept :subdomain and :domain as options. + +* The redirect route method now also accepts a hash of options which will only change the parts of the url in question, or an object which responds to call, allowing for redirects to be reused. + +* Added config.action_controller.include_all_helpers. By default helper :all is done in ActionController::Base, which includes all the helpers by default. Setting +include_all_helpers+ to false will result in including only application_helper and the helper corresponding to controller (like foo_helper for foo_controller). + +* Added a convenience idiom to generate HTML5 data-* attributes in tag helpers from a :data hash of options: + + +tag("div", :data => {:name => 'Stephen', :city_state => %w(Chicago IL)}) +# =>
+ + +Keys are dasherized. Values are JSON-encoded, except for strings and symbols. + +* The old template handler API is deprecated and the new API simply requires a template handler to respond to call. + +* rhtml and rxml are finally removed as template handlers. + +* Moved etag responsibility from ActionDispatch::Response to the middleware stack. + +* Rely on Rack::Session stores API for more compatibility across the Ruby world. This is backwards incompatible since Rack::Session expects #get_session to accept four arguments and requires #destroy_session instead of simply #destroy. + +* file_field automatically adds :multipart => true to the enclosing form. + +* +csrf_meta_tag+ is renamed to +csrf_meta_tags+ and aliases csrf_meta_tag for backwards compatibility. + +* Added Rack::Cache to the default stack. + h4. Abstract Controller h4. Action Controller From 384ac3eca731ea4c8da9b3e06ae29e98bf889409 Mon Sep 17 00:00:00 2001 From: Waynn Lue Date: Sat, 30 Jul 2011 18:27:08 -0700 Subject: [PATCH 118/345] "blog" is more common than "weblog" these days. --- actionmailer/README.rdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionmailer/README.rdoc b/actionmailer/README.rdoc index 63e3893316..de4740b2ed 100644 --- a/actionmailer/README.rdoc +++ b/actionmailer/README.rdoc @@ -10,7 +10,7 @@ Mail gem. It provides a way to make emails using templates in the same way that Action Controller renders views using templates. Additionally, an Action Mailer class can be used to process incoming email, -such as allowing a weblog to accept new posts from an email (which could even +such as allowing a blog to accept new posts from an email (which could even have been sent from a phone). == Sending emails From 8362b070dc959a11042afc9a9a5a8529178c4090 Mon Sep 17 00:00:00 2001 From: Arun Agrawal Date: Sun, 31 Jul 2011 16:56:40 +0530 Subject: [PATCH 119/345] Rack::Sendfile is no more default middleware. --- railties/guides/source/command_line.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/guides/source/command_line.textile b/railties/guides/source/command_line.textile index b34506d4d8..627e22f2de 100644 --- a/railties/guides/source/command_line.textile +++ b/railties/guides/source/command_line.textile @@ -386,7 +386,7 @@ Action Pack version 3.1.0 Active Resource version 3.1.0 Action Mailer version 3.1.0 Active Support version 3.1.0 -Middleware ActionDispatch::Static, Rack::Lock, Rack::Runtime, Rails::Rack::Logger, ActionDispatch::ShowExceptions, ActionDispatch::RemoteIp, Rack::Sendfile, ActionDispatch::Callbacks, ActionDispatch::Cookies, ActionDispatch::Session::CookieStore, ActionDispatch::Flash, ActionDispatch::ParamsParser, Rack::MethodOverride, ActionDispatch::Head +Middleware ActionDispatch::Static, Rack::Lock, Rack::Runtime, Rails::Rack::Logger, ActionDispatch::ShowExceptions, ActionDispatch::RemoteIp, ActionDispatch::Callbacks, ActionDispatch::Cookies, ActionDispatch::Session::CookieStore, ActionDispatch::Flash, ActionDispatch::ParamsParser, Rack::MethodOverride, ActionDispatch::Head Application root /home/foobar/commandsapp Environment development From f63599825b440e214c09646501be33933d265562 Mon Sep 17 00:00:00 2001 From: Arun Agrawal Date: Sun, 31 Jul 2011 21:58:59 +0530 Subject: [PATCH 120/345] Adding more info as rake about is fixed --- railties/guides/source/command_line.textile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/railties/guides/source/command_line.textile b/railties/guides/source/command_line.textile index 627e22f2de..f48fa96451 100644 --- a/railties/guides/source/command_line.textile +++ b/railties/guides/source/command_line.textile @@ -389,6 +389,8 @@ Active Support version 3.1.0 Middleware ActionDispatch::Static, Rack::Lock, Rack::Runtime, Rails::Rack::Logger, ActionDispatch::ShowExceptions, ActionDispatch::RemoteIp, ActionDispatch::Callbacks, ActionDispatch::Cookies, ActionDispatch::Session::CookieStore, ActionDispatch::Flash, ActionDispatch::ParamsParser, Rack::MethodOverride, ActionDispatch::Head Application root /home/foobar/commandsapp Environment development +Database adapter sqlite3 +Database schema version 0 h4. +assets+ From 05f6135895d74f9058f550e6ece4593d2b6501fe Mon Sep 17 00:00:00 2001 From: Vijay Dev Date: Sun, 31 Jul 2011 23:23:25 +0530 Subject: [PATCH 121/345] 3.1 release notes Active Record changes, Architectural changes and organizing sections. --- .../guides/source/3_1_release_notes.textile | 195 +++++++++++++++--- 1 file changed, 168 insertions(+), 27 deletions(-) diff --git a/railties/guides/source/3_1_release_notes.textile b/railties/guides/source/3_1_release_notes.textile index f520e4dfea..7d85d7a600 100644 --- a/railties/guides/source/3_1_release_notes.textile +++ b/railties/guides/source/3_1_release_notes.textile @@ -55,15 +55,23 @@ h3. Rails Architectural Changes h4. Assets Pipeline -TODO. point to assets guide, talk about rake assets:* tasks +The major change in Rails 3.1 is the Assets Pipeline. It makes CSS and JavaScript first-class code citizens and enables proper organization, including use in plugins and engines. -h3. Documentation +The assets pipeline is powered by "Sprockets":https://github.com/sstephenson/sprockets and is covered in the "Asset Pipeline":asset_pipeline.html guide. -The documentation in the Rails tree is being updated with all the API changes, additionally, the "Rails Edge Guides":http://edgeguides.rubyonrails.org/ are being updated one by one to reflect the changes in Rails 3.0. The guides at "guides.rubyonrails.org":http://guides.rubyonrails.org/ however will continue to contain only the stable version of Rails (at this point, version 2.3.5, until 3.0 is released). +h4. HTTP Streaming -More Information: - "Rails Documentation Projects":http://weblog.rubyonrails.org/2009/1/15/rails-documentation-projects. +HTTP Streaming is another change that is new in Rails 3.1. This lets the browser download your stylesheets and JavaScript files while the server is still generating the response. This requires Ruby 1.9.2, is opt-in and requires support from the web server as well, but the popular combo of nginx and unicorn is ready to take advantage of it. -h3. Internationalization +h4. Default JS library is now jQuery + +jQuery is the default JavaScript library that ships with Rails 3.1. But if you use Prototype, it's simple to switch. + +h4. Identity Map + +Active Record has an Identity Map in Rails 3.1. An identity map keeps previously instantiated records and returns the object associated with the record if accessed again. The identity map is created on a per-request basis and is flushed at request completion. + +Rails 3.1 comes with the identity map turned off by default. h3. Railties @@ -95,13 +103,9 @@ h3. Railties h3. Action Pack -TODO split items into controller/view sections. +h4. Abstract Controller -* A warning is given out if the CSRF token authenticity cannot be verified. - -* Allows AM/PM format in datetime selectors. - -* auto_link has been removed from Rails and extracted into the "rails_autolink gem":https://github.com/tenderlove/rails_autolink +h4. Action Controller * Added streaming support, you can enable it with: @@ -111,13 +115,25 @@ class PostsController < ActionController::Base end -Please read the docs at ActionController::Streaming for more information. TODO add links to api docs. +Please read the docs at "ActionController::Streaming":http://edgeapi.rubyonrails.org/classes/ActionController/Streaming.html for more information. + +* Added ActionController::ParamsWrapper to wrap parameters into a nested hash, and will be turned on for JSON request in new applications by default. This can be customized by setting ActionController::Base.wrap_parameters in config/initializer/wrap_parameters.rb. + +h4. Action Dispatch * Added ActionDispatch::Request.ignore_accept_header to ignore accept headers. +h4. Action View + * Created ActionView::Renderer and specified an API for ActionView::Context. -* Added ActionController::ParamsWrapper to wrap parameters into a nested hash, and will be turned on for JSON request in new applications by default. This can be customized by setting ActionController::Base.wrap_parameters in config/initializer/wrap_parameters.rb. +TODO + +* A warning is given out if the CSRF token authenticity cannot be verified. + +* Allows AM/PM format in datetime selectors. + +* auto_link has been removed from Rails and extracted into the "rails_autolink gem":https://github.com/tenderlove/rails_autolink * Added Base.http_basic_authenticate_with to do simple http basic authentication with a single class method call. @@ -209,19 +225,148 @@ Keys are dasherized. Values are JSON-encoded, except for strings and symbols. * Added Rack::Cache to the default stack. -h4. Abstract Controller - -h4. Action Controller - -h4. Action Dispatch - -h4. Action View - h3. Active Record -h3. Active Model +* Added a class method pluralize_table_names to singularize/pluralize table names of individual models. Previously this could only be set globally for all models through ActiveRecord::Base.pluralize_table_names. + +class User < ActiveRecord::Base + self.pluralize_table_names = false +end + -The major changes in Active Model are: +* Added block setting of attributes to singular associations. The block will get called after the instance is initialized. + + +class User < ActiveRecord::Base + has_one :account +end + +user.build_account{ |a| a.credit_limit => 100.0 } + + +* Added ActiveRecord::Base.attribute_names to return a list of attribute names. This will return an empty array if the model is abstract or the table does not exist. + +* CSV Fixtures are deprecated and support will be removed in Rails 3.2.0 + +* ActiveRecord#new, ActiveRecord#create and ActiveRecord#update_attributes all accept a second hash as an option that allows you to specify which role to consider when assigning attributes. This is built on top of ActiveModel's new mass assignment capabilities: + + +class Post < ActiveRecord::Base + attr_accessible :title + attr_accessible :title, :published_at, :as => :admin +end + +Post.new(params[:post], :as => :admin) + + +* default_scope can now take a block, lambda, or any other object which responds to call for lazy evaluation: + +* Default scopes are now evaluated at the latest possible moment, to avoid problems where scopes would be created which would implicitly contain the default scope, which would then be impossible to get rid of via Model.unscoped. + +* PostgreSQL adapter only supports PostgreSQL version 8.2 and higher. + +* ConnectionManagement middleware is changed to clean up the connection pool after the rack body has been flushed. + +* Added an update_column method on ActiveRecord. This new method updates a given attribute on an object, skipping validations and callbacks. It is recommended to use #update_attribute unless you are sure you do not want to execute any callback, including the modification of the updated_at column. It should not be called on new records. + +* Associations with a :through option can now use any association as the through or source association, including other associations which have a :through option and has_and_belongs_to_many associations. + +* The configuration for the current database connection is now accessible via ActiveRecord::Base.connection_config. + +* limits and offsets are removed from COUNT queries unless both are supplied. + +People.limit(1).count # => 'SELECT COUNT(*) FROM people' +People.offset(1).count # => 'SELECT COUNT(*) FROM people' +People.limit(1).offset(1).count # => 'SELECT COUNT(*) FROM people LIMIT 1 OFFSET 1' + + +* ActiveRecord::Associations::AssociationProxy has been split. There is now an +Association+ class (and subclasses) which are responsible for operating on associations, and then a separate, thin wrapper +called+ CollectionProxy, which proxies collection associations. This prevents namespace pollution, separates concerns, and will allow further refactorings. + +* Singular associations (has_one, belongs_to) no longer have a proxy and simply returns the associated record or nil. This means that you should not use undocumented methods such as bob.mother.create - use bob.create_mother instead. + +* Support the :dependent option on has_many :through associations. For historical and practical reasons, :delete_all is the default deletion strategy employed by association.delete(*records), despite the fact that the default strategy is :nullify for regular has_many. Also, this only works at all if the source reflection is a belongs_to. For other situations, you should directly modify the through association. + +* The behavior of association.destroy for has_and_belongs_to_many and has_many :through is changed. From now on, 'destroy' or 'delete' on an association will be taken to mean 'get rid of the link', not (necessarily) 'get rid of the associated records'. + +* Previously, has_and_belongs_to_many.destroy(*records) would destroy the records themselves. It would not delete any records in the join table. Now, it deletes the records in the join table. + +* Previously, has_many_through.destroy(*records) would destroy the records themselves, and the records in the join table. [Note: This has not always been the case; previous version of Rails only deleted the records themselves.] Now, it destroys only the records in the join table. + +* Note that this change is backwards-incompatible to an extent, but there is unfortunately no way to 'deprecate' it before changing it. The change is being made in order to have consistency as to the meaning of 'destroy' or 'delete' across the different types of associations. If you wish to destroy the records themselves, you can do records.association.each(&:destroy) + +* Add :bulk => true option to +change_table+ to make all the schema changes defined in a block using a single ALTER statement. + + +change_table(:users, :bulk => true) do |t| + t.string :company_name + t.change :birthdate, :datetime +end + + +* Removed support for accessing attributes on a +has_and_belongs_to_many+ join table. has_many :through needs to be used. + +* Added a +create_association!+ method for +has_one+ and +belongs_to+ associations. + +* Migrations are now reversible, meaning that Rails will figure out how to reverse your migrations. To use reversible migrations, just define the +change+ method. + +class MyMigration < ActiveRecord::Migration + def change + create_table(:horses) do + t.column :content, :text + t.column :remind_at, :datetime + end + end +end + + +* Some things cannot be automatically reversed for you. If you know how to reverse those things, you should define 'up' and 'down' in your migration. If you define something in change that cannot be reversed, an +IrreversibleMigration+ exception will be raised when going down. + +* Migrations now use instance methods rather than class methods: + +class FooMigration < ActiveRecord::Migration + def up # Not self.up + ... + end +end + + +* Migration files generated from model and constructive migration generators (for example, add_name_to_users) use the reversible migration's change method instead of the ordinary up and down methods. + +* Removed support for interpolating string SQL conditions on associations. Instead, a proc should be used. + + +has_many :things, :conditions => 'foo = #{bar}' # before +has_many :things, :conditions => proc { "foo = #{bar}" } # after + + +Inside the proc, 'self' is the object which is the owner of the association, unless you are eager loading the association, in which case 'self' is the class which the association is within. + +You can have any "normal" conditions inside the proc, so the following will work too: + +has_many :things, :conditions => proc { ["foo = ?", bar] } + + +* Previously :insert_sql and :delete_sql on has_and_belongs_to_many association allowed you to call 'record' to get the record being inserted or deleted. This is now passed as an argument to the proc. + +* Added ActiveRecord::Base#has_secure_password (via ActiveModel::SecurePassword) to encapsulate dead-simple password usage with BCrypt encryption and salting. + +# Schema: User(name:string, password_digest:string, password_salt:string) +class User < ActiveRecord::Base + has_secure_password +end + + +* When a model is generated +add_index+ is added by default for +belongs_to+ or +references+ columns. + +* Setting the id of a belongs_to object will update the reference to the object. + +* ActiveRecord::Base#dup and ActiveRecord::Base#clone semantics have changed to closer match normal Ruby dup and clone semantics. + +* Calling ActiveRecord::Base#clone will result in a shallow copy of the record, including copying the frozen state. No callbacks will be called. + +* Calling ActiveRecord::Base#dup will duplicate the record, including calling after initialize hooks. Frozen state will not be copied, and all associations will be cleared. A duped record will return true for new_record?, have a nil id field, and is saveable. + +h3. Active Model * +attr_accessible+ accepts an option +:as+ to specify a role. @@ -233,8 +378,6 @@ The major changes in Active Model are: h3. Active Resource -The changes in Active Resource are: - * The default format has been changed to JSON for all requests. If you want to continue to use XML you will need to set self.format = :xml in the class. For example, @@ -245,8 +388,6 @@ end h3. Active Support -The main changes in Active Support are: - * ActiveSupport::Dependencies now raises +NameError+ if it finds an existing constant in load_missing_constant. * Added a new reporting method Kernel#quietly which silences both STDOUT and STDERR. From dbc10a09b3c6fbb239ea723e26c75456269b6761 Mon Sep 17 00:00:00 2001 From: Waynn Lue Date: Sun, 31 Jul 2011 11:56:47 -0700 Subject: [PATCH 122/345] typo in "wont" --- actionmailer/README.rdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionmailer/README.rdoc b/actionmailer/README.rdoc index de4740b2ed..42e612cd07 100644 --- a/actionmailer/README.rdoc +++ b/actionmailer/README.rdoc @@ -74,7 +74,7 @@ Or you can just chain the methods together like: == Setting defaults -It is possible to set default values that will be used in every method in your Action Mailer class. To implement this functionality, you just call the public class method default which you get for free from ActionMailer::Base. This method accepts a Hash as the parameter. You can use any of the headers e-mail messages has, like :from as the key. You can also pass in a string as the key, like "Content-Type", but Action Mailer does this out of the box for you, so you wont need to worry about that. Finally it is also possible to pass in a Proc that will get evaluated when it is needed. +It is possible to set default values that will be used in every method in your Action Mailer class. To implement this functionality, you just call the public class method default which you get for free from ActionMailer::Base. This method accepts a Hash as the parameter. You can use any of the headers e-mail messages has, like :from as the key. You can also pass in a string as the key, like "Content-Type", but Action Mailer does this out of the box for you, so you won't need to worry about that. Finally it is also possible to pass in a Proc that will get evaluated when it is needed. Note that every value you set with this method will get over written if you use the same key in your mailer method. From abfbab2713211dc6094165a1bb74fde5c17c2a74 Mon Sep 17 00:00:00 2001 From: Vishnu Atrai Date: Mon, 1 Aug 2011 20:37:42 +0530 Subject: [PATCH 123/345] Active Resource - guide for reading and writing data --- railties/guides/source/active_resource_basics.textile | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/railties/guides/source/active_resource_basics.textile b/railties/guides/source/active_resource_basics.textile index 64f0949475..8a36622814 100644 --- a/railties/guides/source/active_resource_basics.textile +++ b/railties/guides/source/active_resource_basics.textile @@ -24,10 +24,21 @@ end Now the Person class is REST enabled and can invoke REST services very similarly to how Active Record invokes life cycle methods that operate against a persistent store. +h3. Reading and Writing Data + +Active Resource make request over HTTP using a standard JSON format. It mirrors the RESTful routing built into Action Controller but will also work with any other REST service that properly implements the protocol. + +h4. Read + +Read requests use the GET method and expect the JSON form of whatever resource/resources is/are being requested. + # Find a person with id = 1 ryan = Person.find(1) +# Check if a person exists with id = 1 Person.exists?(1) # => true +# Get all resources of Person class +Person.all h3. Changelog From 163533b17d968d23eef0023e4c93338d5357d022 Mon Sep 17 00:00:00 2001 From: Vishnu Atrai Date: Mon, 1 Aug 2011 20:48:45 +0530 Subject: [PATCH 124/345] Active Resource - guide for create --- railties/guides/source/active_resource_basics.textile | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/railties/guides/source/active_resource_basics.textile b/railties/guides/source/active_resource_basics.textile index 8a36622814..e40ca4fc42 100644 --- a/railties/guides/source/active_resource_basics.textile +++ b/railties/guides/source/active_resource_basics.textile @@ -34,13 +34,22 @@ Read requests use the GET method and expect the JSON form of whatever resource/r # Find a person with id = 1 -ryan = Person.find(1) +person = Person.find(1) # Check if a person exists with id = 1 Person.exists?(1) # => true # Get all resources of Person class Person.all +h4. Create + +Creating a new resource submits the JSON form of the resource as the body of the request with HTTP POST method and parse the response into Active Resource object. + + +person = Person.create(:name => 'Vishnu') +person.id # => 1 + + h3. Changelog * July 30, 2011: Initial version by "Vishnu Atrai":http://github.com/vatrai \ No newline at end of file From eed1026e83e04aef4c455a15636dab2e0e28efe3 Mon Sep 17 00:00:00 2001 From: Vishnu Atrai Date: Mon, 1 Aug 2011 20:57:57 +0530 Subject: [PATCH 125/345] Active Resource - guide for update/save --- railties/guides/source/active_resource_basics.textile | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/railties/guides/source/active_resource_basics.textile b/railties/guides/source/active_resource_basics.textile index e40ca4fc42..1115b9848f 100644 --- a/railties/guides/source/active_resource_basics.textile +++ b/railties/guides/source/active_resource_basics.textile @@ -50,6 +50,16 @@ person = Person.create(:name => 'Vishnu') person.id # => 1 +h4. Update + +To update an existing resource, 'save' method is used. This method make a HTTP PUT request in JSON format. + + +person = Person.find(1) +person.name = 'Atrai' +person.save + + h3. Changelog * July 30, 2011: Initial version by "Vishnu Atrai":http://github.com/vatrai \ No newline at end of file From f3564b9e22ae318dadee6c21c52aba01f91b27bb Mon Sep 17 00:00:00 2001 From: Vishnu Atrai Date: Mon, 1 Aug 2011 21:02:48 +0530 Subject: [PATCH 126/345] Active Resource - guide for destroy --- railties/guides/source/active_resource_basics.textile | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/railties/guides/source/active_resource_basics.textile b/railties/guides/source/active_resource_basics.textile index 1115b9848f..332d113fa7 100644 --- a/railties/guides/source/active_resource_basics.textile +++ b/railties/guides/source/active_resource_basics.textile @@ -60,6 +60,15 @@ person.name = 'Atrai' person.save +h4. Delete + +'destroy' method makes a HTTP DELETE request for an existing resource in JSON format to delete that resource. + + +person = Person.find(1) +person.destroy + + h3. Changelog * July 30, 2011: Initial version by "Vishnu Atrai":http://github.com/vatrai \ No newline at end of file From 9e1a27a0ac4ef246079ac6f61f5b5916c68d0497 Mon Sep 17 00:00:00 2001 From: pbflinn Date: Mon, 1 Aug 2011 12:53:43 -0300 Subject: [PATCH 127/345] Fix typo 'console' -> 'constant' --- railties/guides/source/initialization.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/guides/source/initialization.textile b/railties/guides/source/initialization.textile index 477ee5a3a2..9b92edd250 100644 --- a/railties/guides/source/initialization.textile +++ b/railties/guides/source/initialization.textile @@ -71,7 +71,7 @@ module Rails end -The +rails/script_rails_loader+ file uses +RbConfig::Config+ to gather up the +bin_dir+ and +ruby_install_name+ values for the configuration which will result in a path such as +/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby+, which is the default path on Mac OS X. If you're running Windows the path may be something such as +C:/Ruby192/bin/ruby+. Anyway, the path on your system may be different, but the point of this is that it will point at the known ruby executable location for your install. The +RbConfig::CONFIG["EXEEXT"]+ will suffix this path with ".exe" if the script is running on Windows. This constant is used later on in +exec_script_rails!+. As for the +SCRIPT_RAILS+ console, we'll see that when we get to the +in_rails_application?+ method. +The +rails/script_rails_loader+ file uses +RbConfig::Config+ to gather up the +bin_dir+ and +ruby_install_name+ values for the configuration which will result in a path such as +/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby+, which is the default path on Mac OS X. If you're running Windows the path may be something such as +C:/Ruby192/bin/ruby+. Anyway, the path on your system may be different, but the point of this is that it will point at the known ruby executable location for your install. The +RbConfig::CONFIG["EXEEXT"]+ will suffix this path with ".exe" if the script is running on Windows. This constant is used later on in +exec_script_rails!+. As for the +SCRIPT_RAILS+ constant, we'll see that when we get to the +in_rails_application?+ method. Back in +rails/cli+, the next line is this: From b3719ee7ed4693c782087c56c2ba5984a473deb7 Mon Sep 17 00:00:00 2001 From: Vijay Dev Date: Wed, 3 Aug 2011 19:11:22 +0530 Subject: [PATCH 128/345] fixed incorrect tags --- railties/guides/source/migrations.textile | 32 +++++++++++------------ 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/railties/guides/source/migrations.textile b/railties/guides/source/migrations.textile index e51ee0f535..7b501807d6 100644 --- a/railties/guides/source/migrations.textile +++ b/railties/guides/source/migrations.textile @@ -477,7 +477,7 @@ Several methods are provided that allow you to control all this: For example, this migration -
+
 class CreateProducts < ActiveRecord::Migration
   def change
     suppress_messages do
@@ -496,7 +496,7 @@ class CreateProducts < ActiveRecord::Migration
     end
   end
 end
-
+ generates the following output @@ -525,7 +525,7 @@ Bob goes on vacation. Alice creates a migration for the +products+ table which adds a new column and initializes it. She also adds a validation to the Product model for the new column. -
+
 # db/migrate/20100513121110_add_flag_to_product.rb
 
 class AddFlagToProduct < ActiveRecord::Migration
@@ -534,19 +534,19 @@ class AddFlagToProduct < ActiveRecord::Migration
     Product.all.each { |f| f.update_attributes!(:flag => 'false') }
   end
 end
-
+ -
+
 # app/model/product.rb
 
 class Product < ActiveRecord::Base
   validates_presence_of :flag
 end
-
+ Alice adds a second migration which adds and initializes another column to the +products+ table and also adds a validation to the Product model for the new column. -
+
 # db/migrate/20100515121110_add_fuzz_to_product.rb
 
 class AddFuzzToProduct < ActiveRecord::Migration
@@ -555,16 +555,16 @@ class AddFuzzToProduct < ActiveRecord::Migration
     Product.all.each { |f| f.update_attributes! :fuzz => 'fuzzy' }
   end
 end
-
+ -
+
 # app/model/product.rb
 
 class Product < ActiveRecord::Base
   validates_presence_of :flag
   validates_presence_of :fuzz
 end
-
+ Both migrations work for Alice. @@ -575,12 +575,12 @@ Bob comes back from vacation and: The migration crashes because when the model attempts to save, it tries to validate the second added column, which is not in the database when the _first_ migration runs. -
+
 rake aborted!
 An error has occurred, this and all later migrations canceled:
 
 undefined method `fuzz' for #
-
+ A fix for this is to create a local model within the migration. This keeps rails from running the validations, so that the migrations run to completion. @@ -588,7 +588,7 @@ When using a faux model, it's a good idea to call +Product.reset_column_informat If Alice had done this instead, there would have been no problem: -
+
 # db/migrate/20100513121110_add_flag_to_product.rb
 
 class AddFlagToProduct < ActiveRecord::Migration
@@ -600,9 +600,9 @@ class AddFlagToProduct < ActiveRecord::Migration
     Product.all.each { |f| f.update_attributes!(:flag => false) }
   end
 end
-
+ -
+
 # db/migrate/20100515121110_add_fuzz_to_product.rb
 
 class AddFuzzToProduct < ActiveRecord::Migration
@@ -614,7 +614,7 @@ class AddFuzzToProduct < ActiveRecord::Migration
     Product.all.each { |f| f.update_attributes! :fuzz => 'fuzzy' }
   end
 end
-
+ h3. Schema Dumping and You From febdd6c96c827b8faee22ba9d15c1d943a70a6d3 Mon Sep 17 00:00:00 2001 From: Vijay Dev Date: Wed, 3 Aug 2011 19:13:12 +0530 Subject: [PATCH 129/345] minor changes in migrations guide --- railties/guides/source/migrations.textile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/railties/guides/source/migrations.textile b/railties/guides/source/migrations.textile index 7b501807d6..4476e067a6 100644 --- a/railties/guides/source/migrations.textile +++ b/railties/guides/source/migrations.textile @@ -540,7 +540,7 @@ end # app/model/product.rb class Product < ActiveRecord::Base - validates_presence_of :flag + validates :flag, :presence => true end @@ -561,8 +561,7 @@ end # app/model/product.rb class Product < ActiveRecord::Base - validates_presence_of :flag - validates_presence_of :fuzz + validates :flag, :fuzz, :presence => true end @@ -594,9 +593,10 @@ If Alice had done this instead, there would have been no problem: class AddFlagToProduct < ActiveRecord::Migration class Product < ActiveRecord::Base end + def change add_column :products, :flag, :int - Product.reset_column_information + Product.reset_column_information Product.all.each { |f| f.update_attributes!(:flag => false) } end end From 25845b3d42c899749913d948f952f332e275fd26 Mon Sep 17 00:00:00 2001 From: Vijay Dev Date: Wed, 3 Aug 2011 19:34:23 +0530 Subject: [PATCH 130/345] typo fix --- railties/guides/source/initialization.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/guides/source/initialization.textile b/railties/guides/source/initialization.textile index 9b92edd250..6ab2706d6b 100644 --- a/railties/guides/source/initialization.textile +++ b/railties/guides/source/initialization.textile @@ -33,7 +33,7 @@ end This file will attempt to load +rails/cli+ and if it cannot find it then add the +railties/lib+ path to the load path (+$:+) and will then try to require it again. -h4. +railites/lib/rails/cli.rb+ +h4. +railties/lib/rails/cli.rb+ This file looks like this: From 2e764c5fd1ae4757da2cd834ca310f3eeb8db3e0 Mon Sep 17 00:00:00 2001 From: JudeArasu Date: Wed, 3 Aug 2011 23:00:24 +0530 Subject: [PATCH 131/345] grammatical changes --- railties/guides/source/form_helpers.textile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/railties/guides/source/form_helpers.textile b/railties/guides/source/form_helpers.textile index bf2a7369a7..fa0ca5827a 100644 --- a/railties/guides/source/form_helpers.textile +++ b/railties/guides/source/form_helpers.textile @@ -45,7 +45,7 @@ NOTE: Throughout this guide, the +div+ with the hidden input elements will be ex h4. A Generic Search Form -One of the most basic forms you see on the web is a search form. This form contains: +One of the most basic forms you will see on the web is a search form. This form contains: # a form element with "GET" method, # a label for the input, @@ -807,3 +807,4 @@ h3. Authors * Mislav Marohnić * "Frederick Cheung":credits.html#fcheung + From 5f2c790cb7557e94f1d94b30299f44abe4c34dd1 Mon Sep 17 00:00:00 2001 From: Waynn Lue Date: Wed, 3 Aug 2011 21:43:55 -0700 Subject: [PATCH 132/345] The trailing '/' isn't being picked up by Github anyway, and the link works as is. --- actionmailer/README.rdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionmailer/README.rdoc b/actionmailer/README.rdoc index 42e612cd07..937b53a3b2 100644 --- a/actionmailer/README.rdoc +++ b/actionmailer/README.rdoc @@ -141,7 +141,7 @@ The latest version of Action Mailer can be installed with Rubygems: Source code can be downloaded as part of the Rails project on GitHub -* https://github.com/rails/rails/tree/master/actionmailer/ +* https://github.com/rails/rails/tree/master/actionmailer == License From 681d919e48c631c499d6a2536310b97cfbd6098b Mon Sep 17 00:00:00 2001 From: Rashmi Yadav Date: Thu, 4 Aug 2011 12:33:56 +0530 Subject: [PATCH 133/345] The trailing '/' isn't being picked up by Github anyway, and the link works as is. --- actionpack/README.rdoc | 2 +- activemodel/README.rdoc | 2 +- activeresource/README.rdoc | 2 +- activesupport/README.rdoc | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/actionpack/README.rdoc b/actionpack/README.rdoc index c494d78415..792862cb85 100644 --- a/actionpack/README.rdoc +++ b/actionpack/README.rdoc @@ -322,7 +322,7 @@ The latest version of Action Pack can be installed with Rubygems: Source code can be downloaded as part of the Rails project on GitHub -* https://github.com/rails/rails/tree/master/actionpack/ +* https://github.com/rails/rails/tree/master/actionpack == License diff --git a/activemodel/README.rdoc b/activemodel/README.rdoc index a0e6b4d9b3..5f0d340307 100644 --- a/activemodel/README.rdoc +++ b/activemodel/README.rdoc @@ -192,7 +192,7 @@ The latest version of Active Model can be installed with Rubygems: Source code can be downloaded as part of the Rails project on GitHub -* https://github.com/rails/rails/tree/master/activemodel/ +* https://github.com/rails/rails/tree/master/activemodel == License diff --git a/activeresource/README.rdoc b/activeresource/README.rdoc index b7cf0292f0..6f45fe3598 100644 --- a/activeresource/README.rdoc +++ b/activeresource/README.rdoc @@ -36,7 +36,7 @@ Putting Active Resource to use is very similar to Active Record. It's as simple that inherits from ActiveResource::Base and providing a site class variable to it: class Person < ActiveResource::Base - self.site = "http://api.people.com:3000/" + self.site = "http://api.people.com:3000" end Now the Person class is REST enabled and can invoke REST services very similarly to how Active Record invokes diff --git a/activesupport/README.rdoc b/activesupport/README.rdoc index a38ad76f43..cc3981e74d 100644 --- a/activesupport/README.rdoc +++ b/activesupport/README.rdoc @@ -14,7 +14,7 @@ The latest version of Active Support can be installed with Rubygems: Source code can be downloaded as part of the Rails project on GitHub -* https://github.com/rails/rails/tree/master/activesupport/ +* https://github.com/rails/rails/tree/master/activesupport == License From e82b4901eb8f5f3582a079e88c75a4fbc7dea767 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Thu, 4 Aug 2011 15:02:13 -0700 Subject: [PATCH 134/345] Revert "grammatical changes" Reason: As discussed in GitHub, it is debatable, and present tense is fine (and simple, and preferred). This reverts commit 54ccda9f0a5e4a5e72a4c159dc8787faaf65e8a2. --- railties/guides/source/form_helpers.textile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/railties/guides/source/form_helpers.textile b/railties/guides/source/form_helpers.textile index fa0ca5827a..bf2a7369a7 100644 --- a/railties/guides/source/form_helpers.textile +++ b/railties/guides/source/form_helpers.textile @@ -45,7 +45,7 @@ NOTE: Throughout this guide, the +div+ with the hidden input elements will be ex h4. A Generic Search Form -One of the most basic forms you will see on the web is a search form. This form contains: +One of the most basic forms you see on the web is a search form. This form contains: # a form element with "GET" method, # a label for the input, @@ -807,4 +807,3 @@ h3. Authors * Mislav Marohnić * "Frederick Cheung":credits.html#fcheung - From 9e18380a323c7087b2079ec479d26ce899268b72 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Thu, 4 Aug 2011 15:14:06 -0700 Subject: [PATCH 135/345] Revert "Explicitly included hashes in sentence regarding SQL-injection-safe forms" Reason: The hash form is secure, and preferred over the array form if possible. This reverts commit 6dc749596c328c44c80f898d5fa860fff6cab783. --- activerecord/lib/active_record/base.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 461df0555f..4136868b39 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -63,9 +63,9 @@ module ActiveRecord #:nodoc: # == Conditions # # Conditions can either be specified as a string, array, or hash representing the WHERE-part of an SQL statement. - # The array form is to be used when the condition input is tainted and requires sanitization. The string and hash - # forms can be used for statements that don't involve tainted data. The hash form works much like the array form, - # except only equality and range is possible. Examples: + # The array form is to be used when the condition input is tainted and requires sanitization. The string form can + # be used for statements that don't involve tainted data. The hash form works much like the array form, except + # only equality and range is possible. Examples: # # class User < ActiveRecord::Base # def self.authenticate_unsafely(user_name, password) From e44efac0865a66b0546e32b4c6f23605a98a5845 Mon Sep 17 00:00:00 2001 From: Ilya Grigorik Date: Thu, 4 Aug 2011 19:17:03 -0400 Subject: [PATCH 136/345] Clear out tmp/cache when assets:clean is invoked. Otherwise, if bad data is cached in tmp/clear then the next invocation of assets:precompile (or a regular incoming request) will pickup files from tmp without regenerating them from source. --- actionpack/lib/sprockets/assets.rake | 2 +- railties/test/application/assets_test.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/actionpack/lib/sprockets/assets.rake b/actionpack/lib/sprockets/assets.rake index 50278cffcd..0349b2865e 100644 --- a/actionpack/lib/sprockets/assets.rake +++ b/actionpack/lib/sprockets/assets.rake @@ -16,7 +16,7 @@ namespace :assets do end desc "Remove compiled assets" - task :clean => :environment do + task :clean => [:environment, 'tmp:cache:clear'] do assets = Rails.application.config.assets public_asset_path = Rails.public_path + assets.prefix rm_rf public_asset_path, :secure => true diff --git a/railties/test/application/assets_test.rb b/railties/test/application/assets_test.rb index 802b737483..38dd3f5a3f 100644 --- a/railties/test/application/assets_test.rb +++ b/railties/test/application/assets_test.rb @@ -80,7 +80,7 @@ module ApplicationTests Dir.chdir(app_path){ `bundle exec rake assets:clean` } end - files = Dir["#{app_path}/public/assets/**/*"] + files = Dir["#{app_path}/public/assets/**/*", "#{app_path}/tmp/cache/*"] assert_equal 0, files.length, "Expected no assets, but found #{files.join(', ')}" end From ed5c6d254c9ef5d44a11159561fddde7a3033874 Mon Sep 17 00:00:00 2001 From: Ilya Grigorik Date: Thu, 4 Aug 2011 23:48:40 -0400 Subject: [PATCH 137/345] generate environment dependent asset digests If two different environments are configured to use the pipeline, but one has an extra step (such as compression) then without taking the environment into account you may end up serving wrong assets --- actionpack/lib/sprockets/railtie.rb | 1 + actionpack/test/template/sprockets_helper_test.rb | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/actionpack/lib/sprockets/railtie.rb b/actionpack/lib/sprockets/railtie.rb index c8438e6043..0c2eb5075b 100644 --- a/actionpack/lib/sprockets/railtie.rb +++ b/actionpack/lib/sprockets/railtie.rb @@ -20,6 +20,7 @@ module Sprockets app.assets = Sprockets::Environment.new(app.root.to_s) do |env| env.static_root = File.join(app.root.join('public'), config.assets.prefix) env.logger = ::Rails.logger + env.version = ::Rails.env + '-' + env.version if config.assets.cache_store != false env.cache = ActiveSupport::Cache.lookup_store(config.assets.cache_store) || ::Rails.cache diff --git a/actionpack/test/template/sprockets_helper_test.rb b/actionpack/test/template/sprockets_helper_test.rb index f4b5344d63..dfa635335e 100644 --- a/actionpack/test/template/sprockets_helper_test.rb +++ b/actionpack/test/template/sprockets_helper_test.rb @@ -205,4 +205,17 @@ class SprocketsHelperTest < ActionView::TestCase stubs(:asset_environment).returns(assets) assert_match %r{/assets/style-[0-9a-f]+.css}, asset_path("style", "css") end + + test "alternate hash based on environment" do + assets = Sprockets::Environment.new + assets.version = 'development' + assets.append_path(FIXTURES.join("sprockets/alternate/stylesheets")) + stubs(:asset_environment).returns(assets) + dev_path = asset_path("style", "css") + + assets.version = 'production' + prod_path = asset_path("style", "css") + + assert_not_equal prod_path, dev_path + end end From 050c1510b6041a0de21899de1c08d2b816ec0e66 Mon Sep 17 00:00:00 2001 From: Ilya Grigorik Date: Thu, 4 Aug 2011 19:17:03 -0400 Subject: [PATCH 138/345] Clear out tmp/cache when assets:clean is invoked. Otherwise, if bad data is cached in tmp/clear then the next invocation of assets:precompile (or a regular incoming request) will pickup files from tmp without regenerating them from source. --- actionpack/lib/sprockets/assets.rake | 2 +- railties/test/application/assets_test.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/actionpack/lib/sprockets/assets.rake b/actionpack/lib/sprockets/assets.rake index 50278cffcd..0349b2865e 100644 --- a/actionpack/lib/sprockets/assets.rake +++ b/actionpack/lib/sprockets/assets.rake @@ -16,7 +16,7 @@ namespace :assets do end desc "Remove compiled assets" - task :clean => :environment do + task :clean => [:environment, 'tmp:cache:clear'] do assets = Rails.application.config.assets public_asset_path = Rails.public_path + assets.prefix rm_rf public_asset_path, :secure => true diff --git a/railties/test/application/assets_test.rb b/railties/test/application/assets_test.rb index 802b737483..38dd3f5a3f 100644 --- a/railties/test/application/assets_test.rb +++ b/railties/test/application/assets_test.rb @@ -80,7 +80,7 @@ module ApplicationTests Dir.chdir(app_path){ `bundle exec rake assets:clean` } end - files = Dir["#{app_path}/public/assets/**/*"] + files = Dir["#{app_path}/public/assets/**/*", "#{app_path}/tmp/cache/*"] assert_equal 0, files.length, "Expected no assets, but found #{files.join(', ')}" end From 5a05207d99b7e2678f9b42db2d9ffc21ec2c8c3b Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 5 Aug 2011 11:20:15 -0700 Subject: [PATCH 139/345] pg does not allow aliases in the having clause, but functions are fine --- activerecord/test/cases/calculations_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb index 42f98b3d42..c38814713a 100644 --- a/activerecord/test/cases/calculations_test.rb +++ b/activerecord/test/cases/calculations_test.rb @@ -171,7 +171,7 @@ class CalculationsTest < ActiveRecord::TestCase end def test_should_group_by_summed_field_having_condition_from_select - c = Account.select("MIN(credit_limit) AS min_credit_limit").group(:firm_id).having("min_credit_limit > 50").sum(:credit_limit) + c = Account.select("MIN(credit_limit) AS min_credit_limit").group(:firm_id).having("MIN(credit_limit) > 50").sum(:credit_limit) assert_nil c[1] assert_equal 60, c[2] assert_equal 53, c[9] From 780ee36c56d79f934ff123d63a5229e0311cade8 Mon Sep 17 00:00:00 2001 From: Guillermo Iguaran Date: Fri, 5 Aug 2011 13:19:05 -0500 Subject: [PATCH 140/345] Fix AR test suite error under Rubinius 2.0 --- activesupport/lib/active_support/core_ext/time/calculations.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb index c5fbbcf890..a15a06d0e4 100644 --- a/activesupport/lib/active_support/core_ext/time/calculations.rb +++ b/activesupport/lib/active_support/core_ext/time/calculations.rb @@ -1,5 +1,6 @@ require 'active_support/duration' require 'active_support/core_ext/time/zones' +require 'active_support/core_ext/time/conversions' class Time COMMON_YEAR_DAYS_IN_MONTH = [nil, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] From e0a6ec214987882a47722e709a91b17b8395bec9 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 5 Aug 2011 16:48:46 -0300 Subject: [PATCH 141/345] Fix test for Rubinius --- .../test/cases/associations/nested_through_associations_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/test/cases/associations/nested_through_associations_test.rb b/activerecord/test/cases/associations/nested_through_associations_test.rb index dd450a2a8e..80c6e41169 100644 --- a/activerecord/test/cases/associations/nested_through_associations_test.rb +++ b/activerecord/test/cases/associations/nested_through_associations_test.rb @@ -247,7 +247,7 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase def test_has_many_through_has_and_belongs_to_many_with_has_many_source_reflection_preload_via_joins assert_includes_and_joins_equal( - Category.where('comments.id' => comments(:more_greetings).id).order('comments.id'), + Category.where('comments.id' => comments(:more_greetings).id).order('categories.id'), [categories(:general), categories(:technology)], :post_comments ) end From 1b676fc76074047f4784502a9597fb529fd74dd7 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 5 Aug 2011 18:42:41 -0300 Subject: [PATCH 142/345] Revert "to_key on a destroyed model should return nil". Closes #2440 This reverts commit c5448721b5054b8a467958d60427fdee15eac604. --- .../lib/active_record/attribute_methods/primary_key.rb | 5 ++--- activerecord/test/cases/primary_keys_test.rb | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/activerecord/lib/active_record/attribute_methods/primary_key.rb b/activerecord/lib/active_record/attribute_methods/primary_key.rb index 8bd898d126..ed71b5e7d4 100644 --- a/activerecord/lib/active_record/attribute_methods/primary_key.rb +++ b/activerecord/lib/active_record/attribute_methods/primary_key.rb @@ -3,11 +3,10 @@ module ActiveRecord module PrimaryKey extend ActiveSupport::Concern - # Returns this record's primary key value wrapped in an Array or nil if - # the record is not persisted? or has just been destroyed. + # Returns this record's primary key value wrapped in an Array if one is available def to_key key = send(self.class.primary_key) - persisted? && key ? [key] : nil + [key] if key end module ClassMethods diff --git a/activerecord/test/cases/primary_keys_test.rb b/activerecord/test/cases/primary_keys_test.rb index 7e3da145e5..05a41d8a0a 100644 --- a/activerecord/test/cases/primary_keys_test.rb +++ b/activerecord/test/cases/primary_keys_test.rb @@ -26,7 +26,7 @@ class PrimaryKeysTest < ActiveRecord::TestCase def test_to_key_with_primary_key_after_destroy topic = Topic.find(1) topic.destroy - assert_equal nil, topic.to_key + assert_equal [1], topic.to_key end def test_integer_key From 3cfbb3824436b2f8a37544b8ffe2f3a4605bc7c8 Mon Sep 17 00:00:00 2001 From: Erik Michaels-Ober Date: Fri, 5 Aug 2011 15:44:28 -0700 Subject: [PATCH 143/345] Test against Rubinius Happy Rubinius Day! --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 596611ecf4..b2aba11486 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,8 @@ script: 'ci/travis.rb' rvm: - 1.8.7 - 1.9.2 + - rbx + - rbx-2.0 env: - "GEM=railties" - "GEM=ap,am,amo,ares,as" @@ -11,4 +13,4 @@ env: notifications: email: false irc: - - "irc.freenode.org#rails-contrib" \ No newline at end of file + - "irc.freenode.org#rails-contrib" From 5bc6285cfee86e9d9393dfddc00e7b73a412268c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 5 Aug 2011 15:51:33 -0700 Subject: [PATCH 144/345] Revert "Test against Rubinius" This reverts commit 3cfbb3824436b2f8a37544b8ffe2f3a4605bc7c8. --- .travis.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index b2aba11486..596611ecf4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,8 +2,6 @@ script: 'ci/travis.rb' rvm: - 1.8.7 - 1.9.2 - - rbx - - rbx-2.0 env: - "GEM=railties" - "GEM=ap,am,amo,ares,as" @@ -13,4 +11,4 @@ env: notifications: email: false irc: - - "irc.freenode.org#rails-contrib" + - "irc.freenode.org#rails-contrib" \ No newline at end of file From 201e41e11aa0380265d09f763a4e6ef10868e6e7 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 5 Aug 2011 21:28:14 -0300 Subject: [PATCH 145/345] Avoid generating app/views/layouts/application.html.erb on mountable engines, just generate the namespaced one --- .../rails/generators/rails/plugin_new/plugin_new_generator.rb | 2 -- .../app/views/layouts/{ => %name%}/application.html.erb.tt | 0 2 files changed, 2 deletions(-) rename railties/lib/rails/generators/rails/plugin_new/templates/app/views/layouts/{ => %name%}/application.html.erb.tt (100%) diff --git a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb index c46422437d..4baa2110e7 100644 --- a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb +++ b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb @@ -11,8 +11,6 @@ module Rails def app if mountable? directory "app" - template "app/views/layouts/application.html.erb.tt", - "app/views/layouts/#{name}/application.html.erb" empty_directory_with_gitkeep "app/assets/images/#{name}" elsif full? empty_directory_with_gitkeep "app/models" diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/app/views/layouts/application.html.erb.tt b/railties/lib/rails/generators/rails/plugin_new/templates/app/views/layouts/%name%/application.html.erb.tt similarity index 100% rename from railties/lib/rails/generators/rails/plugin_new/templates/app/views/layouts/application.html.erb.tt rename to railties/lib/rails/generators/rails/plugin_new/templates/app/views/layouts/%name%/application.html.erb.tt From b642922496382b2b08154729b05b2b47306712ab Mon Sep 17 00:00:00 2001 From: Evan Light Date: Fri, 5 Aug 2011 22:06:47 -0400 Subject: [PATCH 146/345] Refactored to more closely resemble idiom applied for on_nil --- .../active_support/core_ext/module/delegation.rb | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/activesupport/lib/active_support/core_ext/module/delegation.rb b/activesupport/lib/active_support/core_ext/module/delegation.rb index 149b849b12..bf7e009290 100644 --- a/activesupport/lib/active_support/core_ext/module/delegation.rb +++ b/activesupport/lib/active_support/core_ext/module/delegation.rb @@ -106,26 +106,32 @@ class Module unless options.is_a?(Hash) && to = options[:to] raise ArgumentError, "Delegation needs a target. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, :to => :greeter)." end + prefix, to, allow_nil = options[:prefix], options[:to], options[:allow_nil] - if options[:prefix] == true && options[:to].to_s =~ /^[^a-z_]/ + if prefix == true && to.to_s =~ /^[^a-z_]/ raise ArgumentError, "Can only automatically set the delegation prefix when delegating to a method." end - prefix = options[:prefix] ? "#{options[:prefix] == true ? to : options[:prefix]}_" : '' + method_prefix = + if prefix + "#{prefix == true ? to : prefix}_" + else + '' + end file, line = caller.first.split(':', 2) line = line.to_i methods.each do |method| on_nil = - if options[:allow_nil] + if allow_nil 'return' else - %(raise "#{self}##{prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}") + %(raise "#{self}##{method_prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}") end module_eval(<<-EOS, file, line - 5) - def #{prefix}#{method}(*args, &block) # def customer_name(*args, &block) + def #{method_prefix}#{method}(*args, &block) # def customer_name(*args, &block) #{to}.__send__(#{method.inspect}, *args, &block) # client.__send__(:name, *args, &block) rescue NoMethodError # rescue NoMethodError if #{to}.nil? # if client.nil? From c0bfb5a63c926abcee8df26ed7b7598ef763463a Mon Sep 17 00:00:00 2001 From: Ilya Grigorik Date: Fri, 5 Aug 2011 22:55:56 -0700 Subject: [PATCH 147/345] use assets.version in asset checksum to allow user to easily override --- actionpack/lib/sprockets/railtie.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/sprockets/railtie.rb b/actionpack/lib/sprockets/railtie.rb index 0c2eb5075b..e1db3c52a3 100644 --- a/actionpack/lib/sprockets/railtie.rb +++ b/actionpack/lib/sprockets/railtie.rb @@ -20,7 +20,7 @@ module Sprockets app.assets = Sprockets::Environment.new(app.root.to_s) do |env| env.static_root = File.join(app.root.join('public'), config.assets.prefix) env.logger = ::Rails.logger - env.version = ::Rails.env + '-' + env.version + env.version = ::Rails.env + '-' + config.assets.version if config.assets.cache_store != false env.cache = ActiveSupport::Cache.lookup_store(config.assets.cache_store) || ::Rails.cache From 43e581ef7fb24d11cba37bb4a74f8915ff74f402 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sat, 6 Aug 2011 09:15:32 -0300 Subject: [PATCH 148/345] Use rake >= 0.9.3.beta.1 in Ruby 1.9.3 --- Gemfile | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index f6caa1ee65..e11514d5e6 100644 --- a/Gemfile +++ b/Gemfile @@ -11,7 +11,12 @@ gem "jquery-rails" # it being automatically loaded by sprockets gem "uglifier", ">= 1.0.0", :require => false -gem "rake", ">= 0.8.7" +# Temp fix until rake 0.9.3 is out +if RUBY_VERSION >= "1.9.3" + gem "rake", "0.9.3.beta.1" +else + gem "rake", ">= 0.8.7" +end gem "mocha", ">= 0.9.8" group :doc do From aed9917094f0a618b440d0bacee3a33b30f7d951 Mon Sep 17 00:00:00 2001 From: Guillermo Iguaran Date: Sat, 6 Aug 2011 11:33:18 -0500 Subject: [PATCH 149/345] Fix ActiveSupport::Gzip under Ruby 1.8.7. Closes #2416 --- activesupport/lib/active_support/gzip.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/activesupport/lib/active_support/gzip.rb b/activesupport/lib/active_support/gzip.rb index 62f9c9aa2e..9651f02c73 100644 --- a/activesupport/lib/active_support/gzip.rb +++ b/activesupport/lib/active_support/gzip.rb @@ -1,5 +1,6 @@ require 'zlib' require 'stringio' +require 'active_support/core_ext/string/encoding' module ActiveSupport # A convenient wrapper for the zlib standard library that allows compression/decompression of strings with gzip. From cdb49fc2f3f66bbae81be837424dcb45602ea5e2 Mon Sep 17 00:00:00 2001 From: Gustavo Delfino Date: Sat, 6 Aug 2011 16:05:45 -0430 Subject: [PATCH 150/345] sqlite transactions now logged motivation: http://stackoverflow.com/questions/6892630/sqlite-transactions-not-showing-in-test-log --- .../lib/active_record/connection_adapters/sqlite_adapter.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb index e2a0f63393..ba65ff4357 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb @@ -238,15 +238,15 @@ module ActiveRecord end def begin_db_transaction #:nodoc: - @connection.transaction + log('begin transaction',nil) { @connection.transaction } end def commit_db_transaction #:nodoc: - @connection.commit + log('commit transaction',nil) { @connection.commit } end def rollback_db_transaction #:nodoc: - @connection.rollback + log('rollback transaction',nil) { @connection.rollback } end # SCHEMA STATEMENTS ======================================== From 888539c54167964957b97328e3e863d91fa9c240 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sun, 7 Aug 2011 13:18:10 +0300 Subject: [PATCH 151/345] Test against 1.9.3 as well. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 596611ecf4..953df9e7e5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,7 @@ script: 'ci/travis.rb' rvm: - 1.8.7 - 1.9.2 + - 1.9.3 env: - "GEM=railties" - "GEM=ap,am,amo,ares,as" From 8845ae683e2688bc619baade49510c17e978518f Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sun, 7 Aug 2011 12:34:49 -0300 Subject: [PATCH 152/345] x_sendfile_header now defaults to nil and production.rb env file doesn't set a particular value for it. This allows servers to set it through X-Sendfile-Type, read https://github.com/rack/rack/blob/master/lib/rack/sendfile.rb for more info. Anyways you can force this value in your production.rb --- actionpack/lib/action_controller/metal/data_streaming.rb | 2 +- actionpack/lib/action_dispatch/railtie.rb | 2 +- railties/lib/rails/application.rb | 4 +--- .../app/templates/config/environments/production.rb.tt | 4 ++-- railties/test/application/middleware/sendfile_test.rb | 3 ++- railties/test/application/middleware_test.rb | 8 -------- 6 files changed, 7 insertions(+), 16 deletions(-) diff --git a/actionpack/lib/action_controller/metal/data_streaming.rb b/actionpack/lib/action_controller/metal/data_streaming.rb index 0785fe9679..5e077dd7bd 100644 --- a/actionpack/lib/action_controller/metal/data_streaming.rb +++ b/actionpack/lib/action_controller/metal/data_streaming.rb @@ -17,7 +17,7 @@ module ActionController #:nodoc: protected # Sends the file. This uses a server-appropriate method (such as X-Sendfile) # via the Rack::Sendfile middleware. The header to use is set via - # config.action_dispatch.x_sendfile_header, and defaults to "X-Sendfile". + # config.action_dispatch.x_sendfile_header. # Your server can also configure this for you by setting the X-Sendfile-Type header. # # Be careful to sanitize the path parameter if it is coming from a web diff --git a/actionpack/lib/action_dispatch/railtie.rb b/actionpack/lib/action_dispatch/railtie.rb index f51cc3711b..fbda1f8442 100644 --- a/actionpack/lib/action_dispatch/railtie.rb +++ b/actionpack/lib/action_dispatch/railtie.rb @@ -4,7 +4,7 @@ require "rails" module ActionDispatch class Railtie < Rails::Railtie config.action_dispatch = ActiveSupport::OrderedOptions.new - config.action_dispatch.x_sendfile_header = "" + config.action_dispatch.x_sendfile_header = nil config.action_dispatch.ip_spoofing_check = true config.action_dispatch.show_exceptions = true config.action_dispatch.best_standards_support = true diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index fb60ddd9b5..9e2f1a4b7a 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -163,9 +163,7 @@ module Rails middleware.use ::Rails::Rack::Logger # must come after Rack::MethodOverride to properly log overridden methods middleware.use ::ActionDispatch::ShowExceptions, config.consider_all_requests_local middleware.use ::ActionDispatch::RemoteIp, config.action_dispatch.ip_spoofing_check, config.action_dispatch.trusted_proxies - if config.action_dispatch.x_sendfile_header.present? - middleware.use ::Rack::Sendfile, config.action_dispatch.x_sendfile_header - end + middleware.use ::Rack::Sendfile, config.action_dispatch.x_sendfile_header middleware.use ::ActionDispatch::Reloader unless config.cache_classes middleware.use ::ActionDispatch::Callbacks middleware.use ::ActionDispatch::Cookies diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt index 06ed890e05..de56d47688 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt @@ -15,8 +15,8 @@ config.assets.compress = true # Specifies the header that your server uses for sending files - # (comment out if your front-end server doesn't support this) - config.action_dispatch.x_sendfile_header = "X-Sendfile" # Use 'X-Accel-Redirect' for nginx + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache + # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. # config.force_ssl = true diff --git a/railties/test/application/middleware/sendfile_test.rb b/railties/test/application/middleware/sendfile_test.rb index c7a1c573f9..d2ad2668bb 100644 --- a/railties/test/application/middleware/sendfile_test.rb +++ b/railties/test/application/middleware/sendfile_test.rb @@ -27,11 +27,12 @@ module ApplicationTests end # x_sendfile_header middleware - test "config.action_dispatch.x_sendfile_header defaults to ''" do + test "config.action_dispatch.x_sendfile_header defaults to nil" do make_basic_app simple_controller get "/" + assert !last_response.headers["X-Sendfile"] assert_equal File.read(__FILE__), last_response.body end diff --git a/railties/test/application/middleware_test.rb b/railties/test/application/middleware_test.rb index bed5ba503f..6a0a272073 100644 --- a/railties/test/application/middleware_test.rb +++ b/railties/test/application/middleware_test.rb @@ -20,8 +20,6 @@ module ApplicationTests end test "default middleware stack" do - add_to_config "config.action_dispatch.x_sendfile_header = 'X-Sendfile'" - boot! assert_equal [ @@ -49,12 +47,6 @@ module ApplicationTests ], middleware end - test "Rack::Sendfile is not included by default" do - boot! - - assert !middleware.include?("Rack::Sendfile"), "Rack::Sendfile is not included in the default stack unless you set config.action_dispatch.x_sendfile_header" - end - test "Rack::Cache is present when action_controller.perform_caching is set" do add_to_config "config.action_controller.perform_caching = true" From 4cf94979c9f4d6683c9338d694d5eb3106a4e734 Mon Sep 17 00:00:00 2001 From: Vijay Dev Date: Mon, 29 Aug 2011 06:50:23 +51800 Subject: [PATCH 153/345] edit changelog to mention about x_sendfile_header default change --- actionpack/CHANGELOG | 2 ++ 1 file changed, 2 insertions(+) diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 3b323b3899..b1286d04cc 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -30,6 +30,8 @@ *Rails 3.1.0 (unreleased)* +* x_sendfile_header now defaults to nil and config/environments/production.rb doesn't set a particular value for it. This allows servers to set it through X-Sendfile-Type. [Santiago Pastorino] + * The submit form helper does not generate an id "object_name_id" anymore. [fbrusatti] * Make sure respond_with with :js tries to render a template in all cases [José Valim] From 554232e481a2d6e313d798fad59ccdca03f05ef2 Mon Sep 17 00:00:00 2001 From: Gregg Pollack Date: Sun, 7 Aug 2011 14:19:25 -0400 Subject: [PATCH 154/345] Added irregular zombie inflection, so zombies no longer gets singularized into zomby --- activesupport/lib/active_support/inflections.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/activesupport/lib/active_support/inflections.rb b/activesupport/lib/active_support/inflections.rb index 06ceccdb22..daf2a1e1d9 100644 --- a/activesupport/lib/active_support/inflections.rb +++ b/activesupport/lib/active_support/inflections.rb @@ -54,6 +54,7 @@ module ActiveSupport inflect.irregular('sex', 'sexes') inflect.irregular('move', 'moves') inflect.irregular('cow', 'kine') + inflect.irregular('zombie', 'zombies') inflect.uncountable(%w(equipment information rice money species series fish sheep jeans)) end From e746980507ed48e30ab35daf587bf9863d5b9261 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Sun, 7 Aug 2011 16:20:31 -0700 Subject: [PATCH 155/345] guides generation: apparently this workaround for RedCloth is not needed anymore --- railties/guides/rails_guides/generator.rb | 48 ++----------------- .../guides/rails_guides/textile_extensions.rb | 25 ++++++++-- 2 files changed, 26 insertions(+), 47 deletions(-) diff --git a/railties/guides/rails_guides/generator.rb b/railties/guides/rails_guides/generator.rb index d304512ff7..4682ead66e 100644 --- a/railties/guides/rails_guides/generator.rb +++ b/railties/guides/rails_guides/generator.rb @@ -199,50 +199,10 @@ module RailsGuides end def textile(body, lite_mode=false) - # If the issue with notextile is fixed just remove the wrapper. - with_workaround_for_notextile(body) do |body| - t = RedCloth.new(body) - t.hard_breaks = false - t.lite_mode = lite_mode - t.to_html(:notestuff, :plusplus, :code) - end - end - - # For some reason the notextile tag does not always turn off textile. See - # LH ticket of the security guide (#7). As a temporary workaround we deal - # with code blocks by hand. - def with_workaround_for_notextile(body) - code_blocks = [] - - body.gsub!(%r{<(yaml|shell|ruby|erb|html|sql|plain)>(.*?)}m) do |m| - brush = case $1 - when 'ruby', 'sql', 'plain' - $1 - when 'erb' - 'ruby; html-script: true' - when 'html' - 'xml' # html is understood, but there are .xml rules in the CSS - else - 'plain' - end - - code_blocks.push(< -
-
-#{ERB::Util.h($2).strip}
-
-
- -HTML - "\ndirty_workaround_for_notextile_#{code_blocks.size - 1}\n" - end - - body = yield body - - body.gsub(%r{

dirty_workaround_for_notextile_(\d+)

}) do |_| - code_blocks[$1.to_i] - end + t = RedCloth.new(body) + t.hard_breaks = false + t.lite_mode = lite_mode + t.to_html(:notestuff, :plusplus, :code) end def warn_about_broken_links(html) diff --git a/railties/guides/rails_guides/textile_extensions.rb b/railties/guides/rails_guides/textile_extensions.rb index b3e0e32357..4677fae504 100644 --- a/railties/guides/rails_guides/textile_extensions.rb +++ b/railties/guides/rails_guides/textile_extensions.rb @@ -33,11 +33,30 @@ module RailsGuides body.gsub!('', '+') end + def brush_for(code_type) + case code_type + when 'ruby', 'sql', 'plain' + code_type + when 'erb' + 'ruby; html-script: true' + when 'html' + 'xml' # html is understood, but there are .xml rules in the CSS + else + 'plain' + end + end + def code(body) body.gsub!(%r{<(yaml|shell|ruby|erb|html|sql|plain)>(.*?)}m) do |m| - es = ERB::Util.h($2) - css_class = $1.in?(['erb', 'shell']) ? 'html' : $1 - %{
#{es}
} + < +
+
+#{ERB::Util.h($2).strip}
+
+
+ +HTML end end end From 8360d7196515ba66fe5d535f6dbeeea5394e966a Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Mon, 8 Aug 2011 12:49:10 -0300 Subject: [PATCH 156/345] Initialize config.assets.version the same way it's done in Sprockets --- actionpack/lib/sprockets/railtie.rb | 2 +- railties/lib/rails/application/configuration.rb | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/actionpack/lib/sprockets/railtie.rb b/actionpack/lib/sprockets/railtie.rb index e1db3c52a3..0a2c8c1ea3 100644 --- a/actionpack/lib/sprockets/railtie.rb +++ b/actionpack/lib/sprockets/railtie.rb @@ -20,7 +20,7 @@ module Sprockets app.assets = Sprockets::Environment.new(app.root.to_s) do |env| env.static_root = File.join(app.root.join('public'), config.assets.prefix) env.logger = ::Rails.logger - env.version = ::Rails.env + '-' + config.assets.version + env.version = ::Rails.env + "#{'-' + config.assets.version if config.assets.version.present?}" if config.assets.cache_store != false env.cache = ActiveSupport::Cache.lookup_store(config.assets.cache_store) || ::Rails.cache diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index 975e159999..cd850b6a75 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -37,6 +37,7 @@ module Rails @assets.paths = [] @assets.precompile = [ /\w+\.(?!js|css).+/, /application.(css|js)$/ ] @assets.prefix = "/assets" + @assets.version = '' @assets.cache_store = [ :file_store, "#{root}/tmp/cache/assets/" ] @assets.js_compressor = nil From 396e12155aacdb4904fa13e3dc617b6554f48c5f Mon Sep 17 00:00:00 2001 From: Pivotal Casebook Date: Mon, 8 Aug 2011 13:47:24 -0300 Subject: [PATCH 157/345] Further monkey-patching to avoid deprecation warnings --- railties/lib/rails/tasks/documentation.rake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/railties/lib/rails/tasks/documentation.rake b/railties/lib/rails/tasks/documentation.rake index 5d613e0698..ca8875ad9b 100644 --- a/railties/lib/rails/tasks/documentation.rake +++ b/railties/lib/rails/tasks/documentation.rake @@ -8,6 +8,8 @@ end # Monkey-patch to remove redoc'ing and clobber descriptions to cut down on rake -T noise class RDocTaskWithoutDescriptions < RDoc::Task + include ::Rake::DSL + def define task rdoc_task_name From 58af0d46cfa4481800bb1c4c26950c717ea1ebdd Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Mon, 8 Aug 2011 22:32:26 +0300 Subject: [PATCH 158/345] Fixed test_disable_referential_integrity on Oracle On Oracle disable_referential_integrity before execution of block will disable foreign key constraints and after block will enable them but when constraints are enabled then they are validated. Therefore created record with invalid foreign key should be deleted before enabling foreign key constraints. --- activerecord/test/cases/adapter_test.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/activerecord/test/cases/adapter_test.rb b/activerecord/test/cases/adapter_test.rb index 3942e7bb41..f1023ed7ef 100644 --- a/activerecord/test/cases/adapter_test.rb +++ b/activerecord/test/cases/adapter_test.rb @@ -151,6 +151,9 @@ class AdapterTest < ActiveRecord::TestCase else @connection.execute "INSERT INTO fk_test_has_fk (fk_id) VALUES (0)" end + # should deleted created record as otherwise disable_referential_integrity will try to enable contraints after executed block + # and will fail (at least on Oracle) + @connection.execute "DELETE FROM fk_test_has_fk" end end end From 7db90aa7c7dfe5033ad012b8ee13e6f15d1c66f0 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Mon, 8 Aug 2011 23:27:54 +0100 Subject: [PATCH 159/345] Make it the responsibility of the connection to hold onto an ARel visitor for generating SQL. This improves the code architecture generally, and solves some problems with marshalling. Adapter authors please take note: you now need to define an Adapter.visitor_for method, but it degrades gracefully with a deprecation warning for now. --- .../has_and_belongs_to_many_association.rb | 4 +- .../preloader/has_and_belongs_to_many.rb | 2 +- activerecord/lib/active_record/base.rb | 3 +- .../abstract/connection_pool.rb | 19 ++++++++-- .../abstract/database_statements.rb | 37 ++++++++++++------- .../abstract/query_cache.rb | 5 ++- .../connection_adapters/abstract_adapter.rb | 24 ++++++++++++ .../connection_adapters/mysql2_adapter.rb | 4 ++ .../connection_adapters/mysql_adapter.rb | 4 ++ .../connection_adapters/postgresql_adapter.rb | 4 ++ .../connection_adapters/sqlite_adapter.rb | 4 ++ .../lib/active_record/counter_cache.rb | 2 +- .../lib/active_record/locking/optimistic.rb | 4 +- activerecord/lib/active_record/migration.rb | 6 +-- activerecord/lib/active_record/persistence.rb | 2 +- activerecord/lib/active_record/relation.rb | 13 +++---- .../active_record/relation/calculations.rb | 4 +- .../active_record/relation/finder_methods.rb | 6 +-- activerecord/test/cases/adapter_test.rb | 10 +++++ activerecord/test/cases/base_test.rb | 19 ---------- .../test/cases/connection_pool_test.rb | 4 ++ .../test/cases/method_scoping_test.rb | 8 ++-- .../test/cases/relation_scoping_test.rb | 2 +- 23 files changed, 122 insertions(+), 68 deletions(-) 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 f7ce70db1a..1f917f58f2 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 @@ -26,7 +26,7 @@ module ActiveRecord join_table[reflection.association_foreign_key] => record.id ) - owner.connection.insert stmt.to_sql + owner.connection.insert stmt end record @@ -46,7 +46,7 @@ module ActiveRecord stmt = relation.where(relation[reflection.foreign_key].eq(owner.id). and(relation[reflection.association_foreign_key].in(records.map { |x| x.id }.compact)) ).compile_delete - owner.connection.delete stmt.to_sql + owner.connection.delete stmt end end diff --git a/activerecord/lib/active_record/associations/preloader/has_and_belongs_to_many.rb b/activerecord/lib/active_record/associations/preloader/has_and_belongs_to_many.rb index 24be279449..b77b667219 100644 --- a/activerecord/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +++ b/activerecord/lib/active_record/associations/preloader/has_and_belongs_to_many.rb @@ -13,7 +13,7 @@ module ActiveRecord # access the aliased column on the join table def records_for(ids) scope = super - klass.connection.select_all(scope.arel.to_sql, 'SQL', scope.bind_values) + klass.connection.select_all(scope.arel, 'SQL', scope.bind_values) end def owner_key_name diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 4136868b39..06087642d4 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1409,9 +1409,8 @@ MSG attrs = expand_hash_conditions_for_aggregates(attrs) table = Arel::Table.new(table_name).alias(default_table_name) - viz = Arel::Visitors.for(arel_engine) PredicateBuilder.build_from_hash(arel_engine, attrs, table).map { |b| - viz.accept b + connection.visitor.accept b }.join(' AND ') end alias_method :sanitize_sql_hash, :sanitize_sql_hash_for_conditions diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb index ddfdb05297..61994d4a47 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb @@ -82,10 +82,11 @@ module ActiveRecord # default max pool size to 5 @size = (spec.config[:pool] && spec.config[:pool].to_i) || 5 - @connections = [] - @checked_out = [] + @connections = [] + @checked_out = [] @automatic_reconnect = true - @tables = {} + @tables = {} + @visitor = nil @columns = Hash.new do |h, table_name| h[table_name] = with_connection do |conn| @@ -298,8 +299,18 @@ module ActiveRecord :connected?, :disconnect!, :with => :@connection_mutex private + def new_connection - ActiveRecord::Base.send(spec.adapter_method, spec.config) + connection = ActiveRecord::Base.send(spec.adapter_method, spec.config) + + # TODO: This is a bit icky, and in the long term we may want to change the method + # signature for connections. Also, if we switch to have one visitor per + # connection (and therefore per thread), we can get rid of the thread-local + # variable in Arel::Visitors::ToSql. + @visitor ||= connection.class.visitor_for(self) + connection.visitor = @visitor + + connection end def current_connection_id #:nodoc: 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 777ef15dfc..2ae655e68d 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -1,30 +1,39 @@ module ActiveRecord module ConnectionAdapters # :nodoc: module DatabaseStatements + # Converts an arel AST to SQL + def to_sql(arel) + if arel.respond_to?(:ast) + visitor.accept(arel.ast) + else + arel + end + end + # Returns an array of record hashes with the column names as keys and # column values as values. - def select_all(sql, name = nil, binds = []) - select(sql, name, binds) + def select_all(arel, name = nil, binds = []) + select(to_sql(arel), name, binds) end # Returns a record hash with the column names as keys and column values # as values. - def select_one(sql, name = nil) - result = select_all(sql, name) + def select_one(arel, name = nil) + result = select_all(arel, name) result.first if result end # Returns a single value from a record - def select_value(sql, name = nil) - if result = select_one(sql, name) + def select_value(arel, name = nil) + if result = select_one(arel, name) result.values.first end end # Returns an array of the values of the first column in a select: # select_values("SELECT id FROM companies LIMIT 3") => [1,2,3] - def select_values(sql, name = nil) - result = select_rows(sql, name) + def select_values(arel, name = nil) + result = select_rows(to_sql(arel), name) result.map { |v| v[0] } end @@ -74,20 +83,20 @@ module ActiveRecord # # If the next id was calculated in advance (as in Oracle), it should be # passed in as +id_value+. - def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = []) - sql, binds = sql_for_insert(sql, pk, id_value, sequence_name, binds) + def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = []) + sql, binds = sql_for_insert(to_sql(arel), pk, id_value, sequence_name, binds) value = exec_insert(sql, name, binds) id_value || last_inserted_id(value) end # Executes the update statement and returns the number of rows affected. - def update(sql, name = nil, binds = []) - exec_update(sql, name, binds) + def update(arel, name = nil, binds = []) + exec_update(to_sql(arel), name, binds) end # Executes the delete statement and returns the number of rows affected. - def delete(sql, name = nil, binds = []) - exec_delete(sql, name, binds) + def delete(arel, name = nil, binds = []) + exec_delete(to_sql(arel), name, binds) end # Checks whether there is currently no transaction active. This is done diff --git a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb index 093c30aa42..27ff13ad89 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb @@ -55,9 +55,10 @@ module ActiveRecord @query_cache.clear end - def select_all(sql, name = nil, binds = []) + def select_all(arel, name = nil, binds = []) if @query_cache_enabled - cache_sql(sql, binds) { super } + sql = to_sql(arel) + cache_sql(sql, binds) { super(sql, name, binds) } else super end diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index bde31d1cda..88fd180fa5 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -2,6 +2,7 @@ require 'date' require 'bigdecimal' require 'bigdecimal/util' require 'active_support/core_ext/benchmark' +require 'active_support/deprecation' # TODO: Autoload these files require 'active_record/connection_adapters/column' @@ -38,6 +39,8 @@ module ActiveRecord define_callbacks :checkout, :checkin + attr_accessor :visitor + def initialize(connection, logger = nil) #:nodoc: @active = nil @connection, @logger = connection, logger @@ -45,6 +48,27 @@ module ActiveRecord @query_cache = Hash.new { |h,sql| h[sql] = {} } @open_transactions = 0 @instrumenter = ActiveSupport::Notifications.instrumenter + @visitor = nil + end + + # Returns a visitor instance for this adaptor, which conforms to the Arel::ToSql interface + def self.visitor_for(pool) # :nodoc: + adapter = pool.spec.config[:adapter] + + if Arel::Visitors::VISITORS[adapter] + # TODO: Add a test for this + + ActiveSupport::Deprecation.warn( + "Arel::Visitors::VISITORS is deprecated and will be removed. Database adapters " \ + "should define a visitor_for method which returns the appropriate visitor for " \ + "the database. For example, MysqlAdapter.visitor_for(pool) returns " \ + "Arel::Visitors::MySQL.new(pool)." + ) + + Arel::Visitors::VISITORS[adapter].new(pool) + else + Arel::Visitors::ToSql.new(pool) + end end # Returns the human-readable name of the adapter. Use mixed case - one diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb index f9602bbe77..18fdfa29ec 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb @@ -129,6 +129,10 @@ module ActiveRecord configure_connection end + def self.visitor_for(pool) # :nodoc: + Arel::Visitors::MySQL.new(pool) + end + def adapter_name ADAPTER_NAME end diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index 9e6cb13cca..14b950dbb0 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -192,6 +192,10 @@ module ActiveRecord connect end + def self.visitor_for(pool) # :nodoc: + Arel::Visitors::MySQL.new(pool) + end + def adapter_name #:nodoc: ADAPTER_NAME end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index aefe69f8ed..45c13bdcd6 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -265,6 +265,10 @@ module ActiveRecord @local_tz = execute('SHOW TIME ZONE', 'SCHEMA').first["TimeZone"] end + def self.visitor_for(pool) # :nodoc: + Arel::Visitors::PostgreSQL.new(pool) + end + # Clears the prepared statements cache. def clear_cache! @statements.each_value do |value| diff --git a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb index ba65ff4357..486efc5ba0 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb @@ -53,6 +53,10 @@ module ActiveRecord @config = config end + def self.visitor_for(pool) # :nodoc: + Arel::Visitors::SQLite.new(pool) + end + def adapter_name #:nodoc: 'SQLite' end diff --git a/activerecord/lib/active_record/counter_cache.rb b/activerecord/lib/active_record/counter_cache.rb index 4d387565d9..3c7defedac 100644 --- a/activerecord/lib/active_record/counter_cache.rb +++ b/activerecord/lib/active_record/counter_cache.rb @@ -33,7 +33,7 @@ module ActiveRecord stmt = unscoped.where(arel_table[primary_key].eq(object.id)).arel.compile_update({ arel_table[counter_name] => object.send(association).count }) - connection.update stmt.to_sql + connection.update stmt end return true end diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb index 6cfce6e573..d9ad7e4132 100644 --- a/activerecord/lib/active_record/locking/optimistic.rb +++ b/activerecord/lib/active_record/locking/optimistic.rb @@ -70,7 +70,7 @@ module ActiveRecord # If the locking column has no default value set, # start the lock version at zero. Note we can't use - # locking_enabled? at this point as + # locking_enabled? at this point as # @attributes may not have been initialized yet. if result.key?(self.class.locking_column) && lock_optimistically @@ -100,7 +100,7 @@ module ActiveRecord ) ).arel.compile_update(arel_attributes_values(false, false, attribute_names)) - affected_rows = connection.update stmt.to_sql + affected_rows = connection.update stmt unless affected_rows == 1 raise ActiveRecord::StaleObjectError, "Attempted to update a stale object: #{self.class.name}" diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index fa1b303fc7..7166f1b82a 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -563,7 +563,7 @@ module ActiveRecord def get_all_versions table = Arel::Table.new(schema_migrations_table_name) - Base.connection.select_values(table.project(table['version']).to_sql).map{ |v| v.to_i }.sort + Base.connection.select_values(table.project(table['version'])).map{ |v| v.to_i }.sort end def current_version @@ -720,11 +720,11 @@ module ActiveRecord if down? @migrated_versions.delete(version) stmt = table.where(table["version"].eq(version.to_s)).compile_delete - Base.connection.delete stmt.to_sql + Base.connection.delete stmt else @migrated_versions.push(version).sort! stmt = table.compile_insert table["version"] => version.to_s - Base.connection.insert stmt.to_sql + Base.connection.insert stmt end end diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index ebda3875cd..2dac9ea0fb 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -304,7 +304,7 @@ module ActiveRecord return 0 if attributes_with_values.empty? klass = self.class stmt = klass.unscoped.where(klass.arel_table[klass.primary_key].eq(id)).arel.compile_update(attributes_with_values) - klass.connection.update stmt.to_sql + klass.connection.update stmt end # Creates a record with values matching those of the instance attributes diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index fff0ad1b83..7e59eb4584 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -68,7 +68,7 @@ module ActiveRecord end conn.insert( - im.to_sql, + im, 'SQL', primary_key, primary_key_value, @@ -108,10 +108,10 @@ module ActiveRecord if default_scoped.equal?(self) @records = if @readonly_value.nil? && !@klass.locking_enabled? - eager_loading? ? find_with_associations : @klass.find_by_sql(arel.to_sql, @bind_values) + eager_loading? ? find_with_associations : @klass.find_by_sql(arel, @bind_values) else IdentityMap.without do - eager_loading? ? find_with_associations : @klass.find_by_sql(arel.to_sql, @bind_values) + eager_loading? ? find_with_associations : @klass.find_by_sql(arel, @bind_values) end end @@ -224,7 +224,7 @@ module ActiveRecord stmt.order(*arel.orders) stmt.key = table[primary_key] - @klass.connection.update stmt.to_sql, 'SQL', bind_values + @klass.connection.update stmt, 'SQL', bind_values end end @@ -341,8 +341,7 @@ module ActiveRecord where(conditions).delete_all else statement = arel.compile_delete - affected = @klass.connection.delete( - statement.to_sql, 'SQL', bind_values) + affected = @klass.connection.delete(statement, 'SQL', bind_values) reset affected @@ -388,7 +387,7 @@ module ActiveRecord end def to_sql - @to_sql ||= arel.to_sql + @to_sql ||= klass.connection.to_sql(arel) end def where_values_hash diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb index 9a7ff87e88..af86771d2d 100644 --- a/activerecord/lib/active_record/relation/calculations.rb +++ b/activerecord/lib/active_record/relation/calculations.rb @@ -223,7 +223,7 @@ module ActiveRecord query_builder = relation.arel end - type_cast_calculated_value(@klass.connection.select_value(query_builder.to_sql), column_for(column_name), operation) + type_cast_calculated_value(@klass.connection.select_value(query_builder), column_for(column_name), operation) end def execute_grouped_calculation(operation, column_name, distinct) #:nodoc: @@ -259,7 +259,7 @@ module ActiveRecord relation = except(:group).group(group.join(',')) relation.select_values = select_values - calculated_data = @klass.connection.select_all(relation.to_sql) + calculated_data = @klass.connection.select_all(relation) if association key_ids = calculated_data.collect { |row| row[group_aliases.first] } diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index 8cef4e5554..73368aed18 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -193,8 +193,8 @@ module ActiveRecord else relation = relation.where(table[primary_key].eq(id)) if id end - - connection.select_value(relation.to_sql, "#{name} Exists") ? true : false + + connection.select_value(relation, "#{name} Exists") ? true : false end protected @@ -202,7 +202,7 @@ module ActiveRecord def find_with_associations join_dependency = construct_join_dependency_for_association_find relation = construct_relation_for_association_find(join_dependency) - rows = connection.select_all(relation.to_sql, 'SQL', relation.bind_values) + rows = connection.select_all(relation, 'SQL', relation.bind_values) join_dependency.instantiate(rows) rescue ThrowResult [] diff --git a/activerecord/test/cases/adapter_test.rb b/activerecord/test/cases/adapter_test.rb index f1023ed7ef..94497e37c7 100644 --- a/activerecord/test/cases/adapter_test.rb +++ b/activerecord/test/cases/adapter_test.rb @@ -157,4 +157,14 @@ class AdapterTest < ActiveRecord::TestCase end end end + + def test_deprecated_visitor_for + visitor_klass = Class.new(Arel::Visitors::ToSql) + Arel::Visitors::VISITORS['fuuu'] = visitor_klass + pool = stub(:spec => stub(:config => { :adapter => 'fuuu' })) + visitor = assert_deprecated { + ActiveRecord::ConnectionAdapters::AbstractAdapter.visitor_for(pool) + } + assert visitor.is_a?(visitor_klass) + end end diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index 12101c1683..0a9340aea1 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -144,25 +144,6 @@ class BasicsTest < ActiveRecord::TestCase end end - def test_use_table_engine_for_quoting_where - relation = Topic.where(Topic.arel_table[:id].eq(1)) - engine = relation.table.engine - - fakepool = Class.new(Struct.new(:spec)) { - def with_connection; yield self; end - def connection_pool; self; end - def table_exists?(name); false; end - def quote_table_name(*args); raise "lol quote_table_name"; end - } - - relation.table.engine = fakepool.new(engine.connection_pool.spec) - - error = assert_raises(RuntimeError) { relation.to_a } - assert_match('lol', error.message) - ensure - relation.table.engine = engine - end - def test_preserving_time_objects assert_kind_of( Time, Topic.find(1).bonus_time, diff --git a/activerecord/test/cases/connection_pool_test.rb b/activerecord/test/cases/connection_pool_test.rb index f92f4e62c5..8a0f453127 100644 --- a/activerecord/test/cases/connection_pool_test.rb +++ b/activerecord/test/cases/connection_pool_test.rb @@ -135,6 +135,10 @@ module ActiveRecord pool.with_connection end end + + def test_pool_sets_connection_visitor + assert @pool.connection.visitor.is_a?(Arel::Visitors::ToSql) + end end end end diff --git a/activerecord/test/cases/method_scoping_test.rb b/activerecord/test/cases/method_scoping_test.rb index a0cb5dbdc5..0ab4f30363 100644 --- a/activerecord/test/cases/method_scoping_test.rb +++ b/activerecord/test/cases/method_scoping_test.rb @@ -14,7 +14,7 @@ class MethodScopingTest < ActiveRecord::TestCase def test_set_conditions Developer.send(:with_scope, :find => { :conditions => 'just a test...' }) do - assert_match '(just a test...)', Developer.scoped.arel.to_sql + assert_match '(just a test...)', Developer.scoped.to_sql end end @@ -274,7 +274,7 @@ class NestedScopingTest < ActiveRecord::TestCase Developer.send(:with_scope, :find => { :conditions => 'salary = 80000' }) do Developer.send(:with_scope, :find => { :limit => 10 }) do devs = Developer.scoped - assert_match '(salary = 80000)', devs.arel.to_sql + assert_match '(salary = 80000)', devs.to_sql assert_equal 10, devs.taken end end @@ -308,7 +308,7 @@ class NestedScopingTest < ActiveRecord::TestCase Developer.send(:with_scope, :find => { :conditions => "name = 'David'" }) do Developer.send(:with_scope, :find => { :conditions => 'salary = 80000' }) do devs = Developer.scoped - assert_match "(name = 'David') AND (salary = 80000)", devs.arel.to_sql + assert_match "(name = 'David') AND (salary = 80000)", devs.to_sql assert_equal(1, Developer.count) end Developer.send(:with_scope, :find => { :conditions => "name = 'Maiha'" }) do @@ -321,7 +321,7 @@ class NestedScopingTest < ActiveRecord::TestCase Developer.send(:with_scope, :find => { :conditions => 'salary = 80000', :limit => 10 }) do Developer.send(:with_scope, :find => { :conditions => "name = 'David'" }) do devs = Developer.scoped - assert_match "(salary = 80000) AND (name = 'David')", devs.arel.to_sql + assert_match "(salary = 80000) AND (name = 'David')", devs.to_sql assert_equal 10, devs.taken end end diff --git a/activerecord/test/cases/relation_scoping_test.rb b/activerecord/test/cases/relation_scoping_test.rb index f2d177d834..673aff403f 100644 --- a/activerecord/test/cases/relation_scoping_test.rb +++ b/activerecord/test/cases/relation_scoping_test.rb @@ -170,7 +170,7 @@ class NestedRelationScopingTest < ActiveRecord::TestCase Developer.where('salary = 80000').scoping do Developer.limit(10).scoping do devs = Developer.scoped - assert_match '(salary = 80000)', devs.arel.to_sql + assert_match '(salary = 80000)', devs.to_sql assert_equal 10, devs.taken end end From 9062b75bb7dab38977805c1de35944079a56499a Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Mon, 8 Aug 2011 14:41:23 +0100 Subject: [PATCH 160/345] Fully marshal AR::Base objects. Fixes #2431. --- activerecord/lib/active_record/base.rb | 21 --------------------- activerecord/test/cases/base_test.rb | 13 +++++++++++++ 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 06087642d4..102d8f4175 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -937,17 +937,6 @@ module ActiveRecord #:nodoc: self.current_scope = nil end - # Specifies how the record is loaded by +Marshal+. - # - # +_load+ sets an instance variable for each key in the hash it takes as input. - # Override this method if you require more complex marshalling. - def _load(data) - record = allocate - record.init_with(Marshal.load(data)) - record - end - - # Finder methods must instantiate through this method to work with the # single-table inheritance model that makes it possible to create # objects of different types from the same table. @@ -1588,16 +1577,6 @@ MSG self end - # Specifies how the record is dumped by +Marshal+. - # - # +_dump+ emits a marshalled hash which has been passed to +encode_with+. Override this - # method if you require more complex marshalling. - def _dump(level) - dump = {} - encode_with(dump) - Marshal.dump(dump) - end - # Returns a String, which Action Pack uses for constructing an URL to this # object. The default implementation returns this record's id as a String, # or nil if this record's unsaved. diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index 0a9340aea1..c78d887ed7 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -1813,6 +1813,19 @@ class BasicsTest < ActiveRecord::TestCase assert_equal expected.attributes, actual.attributes end + def test_marshal_new_record_round_trip + post = Marshal.load(Marshal.dump(Post.new)) + assert post.new_record?, "should be a new record" + end + + def test_marshalling_with_associations + post = Post.new + post.comments.build + post = Marshal.load(Marshal.dump(post)) + + assert_equal 1, post.comments.length + end + def test_attribute_names assert_equal ["id", "type", "ruby_type", "firm_id", "firm_name", "name", "client_of", "rating", "account_id"], Company.attribute_names From 5870291425c39405aafeddf26281d4d0c514fd4a Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Mon, 8 Aug 2011 23:51:07 +0100 Subject: [PATCH 161/345] Bump arel version --- activerecord/activerecord.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/activerecord.gemspec b/activerecord/activerecord.gemspec index 8ac4d9a225..d978938f18 100644 --- a/activerecord/activerecord.gemspec +++ b/activerecord/activerecord.gemspec @@ -21,6 +21,6 @@ Gem::Specification.new do |s| s.add_dependency('activesupport', version) s.add_dependency('activemodel', version) - s.add_dependency('arel', '~> 2.1.3') + s.add_dependency('arel', '~> 2.1.5') s.add_dependency('tzinfo', '~> 0.3.29') end From 5680a51dcbaf4239b53481fd1ae39a6f4ee4034d Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Tue, 9 Aug 2011 00:00:52 +0100 Subject: [PATCH 162/345] Remove TODO comment I didn't mean to commit --- .../lib/active_record/connection_adapters/abstract_adapter.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index 88fd180fa5..077cf7df1b 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -56,8 +56,6 @@ module ActiveRecord adapter = pool.spec.config[:adapter] if Arel::Visitors::VISITORS[adapter] - # TODO: Add a test for this - ActiveSupport::Deprecation.warn( "Arel::Visitors::VISITORS is deprecated and will be removed. Database adapters " \ "should define a visitor_for method which returns the appropriate visitor for " \ From 0b212117e60bf6778def3bd9c2521f92f0c74c73 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 8 Aug 2011 19:29:12 -0700 Subject: [PATCH 163/345] be explicit about arguments passed around --- actionpack/lib/action_view/path_set.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/actionpack/lib/action_view/path_set.rb b/actionpack/lib/action_view/path_set.rb index e0cb5d6a70..37b3abbdc9 100644 --- a/actionpack/lib/action_view/path_set.rb +++ b/actionpack/lib/action_view/path_set.rb @@ -25,8 +25,8 @@ module ActionView #:nodoc: [] end - def exists?(*args) - find_all(*args).any? + def exists?(path, prefixes, *args) + find_all(path, prefixes, *args).any? end protected From 681bf1fc481883293a47def022267577224e53b8 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 8 Aug 2011 19:48:12 -0700 Subject: [PATCH 164/345] backporting IO#binread for 1.8 users --- .../lib/active_support/core_ext/io.rb | 15 ++++++++++++ activesupport/test/core_ext/io_test.rb | 23 +++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 activesupport/lib/active_support/core_ext/io.rb create mode 100644 activesupport/test/core_ext/io_test.rb diff --git a/activesupport/lib/active_support/core_ext/io.rb b/activesupport/lib/active_support/core_ext/io.rb new file mode 100644 index 0000000000..75f1055191 --- /dev/null +++ b/activesupport/lib/active_support/core_ext/io.rb @@ -0,0 +1,15 @@ +if RUBY_VERSION < '1.9.2' + +# :stopdoc: +class IO + def self.binread(name, length = nil, offset = nil) + return File.read name unless length || offset + File.open(name, 'rb') { |f| + f.seek offset if offset + f.read length + } + end +end +# :startdoc: + +end diff --git a/activesupport/test/core_ext/io_test.rb b/activesupport/test/core_ext/io_test.rb new file mode 100644 index 0000000000..b9abf685da --- /dev/null +++ b/activesupport/test/core_ext/io_test.rb @@ -0,0 +1,23 @@ +require 'abstract_unit' + +require 'active_support/core_ext/io' + +class IOTest < Test::Unit::TestCase + def test_binread_one_arg + assert_equal File.read(__FILE__), IO.binread(__FILE__) + end + + def test_binread_two_args + assert_equal File.read(__FILE__).bytes.first(10).pack('C*'), + IO.binread(__FILE__, 10) + end + + def test_binread_three_args + actual = IO.binread(__FILE__, 5, 10) + expected = File.open(__FILE__, 'rb') { |f| + f.seek 10 + f.read 5 + } + assert_equal expected, actual + end +end From 0155bf4021e34c70b3b88eaf75ce41e1140fe474 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 8 Aug 2011 19:51:41 -0700 Subject: [PATCH 165/345] use binread to read the files --- actionpack/lib/action_view/template/resolver.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb index 5f7fe81bd5..eea869e7a0 100644 --- a/actionpack/lib/action_view/template/resolver.rb +++ b/actionpack/lib/action_view/template/resolver.rb @@ -1,5 +1,6 @@ require "pathname" require "active_support/core_ext/class" +require "active_support/core_ext/io" require "action_view/template" module ActionView @@ -137,7 +138,7 @@ module ActionView next if File.directory?(p) || !sanitizer[p].include?(p) handler, format = extract_handler_and_format(p, formats) - contents = File.open(p, "rb") { |io| io.read } + contents = File.binread p templates << Template.new(contents, File.expand_path(p), handler, :virtual_path => path.virtual, :format => format, :updated_at => mtime(p)) From 940404096fecd57fdece94d0a6cfe524f20a2aa8 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 8 Aug 2011 21:01:19 -0700 Subject: [PATCH 166/345] use meaningful names with our variables --- actionpack/lib/action_view/template/resolver.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb index eea869e7a0..7c1636fb60 100644 --- a/actionpack/lib/action_view/template/resolver.rb +++ b/actionpack/lib/action_view/template/resolver.rb @@ -134,14 +134,14 @@ module ActionView templates = [] sanitizer = Hash.new { |h,k| h[k] = Dir["#{File.dirname(k)}/*"] } - Dir[query].each do |p| - next if File.directory?(p) || !sanitizer[p].include?(p) + Dir[query].each do |template| + next if File.directory?(template) || !sanitizer[template].include?(template) - handler, format = extract_handler_and_format(p, formats) - contents = File.binread p + handler, format = extract_handler_and_format(template, formats) + contents = File.binread template - templates << Template.new(contents, File.expand_path(p), handler, - :virtual_path => path.virtual, :format => format, :updated_at => mtime(p)) + templates << Template.new(contents, File.expand_path(template), handler, + :virtual_path => path.virtual, :format => format, :updated_at => mtime(template)) end templates From 295a7fd1bb8f56a1c35162bb944c36357008001a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 8 Aug 2011 21:03:40 -0700 Subject: [PATCH 167/345] hash on the template directory in order to improve cache hits --- actionpack/lib/action_view/template/resolver.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb index 7c1636fb60..979be701b2 100644 --- a/actionpack/lib/action_view/template/resolver.rb +++ b/actionpack/lib/action_view/template/resolver.rb @@ -132,10 +132,11 @@ module ActionView def query(path, details, formats) query = build_query(path, details) templates = [] - sanitizer = Hash.new { |h,k| h[k] = Dir["#{File.dirname(k)}/*"] } + sanitizer = Hash.new { |h,dir| h[dir] = Dir["#{dir}/*"] } Dir[query].each do |template| - next if File.directory?(template) || !sanitizer[template].include?(template) + next if File.directory?(template) + next unless sanitizer[File.dirname(template)].include?(template) handler, format = extract_handler_and_format(template, formats) contents = File.binread template From 128467e9278f488e6a97899ee5f7880a8a0c129f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 8 Aug 2011 21:42:45 -0700 Subject: [PATCH 168/345] reduce file stats by improving our dir glob pattern --- actionpack/lib/action_view/template/resolver.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb index 979be701b2..c66990e1ca 100644 --- a/actionpack/lib/action_view/template/resolver.rb +++ b/actionpack/lib/action_view/template/resolver.rb @@ -241,7 +241,7 @@ module ActionView exts.each do |ext| query << "{" - ext.compact.each { |e| query << ".#{e}," } + ext.compact.uniq.each { |e| query << ".#{e}," } query << "}" end From 37b77c6ae7effdba51ecd8b3b91e2cdb0020b6aa Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 8 Aug 2011 22:16:52 -0700 Subject: [PATCH 169/345] refactor the optimized build_query a bit --- actionpack/lib/action_view/template/resolver.rb | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb index c66990e1ca..d0b5c76f1a 100644 --- a/actionpack/lib/action_view/template/resolver.rb +++ b/actionpack/lib/action_view/template/resolver.rb @@ -237,15 +237,10 @@ module ActionView class OptimizedFileSystemResolver < FileSystemResolver #:nodoc: def build_query(path, details) exts = EXTENSIONS.map { |ext| details[ext] } - query = File.join(@path, path) - exts.each do |ext| - query << "{" - ext.compact.uniq.each { |e| query << ".#{e}," } - query << "}" - end - - query + File.join(@path, path) + exts.map { |ext| + "{#{ext.compact.uniq.map { |e| ".#{e}," }.join}}" + }.join end end From 233696a02771abebf867dacc02bce7124b5aa647 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 9 Aug 2011 09:32:16 -0700 Subject: [PATCH 170/345] use functional style to build a list of template objects --- .../lib/action_view/template/resolver.rb | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb index d0b5c76f1a..3abc1b861d 100644 --- a/actionpack/lib/action_view/template/resolver.rb +++ b/actionpack/lib/action_view/template/resolver.rb @@ -131,21 +131,24 @@ module ActionView def query(path, details, formats) query = build_query(path, details) - templates = [] + + # deals with case-insensitive file systems. sanitizer = Hash.new { |h,dir| h[dir] = Dir["#{dir}/*"] } - Dir[query].each do |template| - next if File.directory?(template) - next unless sanitizer[File.dirname(template)].include?(template) + template_paths = Dir[query].reject { |filename| + File.directory?(filename) || + !sanitizer[File.dirname(filename)].include?(filename) + } + template_paths.map { |template| handler, format = extract_handler_and_format(template, formats) contents = File.binread template - templates << Template.new(contents, File.expand_path(template), handler, - :virtual_path => path.virtual, :format => format, :updated_at => mtime(template)) - end - - templates + Template.new(contents, File.expand_path(template), handler, + :virtual_path => path.virtual, + :format => format, + :updated_at => mtime(template)) + } end # Helper for building query glob string based on resolver's pattern. From 1fbc4704df96a8a7e526a3ce4c8110c8e5e26a18 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 9 Aug 2011 10:09:46 -0700 Subject: [PATCH 171/345] the freeze trick does nothing on arrays used as hash keys. --- actionpack/lib/action_view/template/resolver.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb index 3abc1b861d..896baef83c 100644 --- a/actionpack/lib/action_view/template/resolver.rb +++ b/actionpack/lib/action_view/template/resolver.rb @@ -101,13 +101,12 @@ module ActionView if :symbol.respond_to?("<=>") def sort_locals(locals) #:nodoc: - locals.sort.freeze + locals.sort end else def sort_locals(locals) #:nodoc: locals = locals.map{ |l| l.to_s } locals.sort! - locals.freeze end end end From 14a8fd146a64f7ed8399339fa5bc0200b54838ea Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 9 Aug 2011 10:13:02 -0700 Subject: [PATCH 172/345] Just remove the sort_locals method --- actionpack/lib/action_view/template/resolver.rb | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb index 896baef83c..7abaa07bc7 100644 --- a/actionpack/lib/action_view/template/resolver.rb +++ b/actionpack/lib/action_view/template/resolver.rb @@ -69,7 +69,7 @@ module ActionView # before returning it. def cached(key, path_info, details, locals) #:nodoc: name, prefix, partial = path_info - locals = sort_locals(locals) + locals = locals.map { |x| x.to_s }.sort! if key && caching? @cached[key][name][prefix][partial][locals] ||= decorate(yield, path_info, details, locals) @@ -98,17 +98,6 @@ module ActionView t.virtual_path ||= (cached ||= build_path(*path_info)) end end - - if :symbol.respond_to?("<=>") - def sort_locals(locals) #:nodoc: - locals.sort - end - else - def sort_locals(locals) #:nodoc: - locals = locals.map{ |l| l.to_s } - locals.sort! - end - end end # An abstract class that implements a Resolver with path semantics. From 88de343ef4ed314e0134a16c2810e11e482ff481 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 9 Aug 2011 10:54:05 -0700 Subject: [PATCH 173/345] Array#+ automatically dups, no double duping --- actionpack/lib/abstract_controller/view_paths.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/actionpack/lib/abstract_controller/view_paths.rb b/actionpack/lib/abstract_controller/view_paths.rb index 6b7aae8c74..4980576bcd 100644 --- a/actionpack/lib/abstract_controller/view_paths.rb +++ b/actionpack/lib/abstract_controller/view_paths.rb @@ -63,7 +63,7 @@ module AbstractController # the default view path. You may also provide a custom view path # (see ActionView::PathSet for more information) def append_view_path(path) - self.view_paths = view_paths.dup + Array(path) + self.view_paths = view_paths + Array(path) end # Prepend a path to the list of view paths for this controller. @@ -73,7 +73,7 @@ module AbstractController # the default view path. You may also provide a custom view path # (see ActionView::PathSet for more information) def prepend_view_path(path) - self.view_paths = Array(path) + view_paths.dup + self.view_paths = Array(path) + view_paths end # A list of all of the default view paths for this controller. From b14f1c3ad72f7aeef4f725637b835da56bcd7d39 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 9 Aug 2011 11:23:02 -0700 Subject: [PATCH 174/345] Favor composition over inheritance. --- actionpack/lib/action_view/path_set.rb | 54 +++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 6 deletions(-) diff --git a/actionpack/lib/action_view/path_set.rb b/actionpack/lib/action_view/path_set.rb index 37b3abbdc9..b84d9431a4 100644 --- a/actionpack/lib/action_view/path_set.rb +++ b/actionpack/lib/action_view/path_set.rb @@ -1,10 +1,52 @@ module ActionView #:nodoc: # = Action View PathSet - class PathSet < Array #:nodoc: - %w(initialize << concat insert push unshift).each do |method| + class PathSet #:nodoc: + include Enumerable + + attr_reader :paths + + def initialize(paths = []) + @paths = paths + typecast! + end + + def initialize_copy(other) + @paths = other.paths.dup + self + end + + def to_ary + paths.dup + end + + def +(array) + PathSet.new(paths + array) + end + + def include?(item) + paths.include? item + end + + def pop + paths.pop + end + + def size + paths.size + end + + def compact + PathSet.new paths.compact + end + + def each(&block) + paths.each(&block) + end + + %w(<< concat push insert unshift).each do |method| class_eval <<-METHOD, __FILE__, __LINE__ + 1 def #{method}(*args) - super + paths.#{method}(*args) typecast! end METHOD @@ -17,7 +59,7 @@ module ActionView #:nodoc: def find_all(path, prefixes = [], *args) prefixes = [prefixes] if String === prefixes prefixes.each do |prefix| - each do |resolver| + paths.each do |resolver| templates = resolver.find_all(path, prefix, *args) return templates unless templates.empty? end @@ -32,10 +74,10 @@ module ActionView #:nodoc: protected def typecast! - each_with_index do |path, i| + paths.each_with_index do |path, i| path = path.to_s if path.is_a?(Pathname) next unless path.is_a?(String) - self[i] = OptimizedFileSystemResolver.new(path) + paths[i] = OptimizedFileSystemResolver.new(path) end end end From 7cd3772fe65702b6fd0574a5f435efe33c60818c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 9 Aug 2011 11:26:44 -0700 Subject: [PATCH 175/345] only typecast what we need to typecast --- actionpack/lib/action_view/path_set.rb | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/actionpack/lib/action_view/path_set.rb b/actionpack/lib/action_view/path_set.rb index b84d9431a4..e9773120c7 100644 --- a/actionpack/lib/action_view/path_set.rb +++ b/actionpack/lib/action_view/path_set.rb @@ -6,8 +6,7 @@ module ActionView #:nodoc: attr_reader :paths def initialize(paths = []) - @paths = paths - typecast! + @paths = typecast paths end def initialize_copy(other) @@ -19,10 +18,6 @@ module ActionView #:nodoc: paths.dup end - def +(array) - PathSet.new(paths + array) - end - def include?(item) paths.include? item end @@ -35,19 +30,22 @@ module ActionView #:nodoc: paths.size end + def each(&block) + paths.each(&block) + end + def compact PathSet.new paths.compact end - def each(&block) - paths.each(&block) + def +(array) + PathSet.new(paths + array) end %w(<< concat push insert unshift).each do |method| class_eval <<-METHOD, __FILE__, __LINE__ + 1 def #{method}(*args) - paths.#{method}(*args) - typecast! + paths.#{method}(*typecast(args)) end METHOD end @@ -73,7 +71,7 @@ module ActionView #:nodoc: protected - def typecast! + def typecast(paths) paths.each_with_index do |path, i| path = path.to_s if path.is_a?(Pathname) next unless path.is_a?(String) From 26e53a16c4efd479a9bb89202b3e1536e76158b9 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 9 Aug 2011 11:30:43 -0700 Subject: [PATCH 176/345] just use map and case / when rather than modifying the iterating array --- actionpack/lib/action_view/path_set.rb | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/actionpack/lib/action_view/path_set.rb b/actionpack/lib/action_view/path_set.rb index e9773120c7..21dc5617ad 100644 --- a/actionpack/lib/action_view/path_set.rb +++ b/actionpack/lib/action_view/path_set.rb @@ -69,13 +69,16 @@ module ActionView #:nodoc: find_all(path, prefixes, *args).any? end - protected + private def typecast(paths) - paths.each_with_index do |path, i| - path = path.to_s if path.is_a?(Pathname) - next unless path.is_a?(String) - paths[i] = OptimizedFileSystemResolver.new(path) + paths.map do |path| + case path + when Pathname, String + OptimizedFileSystemResolver.new path.to_s + else + path + end end end end From 3ad26c8e489a04a03053ec9f9ea09d7c39e0f3f0 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 9 Aug 2011 11:41:06 -0700 Subject: [PATCH 177/345] avoid object creation via useless duping and freezing --- actionpack/lib/abstract_controller/view_paths.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/actionpack/lib/abstract_controller/view_paths.rb b/actionpack/lib/abstract_controller/view_paths.rb index 4980576bcd..7e11eb3cff 100644 --- a/actionpack/lib/abstract_controller/view_paths.rb +++ b/actionpack/lib/abstract_controller/view_paths.rb @@ -63,7 +63,7 @@ module AbstractController # the default view path. You may also provide a custom view path # (see ActionView::PathSet for more information) def append_view_path(path) - self.view_paths = view_paths + Array(path) + self._view_paths = view_paths + Array(path) end # Prepend a path to the list of view paths for this controller. @@ -73,7 +73,7 @@ module AbstractController # the default view path. You may also provide a custom view path # (see ActionView::PathSet for more information) def prepend_view_path(path) - self.view_paths = Array(path) + view_paths + self._view_paths = ActionView::PathSet.new(Array(path) + view_paths) end # A list of all of the default view paths for this controller. @@ -88,7 +88,6 @@ module AbstractController # otherwise, process the parameter into a PathSet. def view_paths=(paths) self._view_paths = ActionView::Base.process_view_paths(paths) - self._view_paths.freeze end end end From f9f423fa183aeddb8c65bc7974860d0c6c670427 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 9 Aug 2011 12:10:25 -0700 Subject: [PATCH 178/345] deprecating process_view_paths --- actionpack/lib/abstract_controller/view_paths.rb | 2 +- actionpack/lib/action_view/base.rb | 2 ++ actionpack/lib/action_view/lookup_context.rb | 2 +- actionpack/test/template/compiled_templates_test.rb | 2 +- actionpack/test/template/render_test.rb | 2 +- 5 files changed, 6 insertions(+), 4 deletions(-) diff --git a/actionpack/lib/abstract_controller/view_paths.rb b/actionpack/lib/abstract_controller/view_paths.rb index 7e11eb3cff..d18e75ec29 100644 --- a/actionpack/lib/abstract_controller/view_paths.rb +++ b/actionpack/lib/abstract_controller/view_paths.rb @@ -87,7 +87,7 @@ module AbstractController # * paths - If a PathSet is provided, use that; # otherwise, process the parameter into a PathSet. def view_paths=(paths) - self._view_paths = ActionView::Base.process_view_paths(paths) + self._view_paths = ActionView::PathSet.new(Array.wrap(paths)) end end end diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index 36a0a20066..43d67f2032 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -4,6 +4,7 @@ require 'active_support/core_ext/class/attribute' require 'active_support/core_ext/array/wrap' require 'active_support/ordered_options' require 'action_view/log_subscriber' +require 'active_support/core_ext/module/deprecation' module ActionView #:nodoc: # = Action View Base @@ -161,6 +162,7 @@ module ActionView #:nodoc: value.is_a?(PathSet) ? value.dup : ActionView::PathSet.new(Array.wrap(value)) end + deprecate :process_view_paths def xss_safe? #:nodoc: true diff --git a/actionpack/lib/action_view/lookup_context.rb b/actionpack/lib/action_view/lookup_context.rb index 560df15e82..9ec410ac2b 100644 --- a/actionpack/lib/action_view/lookup_context.rb +++ b/actionpack/lib/action_view/lookup_context.rb @@ -78,7 +78,7 @@ module ActionView # Whenever setting view paths, makes a copy so we can manipulate then in # instance objects as we wish. def view_paths=(paths) - @view_paths = ActionView::Base.process_view_paths(paths) + @view_paths = ActionView::PathSet.new(Array.wrap(paths)) end def find(name, prefixes = [], partial = false, keys = []) diff --git a/actionpack/test/template/compiled_templates_test.rb b/actionpack/test/template/compiled_templates_test.rb index 3f31edd5ce..8be0f452fb 100644 --- a/actionpack/test/template/compiled_templates_test.rb +++ b/actionpack/test/template/compiled_templates_test.rb @@ -42,7 +42,7 @@ class CompiledTemplatesTest < Test::Unit::TestCase def render_without_cache(*args) path = ActionView::FileSystemResolver.new(FIXTURE_LOAD_PATH) - view_paths = ActionView::Base.process_view_paths(path) + view_paths = ActionView::PathSet.new([path]) ActionView::Base.new(view_paths, {}).render(*args) end diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb index 6f02f8662d..8a582030f6 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionpack/test/template/render_test.rb @@ -380,7 +380,7 @@ class LazyViewRenderTest < ActiveSupport::TestCase # is not eager loaded def setup path = ActionView::FileSystemResolver.new(FIXTURE_LOAD_PATH) - view_paths = ActionView::Base.process_view_paths(path) + view_paths = ActionView::PathSet.new([path]) assert_equal ActionView::FileSystemResolver.new(FIXTURE_LOAD_PATH), view_paths.first setup_view(view_paths) end From 4f8801963cfc36a5dd28e2c4d281f6d44d815b6e Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Tue, 9 Aug 2011 22:05:23 +0100 Subject: [PATCH 179/345] Okay, the new incompatible arel is now called 2.2 and the sun shines upon thee once more --- activerecord/activerecord.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/activerecord.gemspec b/activerecord/activerecord.gemspec index d978938f18..c91a6ccd35 100644 --- a/activerecord/activerecord.gemspec +++ b/activerecord/activerecord.gemspec @@ -21,6 +21,6 @@ Gem::Specification.new do |s| s.add_dependency('activesupport', version) s.add_dependency('activemodel', version) - s.add_dependency('arel', '~> 2.1.5') + s.add_dependency('arel', '~> 2.2.0') s.add_dependency('tzinfo', '~> 0.3.29') end From 5f56db44549ab1fa821efafa6781e1a8be044d57 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 9 Aug 2011 14:54:39 -0700 Subject: [PATCH 180/345] adding missing require to fist railties tests --- actionpack/lib/abstract_controller/view_paths.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/actionpack/lib/abstract_controller/view_paths.rb b/actionpack/lib/abstract_controller/view_paths.rb index d18e75ec29..e8394447a7 100644 --- a/actionpack/lib/abstract_controller/view_paths.rb +++ b/actionpack/lib/abstract_controller/view_paths.rb @@ -1,3 +1,5 @@ +require 'action_view/base' + module AbstractController module ViewPaths extend ActiveSupport::Concern From d9b690f71f82b52eb7fd4ff01c9d63b6356a035e Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 9 Aug 2011 20:40:52 -0300 Subject: [PATCH 181/345] rake assets:precompile defaults to production env --- actionpack/lib/sprockets/assets.rake | 1 + 1 file changed, 1 insertion(+) diff --git a/actionpack/lib/sprockets/assets.rake b/actionpack/lib/sprockets/assets.rake index 0349b2865e..3bad86413f 100644 --- a/actionpack/lib/sprockets/assets.rake +++ b/actionpack/lib/sprockets/assets.rake @@ -2,6 +2,7 @@ namespace :assets do # Ensures the RAILS_GROUPS environment variable is set task :ensure_env do ENV["RAILS_GROUPS"] ||= "assets" + ENV["RAILS_ENV"] ||= "production" end desc "Compile all the assets named in config.assets.precompile" From bb4f687bc670932f93a7befe07bfb2859a61411a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Tue, 9 Aug 2011 16:49:38 -0700 Subject: [PATCH 182/345] Remove lame comment. --- actionpack/lib/sprockets/assets.rake | 1 - 1 file changed, 1 deletion(-) diff --git a/actionpack/lib/sprockets/assets.rake b/actionpack/lib/sprockets/assets.rake index 3bad86413f..01132d218f 100644 --- a/actionpack/lib/sprockets/assets.rake +++ b/actionpack/lib/sprockets/assets.rake @@ -1,5 +1,4 @@ namespace :assets do - # Ensures the RAILS_GROUPS environment variable is set task :ensure_env do ENV["RAILS_GROUPS"] ||= "assets" ENV["RAILS_ENV"] ||= "production" From d00e1646f7f0faaddf0f89f3051d165aadb2567b Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 10 Aug 2011 11:39:48 -0700 Subject: [PATCH 183/345] add the gem requirement for sqlite3 --- .../lib/active_record/connection_adapters/sqlite3_adapter.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb index c3a7b039ff..0a0da0b5d3 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb @@ -1,4 +1,6 @@ require 'active_record/connection_adapters/sqlite_adapter' + +gem 'sqlite3', '~> 1.3.4' require 'sqlite3' module ActiveRecord From 9e81bfd8fc8a35b28683b3e6b31cd2105b94bb55 Mon Sep 17 00:00:00 2001 From: Gonzalo Rodriguez and Leonardo Capillera Date: Wed, 10 Aug 2011 23:07:38 -0300 Subject: [PATCH 184/345] Remove 'parameters_for_url' parameter from 'form_tag' method signature If you use that parameter it will end calling to url_for with two arguments, which fails because url_for expects only one --- actionpack/lib/action_view/helpers/form_tag_helper.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index 2bbe0c175f..9ed4611123 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -56,8 +56,8 @@ module ActionView # form_tag('http://far.away.com/form', :authenticity_token => "cf50faa3fe97702ca1ae") # # form with custom authenticity token # - def form_tag(url_for_options = {}, options = {}, *parameters_for_url, &block) - html_options = html_options_for_form(url_for_options, options, *parameters_for_url) + def form_tag(url_for_options = {}, options = {}, &block) + html_options = html_options_for_form(url_for_options, options) if block_given? form_tag_in_block(html_options, &block) else @@ -604,12 +604,12 @@ module ActionView end private - def html_options_for_form(url_for_options, options, *parameters_for_url) + def html_options_for_form(url_for_options, options) options.stringify_keys.tap do |html_options| html_options["enctype"] = "multipart/form-data" if html_options.delete("multipart") # The following URL is unescaped, this is just a hash of options, and it is the # responsibility of the caller to escape all the values. - html_options["action"] = url_for(url_for_options, *parameters_for_url) + html_options["action"] = url_for(url_for_options) html_options["accept-charset"] = "UTF-8" html_options["data-remote"] = true if html_options.delete("remote") html_options["authenticity_token"] = html_options.delete("authenticity_token") if html_options.has_key?("authenticity_token") From 895d64531d25a76c1de2d4fec9aba68c0ee8c104 Mon Sep 17 00:00:00 2001 From: Waynn Lue Date: Thu, 11 Aug 2011 00:30:45 -0700 Subject: [PATCH 185/345] fix destructive stringify_keys for label_tag --- actionpack/lib/action_view/helpers/form_tag_helper.rb | 4 ++-- actionpack/test/template/form_tag_helper_test.rb | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index 2bbe0c175f..92349508e6 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -179,9 +179,9 @@ module ActionView def label_tag(name = nil, content_or_options = nil, options = nil, &block) options = content_or_options if block_given? && content_or_options.is_a?(Hash) options ||= {} - options.stringify_keys! + options = options.stringify_keys options["for"] = sanitize_to_id(name) unless name.blank? || options.has_key?("for") - content_tag :label, content_or_options || name.to_s.humanize, options, &block + content_tag :label, content_or_options.is_a?(Hash) ? options : (content_or_options || name.to_s.humanize), options, &block end # Creates a hidden form input field used to transmit data that would be lost due to HTTP's statelessness or diff --git a/actionpack/test/template/form_tag_helper_test.rb b/actionpack/test/template/form_tag_helper_test.rb index ad31812273..c8e47e4f71 100644 --- a/actionpack/test/template/form_tag_helper_test.rb +++ b/actionpack/test/template/form_tag_helper_test.rb @@ -530,6 +530,12 @@ class FormTagHelperTest < ActionView::TestCase assert_equal options, { :option => "random_option" } end + def test_image_label_tag_options_symbolize_keys_side_effects + options = { :option => "random_option" } + actual = label_tag "submit source", "title", options + assert_equal options, { :option => "random_option" } + end + def protect_against_forgery? false end From 61579b76616d06ccb8268411421c23fb612e5113 Mon Sep 17 00:00:00 2001 From: Andrew Kaspick Date: Thu, 11 Aug 2011 13:28:31 -0500 Subject: [PATCH 186/345] when calling url_for with a hash, additional (likely unwanted) values (such as :host) would be returned in the hash... calling #dup on the hash prevents this --- actionpack/lib/action_dispatch/routing/url_for.rb | 2 +- actionpack/test/dispatch/routing_test.rb | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/actionpack/lib/action_dispatch/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb index 480144fe9d..5d354b0fb8 100644 --- a/actionpack/lib/action_dispatch/routing/url_for.rb +++ b/actionpack/lib/action_dispatch/routing/url_for.rb @@ -140,7 +140,7 @@ module ActionDispatch when String options when nil, Hash - _routes.url_for((options || {}).reverse_merge!(url_options).symbolize_keys) + _routes.url_for((options.dup || {}).reverse_merge!(url_options).symbolize_keys) else polymorphic_url(options) end diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index 1938348375..9685b24c1c 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -851,6 +851,18 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end + # tests the use of dup in url_for + def test_url_for_with_no_side_effects + # without dup, additional (and possibly unwanted) values will be present in the options (eg. :host) + original_options = {:controller => 'projects', :action => 'status'} + options = original_options.dup + + url_for options + + # verify that the options passed in have not changed from the original ones + assert_equal original_options, options + end + def test_projects_status with_test_routes do assert_equal '/projects/status', url_for(:controller => 'projects', :action => 'status', :only_path => true) From 8196c842b6f32271c23cba6b97918d32747018d8 Mon Sep 17 00:00:00 2001 From: Arun Agrawal Date: Fri, 12 Aug 2011 16:44:31 +0530 Subject: [PATCH 187/345] We actually don't need a reverse_merge! here. dup removed was giving error with nil class. --- actionpack/lib/action_dispatch/routing/url_for.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/action_dispatch/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb index 5d354b0fb8..de14113c51 100644 --- a/actionpack/lib/action_dispatch/routing/url_for.rb +++ b/actionpack/lib/action_dispatch/routing/url_for.rb @@ -140,7 +140,7 @@ module ActionDispatch when String options when nil, Hash - _routes.url_for((options.dup || {}).reverse_merge!(url_options).symbolize_keys) + _routes.url_for((options || {}).reverse_merge(url_options).symbolize_keys) else polymorphic_url(options) end From 943a37348a9fdef73670be3d8452d436b7db0e69 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 12 Aug 2011 15:53:14 -0700 Subject: [PATCH 188/345] moving test_generate to an integration test with one assert per test --- actionpack/test/controller/routing_test.rb | 108 ----------- .../controller/url_for_integration_test.rb | 183 ++++++++++++++++++ 2 files changed, 183 insertions(+), 108 deletions(-) create mode 100644 actionpack/test/controller/url_for_integration_test.rb diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb index b693fbec2b..5bf68decca 100644 --- a/actionpack/test/controller/routing_test.rb +++ b/actionpack/test/controller/routing_test.rb @@ -1664,114 +1664,6 @@ class RackMountIntegrationTests < ActiveSupport::TestCase assert_raise(ActionController::RoutingError) { @routes.recognize_path('/none', :method => :get) } end - def test_generate - assert_equal '/admin/users', url_for(@routes, { :use_route => 'admin_users' }) - assert_equal '/admin/users', url_for(@routes, { :controller => 'admin/users' }) - assert_equal '/admin/users', url_for(@routes, { :controller => 'admin/users', :action => 'index' }) - assert_equal '/admin/users', url_for(@routes, { :action => 'index' }, { :controller => 'admin/users' }) - assert_equal '/admin/users', url_for(@routes, { :controller => 'users', :action => 'index' }, { :controller => 'admin/accounts' }) - assert_equal '/people', url_for(@routes, { :controller => '/people', :action => 'index' }, { :controller => 'admin/accounts' }) - - assert_equal '/admin/posts', url_for(@routes, { :controller => 'admin/posts' }) - assert_equal '/admin/posts/new', url_for(@routes, { :controller => 'admin/posts', :action => 'new' }) - - assert_equal '/blog/2009', url_for(@routes, { :controller => 'posts', :action => 'show_date', :year => 2009 }) - assert_equal '/blog/2009/1', url_for(@routes, { :controller => 'posts', :action => 'show_date', :year => 2009, :month => 1 }) - assert_equal '/blog/2009/1/1', url_for(@routes, { :controller => 'posts', :action => 'show_date', :year => 2009, :month => 1, :day => 1 }) - - assert_equal '/archive/2010', url_for(@routes, { :controller => 'archive', :action => 'index', :year => '2010' }) - assert_equal '/archive', url_for(@routes, { :controller => 'archive', :action => 'index' }) - assert_equal '/archive?year=january', url_for(@routes, { :controller => 'archive', :action => 'index', :year => 'january' }) - - assert_equal '/people', url_for(@routes, { :controller => 'people', :action => 'index' }) - assert_equal '/people', url_for(@routes, { :action => 'index' }, { :controller => 'people' }) - assert_equal '/people', url_for(@routes, { :action => 'index' }, { :controller => 'people', :action => 'show', :id => '1' }) - assert_equal '/people', url_for(@routes, { :controller => 'people', :action => 'index' }, { :controller => 'people', :action => 'show', :id => '1' }) - assert_equal '/people', url_for(@routes, {}, { :controller => 'people', :action => 'index' }) - assert_equal '/people/1', url_for(@routes, { :controller => 'people', :action => 'show' }, { :controller => 'people', :action => 'show', :id => '1' }) - assert_equal '/people/new', url_for(@routes, { :use_route => 'new_person' }) - assert_equal '/people/new', url_for(@routes, { :controller => 'people', :action => 'new' }) - assert_equal '/people/1', url_for(@routes, { :use_route => 'person', :id => '1' }) - assert_equal '/people/1', url_for(@routes, { :controller => 'people', :action => 'show', :id => '1' }) - assert_equal '/people/1.xml', url_for(@routes, { :controller => 'people', :action => 'show', :id => '1', :format => 'xml' }) - assert_equal '/people/1', url_for(@routes, { :controller => 'people', :action => 'show', :id => 1 }) - assert_equal '/people/1', url_for(@routes, { :controller => 'people', :action => 'show', :id => Model.new('1') }) - assert_equal '/people/1', url_for(@routes, { :action => 'show', :id => '1' }, { :controller => 'people', :action => 'index' }) - assert_equal '/people/1', url_for(@routes, { :action => 'show', :id => 1 }, { :controller => 'people', :action => 'show', :id => '1' }) - assert_equal '/people', url_for(@routes, { :controller => 'people', :action => 'index' }, { :controller => 'people', :action => 'show', :id => '1' }) - assert_equal '/people/1', url_for(@routes, {}, { :controller => 'people', :action => 'show', :id => '1' }) - assert_equal '/people/1', url_for(@routes, { :controller => 'people', :action => 'show' }, { :controller => 'people', :action => 'index', :id => '1' }) - assert_equal '/people/1/edit', url_for(@routes, { :controller => 'people', :action => 'edit', :id => '1' }) - assert_equal '/people/1/edit.xml', url_for(@routes, { :controller => 'people', :action => 'edit', :id => '1', :format => 'xml' }) - assert_equal '/people/1/edit', url_for(@routes, { :use_route => 'edit_person', :id => '1' }) - assert_equal '/people/1?legacy=true', url_for(@routes, { :controller => 'people', :action => 'show', :id => '1', :legacy => 'true' }) - assert_equal '/people?legacy=true', url_for(@routes, { :controller => 'people', :action => 'index', :legacy => 'true' }) - - assert_equal '/id_default/2', url_for(@routes, { :controller => 'foo', :action => 'id_default', :id => '2' }) - assert_equal '/id_default', url_for(@routes, { :controller => 'foo', :action => 'id_default', :id => '1' }) - assert_equal '/id_default', url_for(@routes, { :controller => 'foo', :action => 'id_default', :id => 1 }) - assert_equal '/id_default', url_for(@routes, { :controller => 'foo', :action => 'id_default' }) - assert_equal '/optional/bar', url_for(@routes, { :controller => 'posts', :action => 'index', :optional => 'bar' }) - assert_equal '/posts', url_for(@routes, { :controller => 'posts', :action => 'index' }) - - assert_equal '/project', url_for(@routes, { :controller => 'project', :action => 'index' }) - assert_equal '/projects/1', url_for(@routes, { :controller => 'project', :action => 'index', :project_id => '1' }) - assert_equal '/projects/1', url_for(@routes, { :controller => 'project', :action => 'index'}, {:project_id => '1' }) - assert_raise(ActionController::RoutingError) { url_for(@routes, { :use_route => 'project', :controller => 'project', :action => 'index' }) } - assert_equal '/projects/1', url_for(@routes, { :use_route => 'project', :controller => 'project', :action => 'index', :project_id => '1' }) - assert_equal '/projects/1', url_for(@routes, { :use_route => 'project', :controller => 'project', :action => 'index' }, { :project_id => '1' }) - - assert_equal '/clients', url_for(@routes, { :controller => 'projects', :action => 'index' }) - assert_equal '/clients?project_id=1', url_for(@routes, { :controller => 'projects', :action => 'index', :project_id => '1' }) - assert_equal '/clients', url_for(@routes, { :controller => 'projects', :action => 'index' }, { :project_id => '1' }) - assert_equal '/clients', url_for(@routes, { :action => 'index' }, { :controller => 'projects', :action => 'index', :project_id => '1' }) - - assert_equal '/comment/20', url_for(@routes, { :id => 20 }, { :controller => 'comments', :action => 'show' }) - assert_equal '/comment/20', url_for(@routes, { :controller => 'comments', :id => 20, :action => 'show' }) - assert_equal '/comments/boo', url_for(@routes, { :controller => 'comments', :action => 'boo' }) - - assert_equal '/ws/posts/show/1', url_for(@routes, { :controller => 'posts', :action => 'show', :id => '1', :ws => true }) - assert_equal '/ws/posts', url_for(@routes, { :controller => 'posts', :action => 'index', :ws => true }) - - assert_equal '/account', url_for(@routes, { :controller => 'account', :action => 'subscription' }) - assert_equal '/account/billing', url_for(@routes, { :controller => 'account', :action => 'billing' }) - - assert_equal '/pages/1/notes/show/1', url_for(@routes, { :page_id => '1', :controller => 'notes', :action => 'show', :id => '1' }) - assert_equal '/pages/1/notes/list', url_for(@routes, { :page_id => '1', :controller => 'notes', :action => 'list' }) - assert_equal '/pages/1/notes', url_for(@routes, { :page_id => '1', :controller => 'notes', :action => 'index' }) - assert_equal '/pages/1/notes', url_for(@routes, { :page_id => '1', :controller => 'notes' }) - assert_equal '/notes', url_for(@routes, { :page_id => nil, :controller => 'notes' }) - assert_equal '/notes', url_for(@routes, { :controller => 'notes' }) - assert_equal '/notes/print', url_for(@routes, { :controller => 'notes', :action => 'print' }) - assert_equal '/notes/print', url_for(@routes, {}, { :controller => 'notes', :action => 'print' }) - - assert_equal '/notes/index/1', url_for(@routes, { :controller => 'notes' }, { :controller => 'notes', :id => '1' }) - assert_equal '/notes/index/1', url_for(@routes, { :controller => 'notes' }, { :controller => 'notes', :id => '1', :foo => 'bar' }) - assert_equal '/notes/index/1', url_for(@routes, { :controller => 'notes' }, { :controller => 'notes', :id => '1' }) - assert_equal '/notes/index/1', url_for(@routes, { :action => 'index' }, { :controller => 'notes', :id => '1' }) - assert_equal '/notes/index/1', url_for(@routes, {}, { :controller => 'notes', :id => '1' }) - assert_equal '/notes/show/1', url_for(@routes, {}, { :controller => 'notes', :action => 'show', :id => '1' }) - assert_equal '/notes/index/1', url_for(@routes, { :controller => 'notes', :id => '1' }, { :foo => 'bar' }) - assert_equal '/posts', url_for(@routes, { :controller => 'posts' }, { :controller => 'notes', :action => 'show', :id => '1' }) - assert_equal '/notes/list', url_for(@routes, { :action => 'list' }, { :controller => 'notes', :action => 'show', :id => '1' }) - - assert_equal '/posts/ping', url_for(@routes, { :controller => 'posts', :action => 'ping' }) - assert_equal '/posts/show/1', url_for(@routes, { :controller => 'posts', :action => 'show', :id => '1' }) - assert_equal '/posts', url_for(@routes, { :controller => 'posts' }) - assert_equal '/posts', url_for(@routes, { :controller => 'posts', :action => 'index' }) - assert_equal '/posts', url_for(@routes, { :controller => 'posts' }, { :controller => 'posts', :action => 'index' }) - assert_equal '/posts/create', url_for(@routes, { :action => 'create' }, { :controller => 'posts' }) - assert_equal '/posts?foo=bar', url_for(@routes, { :controller => 'posts', :foo => 'bar' }) - assert_equal '/posts?foo%5B%5D=bar&foo%5B%5D=baz', url_for(@routes, { :controller => 'posts', :foo => ['bar', 'baz'] }) - assert_equal '/posts?page=2', url_for(@routes, { :controller => 'posts', :page => 2 }) - assert_equal '/posts?q%5Bfoo%5D%5Ba%5D=b', url_for(@routes, { :controller => 'posts', :q => { :foo => { :a => 'b'}} }) - - assert_equal '/news.rss', url_for(@routes, { :controller => 'news', :action => 'index', :format => 'rss' }) - - - assert_raise(ActionController::RoutingError) { url_for(@routes, { :action => 'index' }) } - end - def test_generate_extras assert_equal ['/people', []], @routes.generate_extras(:controller => 'people') assert_equal ['/people', [:foo]], @routes.generate_extras(:controller => 'people', :foo => 'bar') diff --git a/actionpack/test/controller/url_for_integration_test.rb b/actionpack/test/controller/url_for_integration_test.rb new file mode 100644 index 0000000000..7b734ff0fb --- /dev/null +++ b/actionpack/test/controller/url_for_integration_test.rb @@ -0,0 +1,183 @@ +# encoding: utf-8 +require 'abstract_unit' +require 'controller/fake_controllers' +require 'active_support/core_ext/object/with_options' + +module RoutingTestHelpers + def url_for(set, options, recall = nil) + set.send(:url_for, options.merge(:only_path => true, :_path_segments => recall)) + end +end + +module ActionPack + class URLForIntegrationTest < ActiveSupport::TestCase + include RoutingTestHelpers + + Model = Struct.new(:to_param) + + Mapping = lambda { + namespace :admin do + resources :users, :posts + end + + namespace 'api' do + root :to => 'users#index' + end + + match '/blog(/:year(/:month(/:day)))' => 'posts#show_date', + :constraints => { + :year => /(19|20)\d\d/, + :month => /[01]?\d/, + :day => /[0-3]?\d/ + }, + :day => nil, + :month => nil + + match 'archive/:year', :controller => 'archive', :action => 'index', + :defaults => { :year => nil }, + :constraints => { :year => /\d{4}/ }, + :as => "blog" + + resources :people + #match 'legacy/people' => "people#index", :legacy => "true" + + match 'symbols', :controller => :symbols, :action => :show, :name => :as_symbol + match 'id_default(/:id)' => "foo#id_default", :id => 1 + match 'get_or_post' => "foo#get_or_post", :via => [:get, :post] + match 'optional/:optional' => "posts#index" + match 'projects/:project_id' => "project#index", :as => "project" + match 'clients' => "projects#index" + + match 'ignorecase/geocode/:postalcode' => 'geocode#show', :postalcode => /hx\d\d-\d[a-z]{2}/i + match 'extended/geocode/:postalcode' => 'geocode#show',:constraints => { + :postalcode => /# Postcode format + \d{5} #Prefix + (-\d{4})? #Suffix + /x + }, :as => "geocode" + + match 'news(.:format)' => "news#index" + + match 'comment/:id(/:action)' => "comments#show" + match 'ws/:controller(/:action(/:id))', :ws => true + match 'account(/:action)' => "account#subscription" + match 'pages/:page_id/:controller(/:action(/:id))' + match ':controller/ping', :action => 'ping' + match ':controller(/:action(/:id))(.:format)' + root :to => "news#index" + } + + def setup + @routes = ActionDispatch::Routing::RouteSet.new + @routes.draw(&Mapping) + end + + [ + ['/admin/users',[ { :use_route => 'admin_users' }]], + ['/admin/users',[ { :controller => 'admin/users' }]], + ['/admin/users',[ { :controller => 'admin/users', :action => 'index' }]], + ['/admin/users',[ { :action => 'index' }, { :controller => 'admin/users' }]], + ['/admin/users',[ { :controller => 'users', :action => 'index' }, { :controller => 'admin/accounts' }]], + ['/people',[ { :controller => '/people', :action => 'index' }, { :controller => 'admin/accounts' }]], + + ['/admin/posts',[ { :controller => 'admin/posts' }]], + ['/admin/posts/new',[ { :controller => 'admin/posts', :action => 'new' }]], + + ['/blog/2009',[ { :controller => 'posts', :action => 'show_date', :year => 2009 }]], + ['/blog/2009/1',[ { :controller => 'posts', :action => 'show_date', :year => 2009, :month => 1 }]], + ['/blog/2009/1/1',[ { :controller => 'posts', :action => 'show_date', :year => 2009, :month => 1, :day => 1 }]], + + ['/archive/2010',[ { :controller => 'archive', :action => 'index', :year => '2010' }]], + ['/archive',[ { :controller => 'archive', :action => 'index' }]], + ['/archive?year=january',[ { :controller => 'archive', :action => 'index', :year => 'january' }]], + + ['/people',[ { :controller => 'people', :action => 'index' }]], + ['/people',[ { :action => 'index' }, { :controller => 'people' }]], + ['/people',[ { :action => 'index' }, { :controller => 'people', :action => 'show', :id => '1' }]], + ['/people',[ { :controller => 'people', :action => 'index' }, { :controller => 'people', :action => 'show', :id => '1' }]], + ['/people',[ {}, { :controller => 'people', :action => 'index' }]], + ['/people/1',[ { :controller => 'people', :action => 'show' }, { :controller => 'people', :action => 'show', :id => '1' }]], + ['/people/new',[ { :use_route => 'new_person' }]], + ['/people/new',[ { :controller => 'people', :action => 'new' }]], + ['/people/1',[ { :use_route => 'person', :id => '1' }]], + ['/people/1',[ { :controller => 'people', :action => 'show', :id => '1' }]], + ['/people/1.xml',[ { :controller => 'people', :action => 'show', :id => '1', :format => 'xml' }]], + ['/people/1',[ { :controller => 'people', :action => 'show', :id => 1 }]], + ['/people/1',[ { :controller => 'people', :action => 'show', :id => Model.new('1') }]], + ['/people/1',[ { :action => 'show', :id => '1' }, { :controller => 'people', :action => 'index' }]], + ['/people/1',[ { :action => 'show', :id => 1 }, { :controller => 'people', :action => 'show', :id => '1' }]], + ['/people',[ { :controller => 'people', :action => 'index' }, { :controller => 'people', :action => 'show', :id => '1' }]], + ['/people/1',[ {}, { :controller => 'people', :action => 'show', :id => '1' }]], + ['/people/1',[ { :controller => 'people', :action => 'show' }, { :controller => 'people', :action => 'index', :id => '1' }]], + ['/people/1/edit',[ { :controller => 'people', :action => 'edit', :id => '1' }]], + ['/people/1/edit.xml',[ { :controller => 'people', :action => 'edit', :id => '1', :format => 'xml' }]], + ['/people/1/edit',[ { :use_route => 'edit_person', :id => '1' }]], + ['/people/1?legacy=true',[ { :controller => 'people', :action => 'show', :id => '1', :legacy => 'true' }]], + ['/people?legacy=true',[ { :controller => 'people', :action => 'index', :legacy => 'true' }]], + + ['/id_default/2',[ { :controller => 'foo', :action => 'id_default', :id => '2' }]], + ['/id_default',[ { :controller => 'foo', :action => 'id_default', :id => '1' }]], + ['/id_default',[ { :controller => 'foo', :action => 'id_default', :id => 1 }]], + ['/id_default',[ { :controller => 'foo', :action => 'id_default' }]], + ['/optional/bar',[ { :controller => 'posts', :action => 'index', :optional => 'bar' }]], + ['/posts',[ { :controller => 'posts', :action => 'index' }]], + + ['/project',[ { :controller => 'project', :action => 'index' }]], + ['/projects/1',[ { :controller => 'project', :action => 'index', :project_id => '1' }]], + ['/projects/1',[ { :controller => 'project', :action => 'index'}, {:project_id => '1' }]], + ['/projects/1',[ { :use_route => 'project', :controller => 'project', :action => 'index', :project_id => '1' }]], + ['/projects/1',[ { :use_route => 'project', :controller => 'project', :action => 'index' }, { :project_id => '1' }]], + + ['/clients',[ { :controller => 'projects', :action => 'index' }]], + ['/clients?project_id=1',[ { :controller => 'projects', :action => 'index', :project_id => '1' }]], + ['/clients',[ { :controller => 'projects', :action => 'index' }, { :project_id => '1' }]], + ['/clients',[ { :action => 'index' }, { :controller => 'projects', :action => 'index', :project_id => '1' }]], + + ['/comment/20',[ { :id => 20 }, { :controller => 'comments', :action => 'show' }]], + ['/comment/20',[ { :controller => 'comments', :id => 20, :action => 'show' }]], + ['/comments/boo',[ { :controller => 'comments', :action => 'boo' }]], + + ['/ws/posts/show/1',[ { :controller => 'posts', :action => 'show', :id => '1', :ws => true }]], + ['/ws/posts',[ { :controller => 'posts', :action => 'index', :ws => true }]], + + ['/account',[ { :controller => 'account', :action => 'subscription' }]], + ['/account/billing',[ { :controller => 'account', :action => 'billing' }]], + + ['/pages/1/notes/show/1',[ { :page_id => '1', :controller => 'notes', :action => 'show', :id => '1' }]], + ['/pages/1/notes/list',[ { :page_id => '1', :controller => 'notes', :action => 'list' }]], + ['/pages/1/notes',[ { :page_id => '1', :controller => 'notes', :action => 'index' }]], + ['/pages/1/notes',[ { :page_id => '1', :controller => 'notes' }]], + ['/notes',[ { :page_id => nil, :controller => 'notes' }]], + ['/notes',[ { :controller => 'notes' }]], + ['/notes/print',[ { :controller => 'notes', :action => 'print' }]], + ['/notes/print',[ {}, { :controller => 'notes', :action => 'print' }]], + + ['/notes/index/1',[ { :controller => 'notes' }, { :controller => 'notes', :id => '1' }]], + ['/notes/index/1',[ { :controller => 'notes' }, { :controller => 'notes', :id => '1', :foo => 'bar' }]], + ['/notes/index/1',[ { :controller => 'notes' }, { :controller => 'notes', :id => '1' }]], + ['/notes/index/1',[ { :action => 'index' }, { :controller => 'notes', :id => '1' }]], + ['/notes/index/1',[ {}, { :controller => 'notes', :id => '1' }]], + ['/notes/show/1',[ {}, { :controller => 'notes', :action => 'show', :id => '1' }]], + ['/notes/index/1',[ { :controller => 'notes', :id => '1' }, { :foo => 'bar' }]], + ['/posts',[ { :controller => 'posts' }, { :controller => 'notes', :action => 'show', :id => '1' }]], + ['/notes/list',[ { :action => 'list' }, { :controller => 'notes', :action => 'show', :id => '1' }]], + + ['/posts/ping',[ { :controller => 'posts', :action => 'ping' }]], + ['/posts/show/1',[ { :controller => 'posts', :action => 'show', :id => '1' }]], + ['/posts',[ { :controller => 'posts' }]], + ['/posts',[ { :controller => 'posts', :action => 'index' }]], + ['/posts',[ { :controller => 'posts' }, { :controller => 'posts', :action => 'index' }]], + ['/posts/create',[ { :action => 'create' }, { :controller => 'posts' }]], + ['/posts?foo=bar',[ { :controller => 'posts', :foo => 'bar' }]], + ['/posts?foo%5B%5D=bar&foo%5B%5D=baz', [{ :controller => 'posts', :foo => ['bar', 'baz'] }]], + ['/posts?page=2', [{ :controller => 'posts', :page => 2 }]], + ['/posts?q%5Bfoo%5D%5Ba%5D=b', [{ :controller => 'posts', :q => { :foo => { :a => 'b'}} }]], + + ['/news.rss', [{ :controller => 'news', :action => 'index', :format => 'rss' }]], + ].each_with_index do |(url, params), i| + define_method("test_#{url.gsub(/\W/, '_')}_#{i}") do + assert_equal url, url_for(@routes, *params), params.inspect + end + end + end +end From d3c15a1d31d77e44b142c96cb55b654f3552a89d Mon Sep 17 00:00:00 2001 From: Myron Marston Date: Fri, 12 Aug 2011 19:58:37 -0700 Subject: [PATCH 189/345] Allow ActiveRecord observers to be disabled. We have to use Observer#update rather than Observer#send since the enabled state is checked in #update before forwarding the method call on. --- activemodel/lib/active_model/observing.rb | 4 ++-- activemodel/test/cases/observing_test.rb | 12 ++++++++++++ activerecord/lib/active_record/observer.rb | 2 +- activerecord/test/cases/lifecycle_test.rb | 12 ++++++++++++ 4 files changed, 27 insertions(+), 3 deletions(-) diff --git a/activemodel/lib/active_model/observing.rb b/activemodel/lib/active_model/observing.rb index d48f2e8a1f..7a910d18e7 100644 --- a/activemodel/lib/active_model/observing.rb +++ b/activemodel/lib/active_model/observing.rb @@ -226,10 +226,10 @@ module ActiveModel # Send observed_method(object) if the method exists and # the observer is enabled for the given object's class. - def update(observed_method, object) #:nodoc: + def update(observed_method, object, &block) #:nodoc: return unless respond_to?(observed_method) return if disabled_for?(object) - send(observed_method, object) + send(observed_method, object, &block) end # Special method sent by the observed class when it is inherited. diff --git a/activemodel/test/cases/observing_test.rb b/activemodel/test/cases/observing_test.rb index 99b1f407ae..f6ec24ae57 100644 --- a/activemodel/test/cases/observing_test.rb +++ b/activemodel/test/cases/observing_test.rb @@ -17,6 +17,10 @@ class FooObserver < ActiveModel::Observer def on_spec(record) stub.event_with(record) if stub end + + def around_save(record) + yield :in_around_save + end end class Foo @@ -133,4 +137,12 @@ class ObserverTest < ActiveModel::TestCase foo = Foo.new Foo.send(:notify_observers, :whatever, foo) end + + test "update passes a block on to the observer" do + yielded_value = nil + FooObserver.instance.update(:around_save, Foo.new) do |val| + yielded_value = val + end + assert_equal :in_around_save, yielded_value + end end diff --git a/activerecord/lib/active_record/observer.rb b/activerecord/lib/active_record/observer.rb index 5a5351b517..fdf17c003c 100644 --- a/activerecord/lib/active_record/observer.rb +++ b/activerecord/lib/active_record/observer.rb @@ -111,7 +111,7 @@ module ActiveRecord callback_meth = :"_notify_#{observer_name}_for_#{callback}" unless klass.respond_to?(callback_meth) klass.send(:define_method, callback_meth) do |&block| - observer.send(callback, self, &block) + observer.update(callback, self, &block) end klass.send(callback, callback_meth) end diff --git a/activerecord/test/cases/lifecycle_test.rb b/activerecord/test/cases/lifecycle_test.rb index 643e949087..75e5dfa49b 100644 --- a/activerecord/test/cases/lifecycle_test.rb +++ b/activerecord/test/cases/lifecycle_test.rb @@ -231,6 +231,18 @@ class LifecycleTest < ActiveRecord::TestCase assert_not_nil observer.topic_ids.last end + test "able to disable observers" do + observer = DeveloperObserver.instance # activate + observer.calls.clear + + ActiveRecord::Base.observers.disable DeveloperObserver do + Developer.create! :name => 'Ancestor', :salary => 100000 + SpecialDeveloper.create! :name => 'Descendent', :salary => 100000 + end + + assert_equal [], observer.calls + end + def test_observer_is_called_once observer = DeveloperObserver.instance # activate observer.calls.clear From 5bc87cc2ee684ec19b9dada596c901488dc9295b Mon Sep 17 00:00:00 2001 From: Arun Agrawal Date: Sat, 13 Aug 2011 13:13:05 +0530 Subject: [PATCH 190/345] We need [] method here. previously it's an array. --- actionpack/lib/action_view/path_set.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/actionpack/lib/action_view/path_set.rb b/actionpack/lib/action_view/path_set.rb index 21dc5617ad..bbb1af8154 100644 --- a/actionpack/lib/action_view/path_set.rb +++ b/actionpack/lib/action_view/path_set.rb @@ -14,6 +14,10 @@ module ActionView #:nodoc: self end + def [](i) + paths[i] + end + def to_ary paths.dup end From 34689c40a03c9921b5c43ac1e120a9885edded73 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Sat, 13 Aug 2011 13:54:54 +0100 Subject: [PATCH 191/345] Work around for lolruby bug. (Read on for explanation.) We were experiencing CI test failures, for example: * 3-1-stable: http://travis-ci.org/#!/rails/rails/builds/79473/L407 * master: http://travis-ci.org/#!/rails/rails/builds/79507/L80 These failures only happened on 1.8.7-p352, and we were only able to reproduce on the Travis CI VM worker. We even tried creating a new 32 bit Ubuntu VM and running the tests on that, and it all worked fine. After some epic trial and error, we discovered that replacing the following: fuu = Marshal.load(Marshal.dump(fuu)) with: marshalled = Marshal.dump(fuu) fuu = Marshal.load(marshalled) seemed to prevent the failure. We have NO IDEA why this is. If anyone has some great insight to contribute then that is welcome. Otherwise, hopefully this will just help us get the CI green again. Many thanks to @joshk for help with sorting this out. --- .../test/cases/associations/extension_test.rb | 8 ++++++-- activerecord/test/cases/base_test.rb | 11 ++++++++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/activerecord/test/cases/associations/extension_test.rb b/activerecord/test/cases/associations/extension_test.rb index 24830a661a..490fc5177e 100644 --- a/activerecord/test/cases/associations/extension_test.rb +++ b/activerecord/test/cases/associations/extension_test.rb @@ -39,7 +39,9 @@ class AssociationsExtensionsTest < ActiveRecord::TestCase david = developers(:david) assert_equal projects(:action_controller), david.projects.find_most_recent - david = Marshal.load(Marshal.dump(david)) + marshalled = Marshal.dump(david) + david = Marshal.load(marshalled) + assert_equal projects(:action_controller), david.projects.find_most_recent end @@ -47,7 +49,9 @@ class AssociationsExtensionsTest < ActiveRecord::TestCase david = developers(:david) assert_equal projects(:action_controller), david.projects_extended_by_name.find_most_recent - david = Marshal.load(Marshal.dump(david)) + marshalled = Marshal.dump(david) + david = Marshal.load(marshalled) + assert_equal projects(:action_controller), david.projects_extended_by_name.find_most_recent end diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index c78d887ed7..b8ebabfe70 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -1808,20 +1808,25 @@ class BasicsTest < ActiveRecord::TestCase def test_marshal_round_trip expected = posts(:welcome) - actual = Marshal.load(Marshal.dump(expected)) + marshalled = Marshal.dump(expected) + actual = Marshal.load(marshalled) assert_equal expected.attributes, actual.attributes end def test_marshal_new_record_round_trip - post = Marshal.load(Marshal.dump(Post.new)) + marshalled = Marshal.dump(Post.new) + post = Marshal.load(marshalled) + assert post.new_record?, "should be a new record" end def test_marshalling_with_associations post = Post.new post.comments.build - post = Marshal.load(Marshal.dump(post)) + + marshalled = Marshal.dump(post) + post = Marshal.load(marshalled) assert_equal 1, post.comments.length end From 24f902b1bcfa5dca4bfc7f2b978a4b0dece73894 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Sat, 13 Aug 2011 16:37:44 +0100 Subject: [PATCH 192/345] Fix default scope thread safety. Thanks @thedarkone for reporting. --- activerecord/lib/active_record/base.rb | 39 ++++++++++++------- .../test/cases/relation_scoping_test.rb | 18 +++++++++ activerecord/test/models/developer.rb | 9 +++++ 3 files changed, 52 insertions(+), 14 deletions(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 102d8f4175..5a57e1bc70 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1206,6 +1206,14 @@ MSG Thread.current["#{self}_current_scope"] = scope end + def ignore_default_scope? #:nodoc: + Thread.current["#{self}_ignore_default_scope"] + end + + def ignore_default_scope=(ignore) #:nodoc: + Thread.current["#{self}_ignore_default_scope"] = ignore + end + # Use this macro in your model to set a default scope for all operations on # the model. # @@ -1259,24 +1267,27 @@ MSG # The @ignore_default_scope flag is used to prevent an infinite recursion situation where # a default scope references a scope which has a default scope which references a scope... def build_default_scope #:nodoc: - return if defined?(@ignore_default_scope) && @ignore_default_scope - @ignore_default_scope = true + return if ignore_default_scope? - if method(:default_scope).owner != Base.singleton_class - default_scope - elsif default_scopes.any? - default_scopes.inject(relation) do |default_scope, scope| - if scope.is_a?(Hash) - default_scope.apply_finder_options(scope) - elsif !scope.is_a?(Relation) && scope.respond_to?(:call) - default_scope.merge(scope.call) - else - default_scope.merge(scope) + begin + self.ignore_default_scope = true + + if method(:default_scope).owner != Base.singleton_class + default_scope + elsif default_scopes.any? + default_scopes.inject(relation) do |default_scope, scope| + if scope.is_a?(Hash) + default_scope.apply_finder_options(scope) + elsif !scope.is_a?(Relation) && scope.respond_to?(:call) + default_scope.merge(scope.call) + else + default_scope.merge(scope) + end end end + ensure + self.ignore_default_scope = false end - ensure - @ignore_default_scope = false end # Returns the class type of the record using the current module as a prefix. So descendants of diff --git a/activerecord/test/cases/relation_scoping_test.rb b/activerecord/test/cases/relation_scoping_test.rb index 673aff403f..1e2093273e 100644 --- a/activerecord/test/cases/relation_scoping_test.rb +++ b/activerecord/test/cases/relation_scoping_test.rb @@ -524,4 +524,22 @@ class DefaultScopingTest < ActiveRecord::TestCase assert_equal 1, DeveloperWithIncludes.where(:audit_logs => { :message => 'foo' }).count end + + def test_default_scope_is_threadsafe + if in_memory_db? + skip "in memory db can't share a db between threads" + end + + threads = [] + assert_not_equal 1, ThreadsafeDeveloper.unscoped.count + + threads << Thread.new do + Thread.current[:long_default_scope] = true + assert_equal 1, ThreadsafeDeveloper.all.count + end + threads << Thread.new do + assert_equal 1, ThreadsafeDeveloper.all.count + end + threads.each(&:join) + end end diff --git a/activerecord/test/models/developer.rb b/activerecord/test/models/developer.rb index f182a7fa97..4dc9fff9fd 100644 --- a/activerecord/test/models/developer.rb +++ b/activerecord/test/models/developer.rb @@ -227,3 +227,12 @@ class EagerDeveloperWithCallableDefaultScope < ActiveRecord::Base default_scope OpenStruct.new(:call => includes(:projects)) end + +class ThreadsafeDeveloper < ActiveRecord::Base + self.table_name = 'developers' + + def self.default_scope + sleep 0.05 if Thread.current[:long_default_scope] + limit(1) + end +end From 9ecc4433bbda255cbcb4a2be442c8ee985692d06 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Sat, 13 Aug 2011 16:50:03 +0100 Subject: [PATCH 193/345] Perf: don't mess around with thread local vars unless we actually need to --- activerecord/lib/active_record/base.rb | 41 +++++++++++++++----------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 5a57e1bc70..0c5248c576 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1206,14 +1206,6 @@ MSG Thread.current["#{self}_current_scope"] = scope end - def ignore_default_scope? #:nodoc: - Thread.current["#{self}_ignore_default_scope"] - end - - def ignore_default_scope=(ignore) #:nodoc: - Thread.current["#{self}_ignore_default_scope"] = ignore - end - # Use this macro in your model to set a default scope for all operations on # the model. # @@ -1264,17 +1256,11 @@ MSG self.default_scopes = default_scopes + [scope] end - # The @ignore_default_scope flag is used to prevent an infinite recursion situation where - # a default scope references a scope which has a default scope which references a scope... def build_default_scope #:nodoc: - return if ignore_default_scope? - - begin - self.ignore_default_scope = true - - if method(:default_scope).owner != Base.singleton_class - default_scope - elsif default_scopes.any? + if method(:default_scope).owner != Base.singleton_class + evaluate_default_scope { default_scope } + elsif default_scopes.any? + evaluate_default_scope do default_scopes.inject(relation) do |default_scope, scope| if scope.is_a?(Hash) default_scope.apply_finder_options(scope) @@ -1285,6 +1271,25 @@ MSG end end end + end + end + + def ignore_default_scope? #:nodoc: + Thread.current["#{self}_ignore_default_scope"] + end + + def ignore_default_scope=(ignore) #:nodoc: + Thread.current["#{self}_ignore_default_scope"] = ignore + end + + # The ignore_default_scope flag is used to prevent an infinite recursion situation where + # a default scope references a scope which has a default scope which references a scope... + def evaluate_default_scope + return if ignore_default_scope? + + begin + self.ignore_default_scope = true + yield ensure self.ignore_default_scope = false end From c3bd6bb75fdbeb8f5d92b12ed2a9f5d4958d2f9c Mon Sep 17 00:00:00 2001 From: Vijay Dev Date: Sat, 13 Aug 2011 22:14:18 +0530 Subject: [PATCH 194/345] Fixes readme links better - earlier links broke when the current page is anything other than github.com/rails/rails/. Even github.com/rails/rails (without the trailing slash) broke the readme links. Also change the rakefile that generates the rdoc readme accordingly --- README.rdoc | 4 ++-- Rakefile | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.rdoc b/README.rdoc index 5d1e3f5c5d..1e78799e83 100644 --- a/README.rdoc +++ b/README.rdoc @@ -18,7 +18,7 @@ you to present the data from database rows as objects and embellish these data o with business logic methods. Although most Rails models are backed by a database, models can also be ordinary Ruby classes, or Ruby classes that implement a set of interfaces as provided by the ActiveModel module. You can read more about Active Record in its -{README}[link:blob/master/activerecord/README.rdoc]. +{README}[link:/rails/rails/blob/master/activerecord/README.rdoc]. The Controller layer is responsible for handling incoming HTTP requests and providing a suitable response. Usually this means returning HTML, but Rails controllers can also @@ -29,7 +29,7 @@ In Rails, the Controller and View layers are handled together by Action Pack. These two layers are bundled in a single package due to their heavy interdependence. This is unlike the relationship between Active Record and Action Pack which are independent. Each of these packages can be used independently outside of Rails. You -can read more about Action Pack in its {README}[link:blob/master/actionpack/README.rdoc]. +can read more about Action Pack in its {README}[link:/rails/rails/blob/master/actionpack/README.rdoc]. == Getting Started diff --git a/Rakefile b/Rakefile index d18dac0dbd..36007f6e91 100755 --- a/Rakefile +++ b/Rakefile @@ -74,7 +74,7 @@ RDoc::Task.new do |rdoc| # since no autolinking happens there and RDoc displays the backslash # otherwise. rdoc_main.gsub!(/^(?=\S).*?\b(?=Rails)\b/) { "#$&\\" } - rdoc_main.gsub!(%r{link:blob/master/(\w+)/README\.rdoc}, "link:files/\\1/README_rdoc.html") + rdoc_main.gsub!(%r{link:/rails/rails/blob/master/(\w+)/README\.rdoc}, "link:files/\\1/README_rdoc.html") File.open(RDOC_MAIN, 'w') do |f| f.write(rdoc_main) From 4bb7abcb7715c06ff816243c61d75b14afc117e0 Mon Sep 17 00:00:00 2001 From: "Jonathon M. Abbott" Date: Wed, 27 Jul 2011 17:35:35 +1000 Subject: [PATCH 195/345] Use mysql_creation_options inside rescue block Commit ecd37084b28a05f05251 did not take into account the use of creation_options inside the access denied exception handler. --- activerecord/lib/active_record/railties/databases.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index ec00f7faad..13c41350fb 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -94,7 +94,7 @@ db_namespace = namespace :db do "IDENTIFIED BY '#{config['password']}' WITH GRANT OPTION;" ActiveRecord::Base.establish_connection(config.merge( 'database' => nil, 'username' => 'root', 'password' => root_password)) - ActiveRecord::Base.connection.create_database(config['database'], creation_options) + ActiveRecord::Base.connection.create_database(config['database'], mysql_creation_options(config)) ActiveRecord::Base.connection.execute grant_statement ActiveRecord::Base.establish_connection(config) else From 75dd33a0aed96d9f03b79c82f7e5bc5ccf462e8e Mon Sep 17 00:00:00 2001 From: Franck Verrot Date: Sun, 14 Aug 2011 18:58:29 +0200 Subject: [PATCH 196/345] Methods like status and location are interfering with redirect_to [Closes #2511] --- actionpack/lib/action_controller/metal/instrumentation.rb | 6 +++--- actionpack/test/controller/redirect_test.rb | 5 +++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/actionpack/lib/action_controller/metal/instrumentation.rb b/actionpack/lib/action_controller/metal/instrumentation.rb index 85d0f5f699..777a0ab343 100644 --- a/actionpack/lib/action_controller/metal/instrumentation.rb +++ b/actionpack/lib/action_controller/metal/instrumentation.rb @@ -58,8 +58,8 @@ module ActionController def redirect_to(*args) ActiveSupport::Notifications.instrument("redirect_to.action_controller") do |payload| result = super - payload[:status] = self.status - payload[:location] = self.location + payload[:status] = response.status + payload[:location] = response.location result end end @@ -97,4 +97,4 @@ module ActionController end end end -end \ No newline at end of file +end diff --git a/actionpack/test/controller/redirect_test.rb b/actionpack/test/controller/redirect_test.rb index 92d4a6d98b..79041055bd 100644 --- a/actionpack/test/controller/redirect_test.rb +++ b/actionpack/test/controller/redirect_test.rb @@ -4,6 +4,11 @@ class WorkshopsController < ActionController::Base end class RedirectController < ActionController::Base + # empty method not used anywhere to ensure methods like + # `status` and `location` aren't called on `redirect_to` calls + def status; render :text => 'called status'; end + def location; render :text => 'called location'; end + def simple_redirect redirect_to :action => "hello_world" end From 652ab436db674a112bcbc72d8c73e21f2ced512a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sun, 14 Aug 2011 10:52:46 -0700 Subject: [PATCH 197/345] Ensure changing RAILS_GROUPS will load the proper dependencies. --- actionpack/lib/sprockets/assets.rake | 29 +++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/actionpack/lib/sprockets/assets.rake b/actionpack/lib/sprockets/assets.rake index 01132d218f..50af88c44f 100644 --- a/actionpack/lib/sprockets/assets.rake +++ b/actionpack/lib/sprockets/assets.rake @@ -1,18 +1,21 @@ namespace :assets do - task :ensure_env do - ENV["RAILS_GROUPS"] ||= "assets" - ENV["RAILS_ENV"] ||= "production" - end - desc "Compile all the assets named in config.assets.precompile" - task :precompile => :ensure_env do - Rake::Task["environment"].invoke - Sprockets::Helpers::RailsHelper + task :precompile do + # We need to do this dance because RAILS_GROUPS is used + # too early in the boot process and changing here is already too late. + if ENV["RAILS_GROUPS"].to_s.empty? + ENV["RAILS_GROUPS"] = "assets" + ENV["RAILS_ENV"] ||= "production" + Kernel.exec $0, *ARGV + else + Rake::Task["environment"].invoke + Sprockets::Helpers::RailsHelper - assets = Rails.application.config.assets.precompile - # Always perform caching so that asset_path appends the timestamps to file references. - Rails.application.config.action_controller.perform_caching = true - Rails.application.assets.precompile(*assets) + assets = Rails.application.config.assets.precompile + # Always perform caching so that asset_path appends the timestamps to file references. + Rails.application.config.action_controller.perform_caching = true + Rails.application.assets.precompile(*assets) + end end desc "Remove compiled assets" @@ -21,4 +24,4 @@ namespace :assets do public_asset_path = Rails.public_path + assets.prefix rm_rf public_asset_path, :secure => true end -end +end \ No newline at end of file From 6f4b405250157c76fea86c42c8b0854ca4a3c4b8 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Mon, 18 Jul 2011 15:50:02 +0100 Subject: [PATCH 198/345] Backport Object#public_send to 1.8 so that we can implement Module#delegate such that non-public methods raise --- .../lib/active_support/core_ext/object.rb | 1 + .../core_ext/object/public_send.rb | 25 ++++ .../test/core_ext/object/public_send_test.rb | 117 ++++++++++++++++++ 3 files changed, 143 insertions(+) create mode 100644 activesupport/lib/active_support/core_ext/object/public_send.rb create mode 100644 activesupport/test/core_ext/object/public_send_test.rb diff --git a/activesupport/lib/active_support/core_ext/object.rb b/activesupport/lib/active_support/core_ext/object.rb index 9ad1e12699..249c2e93c5 100644 --- a/activesupport/lib/active_support/core_ext/object.rb +++ b/activesupport/lib/active_support/core_ext/object.rb @@ -3,6 +3,7 @@ require 'active_support/core_ext/object/blank' require 'active_support/core_ext/object/duplicable' require 'active_support/core_ext/object/try' require 'active_support/core_ext/object/inclusion' +require 'active_support/core_ext/object/public_send' require 'active_support/core_ext/object/conversions' require 'active_support/core_ext/object/instance_variables' diff --git a/activesupport/lib/active_support/core_ext/object/public_send.rb b/activesupport/lib/active_support/core_ext/object/public_send.rb new file mode 100644 index 0000000000..233e69b4f8 --- /dev/null +++ b/activesupport/lib/active_support/core_ext/object/public_send.rb @@ -0,0 +1,25 @@ +require 'active_support/core_ext/kernel/singleton_class' + +class Object + unless Object.public_method_defined?(:public_send) + # Backports Object#public_send from 1.9 + def public_send(method, *args, &block) # :nodoc: + # Don't create a singleton class for the object if it doesn't already have one + # (This also protects us from classes like Fixnum and Symbol, which cannot have a + # singleton class.) + klass = singleton_methods.any? ? self.singleton_class : self.class + + if klass.public_method_defined?(method) + send(method, *args, &block) + else + if klass.private_method_defined?(method) + raise NoMethodError, "private method `#{method}' called for #{inspect}" + elsif klass.protected_method_defined?(method) + raise NoMethodError, "protected method `#{method}' called for #{inspect}" + else + raise NoMethodError, "undefined method `#{method}' for #{inspect}" + end + end + end + end +end diff --git a/activesupport/test/core_ext/object/public_send_test.rb b/activesupport/test/core_ext/object/public_send_test.rb new file mode 100644 index 0000000000..7dc542e51c --- /dev/null +++ b/activesupport/test/core_ext/object/public_send_test.rb @@ -0,0 +1,117 @@ +require 'abstract_unit' +require 'active_support/core_ext/object/public_send' + +module PublicSendReceiver + def receive_public_method(*args) + return args + [yield] + end + + protected + + def receive_protected_method(*args) + return args + [yield] + end + + private + + def receive_private_method(*args) + return args + [yield] + end +end + +# Note, running this on 1.9 will be testing the Ruby core implementation, but it is good to +# do this to ensure that our backport functions the same as Ruby core in 1.9 +class PublicSendTest < Test::Unit::TestCase + def instance + @instance ||= begin + klass = Class.new do + include PublicSendReceiver + end + klass.new + end + end + + def singleton_instance + @singleton_instance ||= begin + object = Object.new + object.singleton_class.send(:include, PublicSendReceiver) + object + end + end + + def test_should_receive_public_method + assert_equal( + [:foo, :bar, :baz], + instance.public_send(:receive_public_method, :foo, :bar) { :baz } + ) + end + + def test_should_receive_public_singleton_method + assert_equal( + [:foo, :bar, :baz], + singleton_instance.public_send(:receive_public_method, :foo, :bar) { :baz } + ) + end + + def test_should_raise_on_protected_method + assert_raises(NoMethodError) do + instance.public_send(:receive_protected_method, :foo, :bar) { :baz } + end + end + + def test_should_raise_on_protected_singleton_method + assert_raises(NoMethodError) do + singleton_instance.public_send(:receive_protected_method, :foo, :bar) { :baz } + end + end + + def test_should_raise_on_private_method + assert_raises(NoMethodError) do + instance.public_send(:receive_private_method, :foo, :bar) { :baz } + end + end + + def test_should_raise_on_singleton_private_method + assert_raises(NoMethodError) do + singleton_instance.public_send(:receive_private_method, :foo, :bar) { :baz } + end + end + + def test_should_raise_on_undefined_method + assert_raises(NoMethodError) do + instance.public_send(:receive_undefined_method, :foo, :bar) { :baz } + end + end + + def test_protected_method_message + instance.public_send(:receive_protected_method, :foo, :bar) { :baz } + rescue NoMethodError => exception + assert_equal( + "protected method `receive_protected_method' called for #{instance.inspect}", + exception.message + ) + end + + def test_private_method_message + instance.public_send(:receive_private_method, :foo, :bar) { :baz } + rescue NoMethodError => exception + assert_equal( + "private method `receive_private_method' called for #{instance.inspect}", + exception.message + ) + end + + def test_undefined_method_message + instance.public_send(:receive_undefined_method, :foo, :bar) { :baz } + rescue NoMethodError => exception + assert_equal( + "undefined method `receive_undefined_method' for #{instance.inspect}", + exception.message + ) + end + + def test_receiver_with_no_singleton + assert_equal "5", 5.public_send(:to_s) + assert_equal "foo", :foo.public_send(:to_s) + end +end From 8bba95f293714283f6fc30cb213af54811cccff3 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Mon, 18 Jul 2011 16:06:21 +0100 Subject: [PATCH 199/345] Just do the method call directly in Module#delegate, if we can (we cannot for method names ending in '='). Two reasons: 1) it's faster, see https://gist.github.com/1089783 and 2) more importantly, delegate should not allow you to accidentally call private or protected methods. --- activesupport/CHANGELOG | 4 +++- .../core_ext/module/delegation.rb | 5 ++++- activesupport/test/core_ext/module_test.rb | 22 +++++++++++++++++-- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG index a25720adbf..2129e8b179 100644 --- a/activesupport/CHANGELOG +++ b/activesupport/CHANGELOG @@ -1,11 +1,13 @@ *Rails 3.2.0 (unreleased)* +* Removed support for using Module#delegate to delegate to non-public methods [Jon Leighton] + * The definition of blank string for Ruby 1.9 has been extended to Unicode whitespace. Also, in 1.8 the ideographic space U+3000 is considered to be whitespace. [Akira Matsuda, Damien Mathieu] * The inflector understands acronyms. [dlee] -* Deprecated ActiveSupport::Memoizable in favor of Ruby memoization pattern [José Valim] +* Deprecated ActiveSupport::Memoizable in favor of Ruby memoization pattern [José Valim] * Added Time#all_day/week/quarter/year as a way of generating ranges (example: Event.where(created_at: Time.now.all_week)) [DHH] diff --git a/activesupport/lib/active_support/core_ext/module/delegation.rb b/activesupport/lib/active_support/core_ext/module/delegation.rb index bf7e009290..8655288bc3 100644 --- a/activesupport/lib/active_support/core_ext/module/delegation.rb +++ b/activesupport/lib/active_support/core_ext/module/delegation.rb @@ -123,6 +123,9 @@ class Module line = line.to_i methods.each do |method| + method = method.to_s + call = (method[-1..-1] == '=') ? "public_send(:#{method}, " : "#{method}(" + on_nil = if allow_nil 'return' @@ -132,7 +135,7 @@ class Module module_eval(<<-EOS, file, line - 5) def #{method_prefix}#{method}(*args, &block) # def customer_name(*args, &block) - #{to}.__send__(#{method.inspect}, *args, &block) # client.__send__(:name, *args, &block) + #{to}.#{call}*args, &block) # client.name(*args, &block) rescue NoMethodError # rescue NoMethodError if #{to}.nil? # if client.nil? #{on_nil} # return # depends on :allow_nil diff --git a/activesupport/test/core_ext/module_test.rb b/activesupport/test/core_ext/module_test.rb index a95cf1591f..074a3412d4 100644 --- a/activesupport/test/core_ext/module_test.rb +++ b/activesupport/test/core_ext/module_test.rb @@ -26,10 +26,20 @@ module Yz end end -Somewhere = Struct.new(:street, :city) +Somewhere = Struct.new(:street, :city) do + protected + + def protected_method + end + + private + + def private_method + end +end Someone = Struct.new(:name, :place) do - delegate :street, :city, :to_f, :to => :place + delegate :street, :city, :to_f, :protected_method, :private_method, :to => :place delegate :upcase, :to => "place.city" end @@ -69,6 +79,14 @@ class ModuleTest < Test::Unit::TestCase assert_equal "Chicago", @david.city end + def test_delegation_to_protected_method + assert_raise(NoMethodError) { @david.protected_method } + end + + def test_delegation_to_private_method + assert_raise(NoMethodError) { @david.private_method } + end + def test_delegation_down_hierarchy assert_equal "CHICAGO", @david.upcase end From 7b56fb034a2f9a03ccbdc485287946b49e5e9b68 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Mon, 18 Jul 2011 16:35:21 +0100 Subject: [PATCH 200/345] Fix private methods which are delegated to. This previously worked because Module#delegate previously ignored method visibility. --- .../active_record/associations/association.rb | 16 ++++++++-------- .../belongs_to_polymorphic_association.rb | 10 +++++----- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/activerecord/lib/active_record/associations/association.rb b/activerecord/lib/active_record/associations/association.rb index bb519c5703..d1e3ff8e38 100644 --- a/activerecord/lib/active_record/associations/association.rb +++ b/activerecord/lib/active_record/associations/association.rb @@ -151,20 +151,20 @@ module ActiveRecord reset end + def interpolate(sql, record = nil) + if sql.respond_to?(:to_proc) + owner.send(:instance_exec, record, &sql) + else + sql + end + end + private def find_target? !loaded? && (!owner.new_record? || foreign_key_present?) && klass end - def interpolate(sql, record = nil) - if sql.respond_to?(:to_proc) - owner.send(:instance_exec, record, &sql) - else - sql - end - end - def creation_attributes attributes = {} diff --git a/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb b/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb index 198ad06360..2ee5dbbd70 100644 --- a/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb +++ b/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb @@ -2,6 +2,11 @@ module ActiveRecord # = Active Record Belongs To Polymorphic Association module Associations class BelongsToPolymorphicAssociation < BelongsToAssociation #:nodoc: + def klass + type = owner[reflection.foreign_type] + type.presence && type.constantize + end + private def replace_keys(record) @@ -17,11 +22,6 @@ module ActiveRecord reflection.polymorphic_inverse_of(record.class) end - def klass - type = owner[reflection.foreign_type] - type.presence && type.constantize - end - def raise_on_type_mismatch(record) # A polymorphic association cannot have a type mismatch, by definition end From 63d100ea35a7fabea25c37f654177c3828fc1dcb Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Mon, 15 Aug 2011 12:50:57 +0100 Subject: [PATCH 201/345] Fix the line number in the backtrace when Module#delegate raises --- .../active_support/core_ext/module/delegation.rb | 2 +- activesupport/test/core_ext/module_test.rb | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/activesupport/lib/active_support/core_ext/module/delegation.rb b/activesupport/lib/active_support/core_ext/module/delegation.rb index 8655288bc3..654e3a01c6 100644 --- a/activesupport/lib/active_support/core_ext/module/delegation.rb +++ b/activesupport/lib/active_support/core_ext/module/delegation.rb @@ -133,7 +133,7 @@ class Module %(raise "#{self}##{method_prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}") end - module_eval(<<-EOS, file, line - 5) + module_eval(<<-EOS, file, line - 1) def #{method_prefix}#{method}(*args, &block) # def customer_name(*args, &block) #{to}.#{call}*args, &block) # client.name(*args, &block) rescue NoMethodError # rescue NoMethodError diff --git a/activesupport/test/core_ext/module_test.rb b/activesupport/test/core_ext/module_test.rb index 074a3412d4..c33ade8381 100644 --- a/activesupport/test/core_ext/module_test.rb +++ b/activesupport/test/core_ext/module_test.rb @@ -38,9 +38,12 @@ Somewhere = Struct.new(:street, :city) do end end -Someone = Struct.new(:name, :place) do +class Someone < Struct.new(:name, :place) delegate :street, :city, :to_f, :protected_method, :private_method, :to => :place delegate :upcase, :to => "place.city" + + FAILED_DELEGATE_LINE = __LINE__ + 1 + delegate :foo, :to => :place end Invoice = Struct.new(:client) do @@ -182,6 +185,15 @@ class ModuleTest < Test::Unit::TestCase end end + def test_delegation_exception_backtrace + someone = Someone.new("foo", "bar") + someone.foo + rescue NoMethodError => e + file_and_line = "#{__FILE__}:#{Someone::FAILED_DELEGATE_LINE}" + assert e.backtrace.first.include?(file_and_line), + "[#{e.backtrace.first}] did not include [#{file_and_line}]" + end + def test_parent assert_equal Yz::Zy, Yz::Zy::Cd.parent assert_equal Yz, Yz::Zy.parent From 27da0c5480ecf6b020e73f994d3240ae15b0646b Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Mon, 15 Aug 2011 13:56:04 +0100 Subject: [PATCH 202/345] Split up the definitions in Module#delegate depending on :allow_nil, and don't use exceptions for flow control in the :allow_nil => true case. --- .../core_ext/module/delegation.rb | 39 +++++++++++-------- activesupport/test/core_ext/module_test.rb | 12 ++++++ 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/activesupport/lib/active_support/core_ext/module/delegation.rb b/activesupport/lib/active_support/core_ext/module/delegation.rb index 654e3a01c6..fe17359a24 100644 --- a/activesupport/lib/active_support/core_ext/module/delegation.rb +++ b/activesupport/lib/active_support/core_ext/module/delegation.rb @@ -126,24 +126,29 @@ class Module method = method.to_s call = (method[-1..-1] == '=') ? "public_send(:#{method}, " : "#{method}(" - on_nil = - if allow_nil - 'return' - else - %(raise "#{self}##{method_prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}") - end + if allow_nil + module_eval(<<-EOS, file, line - 2) + def #{method_prefix}#{method}(*args, &block) # def customer_name(*args, &block) + if #{to} || #{to}.respond_to?(:#{method}) # if client || client.respond_to?(:name) + #{to}.#{call}*args, &block) # client.name(*args, &block) + end # end + end # end + EOS + else + exception = %(raise "#{self}##{method_prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}") - module_eval(<<-EOS, file, line - 1) - def #{method_prefix}#{method}(*args, &block) # def customer_name(*args, &block) - #{to}.#{call}*args, &block) # client.name(*args, &block) - rescue NoMethodError # rescue NoMethodError - if #{to}.nil? # if client.nil? - #{on_nil} # return # depends on :allow_nil - else # else - raise # raise - end # end - end # end - EOS + module_eval(<<-EOS, file, line - 1) + def #{method_prefix}#{method}(*args, &block) # def customer_name(*args, &block) + #{to}.#{call}*args, &block) # client.name(*args, &block) + rescue NoMethodError # rescue NoMethodError + if #{to}.nil? # if client.nil? + #{exception} # # add helpful message to the exception + else # else + raise # raise + end # end + end # end + EOS + end end end end diff --git a/activesupport/test/core_ext/module_test.rb b/activesupport/test/core_ext/module_test.rb index c33ade8381..a24f013d4f 100644 --- a/activesupport/test/core_ext/module_test.rb +++ b/activesupport/test/core_ext/module_test.rb @@ -44,6 +44,9 @@ class Someone < Struct.new(:name, :place) FAILED_DELEGATE_LINE = __LINE__ + 1 delegate :foo, :to => :place + + FAILED_DELEGATE_LINE_2 = __LINE__ + 1 + delegate :bar, :to => :place, :allow_nil => true end Invoice = Struct.new(:client) do @@ -194,6 +197,15 @@ class ModuleTest < Test::Unit::TestCase "[#{e.backtrace.first}] did not include [#{file_and_line}]" end + def test_delegation_exception_backtrace_with_allow_nil + someone = Someone.new("foo", "bar") + someone.bar + rescue NoMethodError => e + file_and_line = "#{__FILE__}:#{Someone::FAILED_DELEGATE_LINE_2}" + assert e.backtrace.first.include?(file_and_line), + "[#{e.backtrace.first}] did not include [#{file_and_line}]" + end + def test_parent assert_equal Yz::Zy, Yz::Zy::Cd.parent assert_equal Yz, Yz::Zy.parent From 10b99f2826c6baab0db9c9c57ddf600fe78356e5 Mon Sep 17 00:00:00 2001 From: Arun Agrawal Date: Mon, 15 Aug 2011 19:13:25 +0530 Subject: [PATCH 203/345] Need to include public_send --- activesupport/lib/active_support/core_ext/module/delegation.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/activesupport/lib/active_support/core_ext/module/delegation.rb b/activesupport/lib/active_support/core_ext/module/delegation.rb index fe17359a24..72988fa6b5 100644 --- a/activesupport/lib/active_support/core_ext/module/delegation.rb +++ b/activesupport/lib/active_support/core_ext/module/delegation.rb @@ -1,3 +1,4 @@ +require 'active_support/core_ext/object/public_send' class Module # Provides a delegate class method to easily expose contained objects' methods # as your own. Pass one or more methods (specified as symbols or strings) From 57423d815b3747aa382cd3859a15bffa538525ad Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Mon, 15 Aug 2011 16:00:35 +0100 Subject: [PATCH 204/345] Ensure empty has_many :through association preloaded via joins is marked as loaded. Fixes #2054. --- .../lib/active_record/associations/join_dependency.rb | 5 ++--- .../associations/has_many_through_associations_test.rb | 8 ++++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/activerecord/lib/active_record/associations/join_dependency.rb b/activerecord/lib/active_record/associations/join_dependency.rb index 504f25271c..6c878f0f00 100644 --- a/activerecord/lib/active_record/associations/join_dependency.rb +++ b/activerecord/lib/active_record/associations/join_dependency.rb @@ -188,13 +188,12 @@ module ActiveRecord association = join_part.instantiate(row) unless row[join_part.aliased_primary_key].nil? set_target_and_inverse(join_part, association, record) else - return if row[join_part.aliased_primary_key].nil? - association = join_part.instantiate(row) + association = join_part.instantiate(row) unless row[join_part.aliased_primary_key].nil? case macro when :has_many, :has_and_belongs_to_many other = record.association(join_part.reflection.name) other.loaded! - other.target.push(association) + other.target.push(association) if association other.set_inverse_instance(association) when :belongs_to set_target_and_inverse(join_part, association, record) diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb index 0b1ba31ac2..5f2328ff95 100644 --- a/activerecord/test/cases/associations/has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb @@ -813,4 +813,12 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase assert !c.save end end + + def test_preloading_empty_through_association_via_joins + person = Person.create!(:first_name => "Gaga") + person = Person.where(:id => person.id).where('readers.id = 1 or 1=1').includes(:posts).to_a.first + + assert person.posts.loaded?, 'person.posts should be loaded' + assert_equal [], person.posts + end end From 2e2f3f5a469cb441e52fb161647ea5fd27d98d81 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Mon, 15 Aug 2011 16:07:49 +0100 Subject: [PATCH 205/345] Add a test for delegating a method ending in '=' as this is a special case. --- .../lib/active_support/core_ext/module/delegation.rb | 1 + activesupport/test/core_ext/module_test.rb | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/activesupport/lib/active_support/core_ext/module/delegation.rb b/activesupport/lib/active_support/core_ext/module/delegation.rb index 72988fa6b5..4a899a7d84 100644 --- a/activesupport/lib/active_support/core_ext/module/delegation.rb +++ b/activesupport/lib/active_support/core_ext/module/delegation.rb @@ -1,4 +1,5 @@ require 'active_support/core_ext/object/public_send' + class Module # Provides a delegate class method to easily expose contained objects' methods # as your own. Pass one or more methods (specified as symbols or strings) diff --git a/activesupport/test/core_ext/module_test.rb b/activesupport/test/core_ext/module_test.rb index a24f013d4f..d4ce81fdfa 100644 --- a/activesupport/test/core_ext/module_test.rb +++ b/activesupport/test/core_ext/module_test.rb @@ -27,6 +27,8 @@ module Yz end Somewhere = Struct.new(:street, :city) do + attr_accessor :name + protected def protected_method @@ -40,6 +42,7 @@ end class Someone < Struct.new(:name, :place) delegate :street, :city, :to_f, :protected_method, :private_method, :to => :place + delegate :name=, :to => :place, :prefix => true delegate :upcase, :to => "place.city" FAILED_DELEGATE_LINE = __LINE__ + 1 @@ -85,6 +88,11 @@ class ModuleTest < Test::Unit::TestCase assert_equal "Chicago", @david.city end + def test_delegation_to_assignment_method + @david.place_name = "Fred" + assert_equal "Fred", @david.place.name + end + def test_delegation_to_protected_method assert_raise(NoMethodError) { @david.protected_method } end From c80876f77880a97f94d2255ff9405bb080a6faa4 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Mon, 15 Aug 2011 16:26:37 +0100 Subject: [PATCH 206/345] Document Object#public_send --- .../core_ext/object/public_send.rb | 2 +- .../active_support_core_extensions.textile | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/activesupport/lib/active_support/core_ext/object/public_send.rb b/activesupport/lib/active_support/core_ext/object/public_send.rb index 233e69b4f8..2e77a22c4b 100644 --- a/activesupport/lib/active_support/core_ext/object/public_send.rb +++ b/activesupport/lib/active_support/core_ext/object/public_send.rb @@ -3,7 +3,7 @@ require 'active_support/core_ext/kernel/singleton_class' class Object unless Object.public_method_defined?(:public_send) # Backports Object#public_send from 1.9 - def public_send(method, *args, &block) # :nodoc: + def public_send(method, *args, &block) # Don't create a singleton class for the object if it doesn't already have one # (This also protects us from classes like Fixnum and Symbol, which cannot have a # singleton class.) diff --git a/railties/guides/source/active_support_core_extensions.textile b/railties/guides/source/active_support_core_extensions.textile index 781d3d08cd..8716e94bd9 100644 --- a/railties/guides/source/active_support_core_extensions.textile +++ b/railties/guides/source/active_support_core_extensions.textile @@ -452,6 +452,30 @@ Examples of +in?+: NOTE: Defined in +active_support/core_ext/object/inclusion.rb+. +h4. +public_send+ + +This method is available by default in Ruby 1.9, and is backported to Ruby 1.8 by Active Support. Like the regular +send+ method, +public_send+ allows you to call a method when the name is not known until runtime. However, if the method is not public then a +NoMethodError+ exception will be raised. + + +class Greeter + def hello(who) + "Hello " + who + end + + private + + def secret + "sauce" + end +end + +greeter = Greeter.new +greeter.public_send(:hello, 'Jim') # => "Hello Jim" +greeter.public_send(:secret) # => NoMethodError + + +NOTE: Defined in +active_support/core_ext/object/public_send.rb+. + h3. Extensions to +Module+ h4. +alias_method_chain+ From 45ccd648664d894ee2a6a8812193ae47a4db6418 Mon Sep 17 00:00:00 2001 From: Arun Agrawal Date: Mon, 15 Aug 2011 21:49:12 +0530 Subject: [PATCH 207/345] Unused variable removed. --- actionpack/test/template/form_tag_helper_test.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/actionpack/test/template/form_tag_helper_test.rb b/actionpack/test/template/form_tag_helper_test.rb index ad31812273..eb569c7308 100644 --- a/actionpack/test/template/form_tag_helper_test.rb +++ b/actionpack/test/template/form_tag_helper_test.rb @@ -508,25 +508,25 @@ class FormTagHelperTest < ActionView::TestCase def test_text_area_tag_options_symbolize_keys_side_effects options = { :option => "random_option" } - actual = text_area_tag "body", "hello world", options + text_area_tag "body", "hello world", options assert_equal options, { :option => "random_option" } end def test_submit_tag_options_symbolize_keys_side_effects options = { :option => "random_option" } - actual = submit_tag "submit value", options + submit_tag "submit value", options assert_equal options, { :option => "random_option" } end def test_button_tag_options_symbolize_keys_side_effects options = { :option => "random_option" } - actual = button_tag "button value", options + button_tag "button value", options assert_equal options, { :option => "random_option" } end def test_image_submit_tag_options_symbolize_keys_side_effects options = { :option => "random_option" } - actual = image_submit_tag "submit source", options + image_submit_tag "submit source", options assert_equal options, { :option => "random_option" } end From ebb2e9423ffc11174398b962fa2f1a9d94626673 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Mon, 15 Aug 2011 17:23:15 +0100 Subject: [PATCH 208/345] Update travis config on @joshk's instructions --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 953df9e7e5..6130b69631 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,4 +12,5 @@ env: notifications: email: false irc: - - "irc.freenode.org#rails-contrib" \ No newline at end of file + - "irc.freenode.org#rails-contrib" +bundler_args: --path vendor/bundle From 4ca605b71b0482c34c735b63b94ed001786c7125 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Mon, 15 Aug 2011 15:31:47 -0300 Subject: [PATCH 209/345] rake assets:precompile executes in production environment as default if RAILS_ENV was not provided --- actionpack/lib/sprockets/assets.rake | 8 ++++---- railties/test/application/assets_test.rb | 26 +++++++++++++++++------- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/actionpack/lib/sprockets/assets.rake b/actionpack/lib/sprockets/assets.rake index 50af88c44f..9b2646b0a2 100644 --- a/actionpack/lib/sprockets/assets.rake +++ b/actionpack/lib/sprockets/assets.rake @@ -3,9 +3,9 @@ namespace :assets do task :precompile do # We need to do this dance because RAILS_GROUPS is used # too early in the boot process and changing here is already too late. - if ENV["RAILS_GROUPS"].to_s.empty? - ENV["RAILS_GROUPS"] = "assets" - ENV["RAILS_ENV"] ||= "production" + if ENV["RAILS_GROUPS"].to_s.empty? || ENV["RAILS_ENV"].to_s.empty? + ENV["RAILS_GROUPS"] ||= "assets" + ENV["RAILS_ENV"] ||= "production" Kernel.exec $0, *ARGV else Rake::Task["environment"].invoke @@ -24,4 +24,4 @@ namespace :assets do public_asset_path = Rails.public_path + assets.prefix rm_rf public_asset_path, :secure => true end -end \ No newline at end of file +end diff --git a/railties/test/application/assets_test.rb b/railties/test/application/assets_test.rb index 38dd3f5a3f..ccc03f8d9c 100644 --- a/railties/test/application/assets_test.rb +++ b/railties/test/application/assets_test.rb @@ -46,28 +46,40 @@ module ApplicationTests assert defined?(Uglifier) end - test "precompile creates the file and gives it the original asset's content" do + test "precompile creates the filem, gives it the original asset's content and run in production as default" do app_file "app/assets/javascripts/application.js", "alert();" app_file "app/assets/javascripts/foo/application.js", "alert();" + ENV["RAILS_ENV"] = nil capture(:stdout) do Dir.chdir(app_path){ `bundle exec rake assets:precompile` } end - files = Dir["#{app_path}/public/assets/application-*.js"] - files << Dir["#{app_path}/public/assets/foo/application-*.js"].first + files = Dir["#{app_path}/public/assets/application-b29a188b3d9c74ef7cbb7ddf9e99f953.js"] + files << Dir["#{app_path}/public/assets/foo/application-b29a188b3d9c74ef7cbb7ddf9e99f953.js"].first files.each do |file| assert_not_nil file, "Expected application.js asset to be generated, but none found" - assert_equal "alert();\n", File.read(file) + assert_equal "alert()", File.read(file) end end - test "precompile appends the md5 hash to files referenced with asset_path" do + test "precompile appends the md5 hash to files referenced with asset_path and run in the provided RAILS_ENV" do app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>" + # capture(:stdout) do + Dir.chdir(app_path){ `bundle exec rake assets:precompile RAILS_ENV=test` } + # end + file = Dir["#{app_path}/public/assets/application-4bd8b7059c5336ec7ad515c9dbd59974.css"].first + assert_match /\/assets\/rails-([0-z]+)\.png/, File.read(file) + end + + test "precompile appends the md5 hash to files referenced with asset_path and run in production as default even using RAILS_GROUPS=assets" do + app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>" + + ENV["RAILS_ENV"] = nil capture(:stdout) do - Dir.chdir(app_path){ `bundle exec rake assets:precompile` } + Dir.chdir(app_path){ `bundle exec rake assets:precompile RAILS_GROUPS=assets` } end - file = Dir["#{app_path}/public/assets/application-*.css"].first + file = Dir["#{app_path}/public/assets/application-8d301a938f1abfd789bbec87ed1ef770.css"].first assert_match /\/assets\/rails-([0-z]+)\.png/, File.read(file) end From fd29b4e47f498ac259c8d3c3fcfaa61c99f2972a Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Mon, 15 Aug 2011 15:35:47 -0300 Subject: [PATCH 210/345] Fix typo --- railties/test/application/assets_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/test/application/assets_test.rb b/railties/test/application/assets_test.rb index ccc03f8d9c..7e68de5674 100644 --- a/railties/test/application/assets_test.rb +++ b/railties/test/application/assets_test.rb @@ -46,7 +46,7 @@ module ApplicationTests assert defined?(Uglifier) end - test "precompile creates the filem, gives it the original asset's content and run in production as default" do + test "precompile creates the file, gives it the original asset's content and run in production as default" do app_file "app/assets/javascripts/application.js", "alert();" app_file "app/assets/javascripts/foo/application.js", "alert();" From b2469283a77133fc36382281eca7ea8d4d56c7ed Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Mon, 15 Aug 2011 14:06:42 +0100 Subject: [PATCH 211/345] Removing unnecessary require, solve 'circular require considered harmful' warning. --- activesupport/lib/active_support/notifications.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/activesupport/lib/active_support/notifications.rb b/activesupport/lib/active_support/notifications.rb index 77696eb1db..b5a70d5933 100644 --- a/activesupport/lib/active_support/notifications.rb +++ b/activesupport/lib/active_support/notifications.rb @@ -1,5 +1,3 @@ -require 'active_support/core_ext/module/delegation' - module ActiveSupport # Notifications provides an instrumentation API for Ruby. To instrument an # action in Ruby you just need to do: From 83eec4ca4c8312e27678c15f87ba2e17532f7f07 Mon Sep 17 00:00:00 2001 From: Arun Agrawal Date: Tue, 16 Aug 2011 01:36:21 +0530 Subject: [PATCH 212/345] Requiring delegate. --- activesupport/test/notifications_test.rb | 1 + railties/lib/rails/railtie.rb | 1 + 2 files changed, 2 insertions(+) diff --git a/activesupport/test/notifications_test.rb b/activesupport/test/notifications_test.rb index cc0dc564f7..884ee61547 100644 --- a/activesupport/test/notifications_test.rb +++ b/activesupport/test/notifications_test.rb @@ -1,4 +1,5 @@ require 'abstract_unit' +require 'active_support/core_ext/module/delegation' module Notifications class TestCase < ActiveSupport::TestCase diff --git a/railties/lib/rails/railtie.rb b/railties/lib/rails/railtie.rb index 8c88b25617..e8fb1f3d98 100644 --- a/railties/lib/rails/railtie.rb +++ b/railties/lib/rails/railtie.rb @@ -2,6 +2,7 @@ require 'rails/initializable' require 'rails/configuration' require 'active_support/inflector' require 'active_support/core_ext/module/introspection' +require 'active_support/core_ext/module/delegation' module Rails # Railtie is the core of the Rails framework and provides several hooks to extend From 9482554f31f3ac7f941e6239890c60fcc01975e1 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Mon, 15 Aug 2011 16:56:33 -0500 Subject: [PATCH 213/345] Added Array#prepend as an alias for Array#unshift and Array#append as an alias for Array#<< [DHH] --- activesupport/CHANGELOG | 2 ++ activesupport/lib/active_support/core_ext/array.rb | 1 + .../core_ext/array/prepend_and_append.rb | 7 +++++++ activesupport/test/core_ext/array_ext_test.rb | 10 ++++++++++ 4 files changed, 20 insertions(+) create mode 100644 activesupport/lib/active_support/core_ext/array/prepend_and_append.rb diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG index 2129e8b179..dba914da48 100644 --- a/activesupport/CHANGELOG +++ b/activesupport/CHANGELOG @@ -1,5 +1,7 @@ *Rails 3.2.0 (unreleased)* +* Added Array#prepend as an alias for Array#unshift and Array#append as an alias for Array#<< [DHH] + * Removed support for using Module#delegate to delegate to non-public methods [Jon Leighton] * The definition of blank string for Ruby 1.9 has been extended to Unicode whitespace. diff --git a/activesupport/lib/active_support/core_ext/array.rb b/activesupport/lib/active_support/core_ext/array.rb index 4688468a8f..268c9bed4c 100644 --- a/activesupport/lib/active_support/core_ext/array.rb +++ b/activesupport/lib/active_support/core_ext/array.rb @@ -5,3 +5,4 @@ require 'active_support/core_ext/array/conversions' require 'active_support/core_ext/array/extract_options' require 'active_support/core_ext/array/grouping' require 'active_support/core_ext/array/random_access' +require 'active_support/core_ext/array/prepend_and_append' diff --git a/activesupport/lib/active_support/core_ext/array/prepend_and_append.rb b/activesupport/lib/active_support/core_ext/array/prepend_and_append.rb new file mode 100644 index 0000000000..27718f19d4 --- /dev/null +++ b/activesupport/lib/active_support/core_ext/array/prepend_and_append.rb @@ -0,0 +1,7 @@ +class Array + # The human way of thinking about adding stuff to the end of a list is with append + alias_method :append, :<< + + # The human way of thinking about adding stuff to the beginning of a list is with prepend + alias_method :prepend, :unshift +end \ No newline at end of file diff --git a/activesupport/test/core_ext/array_ext_test.rb b/activesupport/test/core_ext/array_ext_test.rb index e532010b18..f035505a01 100644 --- a/activesupport/test/core_ext/array_ext_test.rb +++ b/activesupport/test/core_ext/array_ext_test.rb @@ -465,3 +465,13 @@ class ArrayWrapperTests < Test::Unit::TestCase assert_equal DoubtfulToAry.new.to_ary, Array.wrap(DoubtfulToAry.new) end end + +class ArrayPrependAppendTest < Test::Unit::TestCase + def test_append + assert_equal [1, 2], [1].append(2) + end + + def test_prepend + assert_equal [2, 1], [1].prepend(2) + end +end \ No newline at end of file From 128d006242dae07edc65ad03e0e045adac0bbbf3 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Tue, 9 Aug 2011 00:12:53 +0100 Subject: [PATCH 214/345] Support updates with joins. Fixes #522. --- .../abstract/database_statements.rb | 9 +++++++++ .../connection_adapters/mysql2_adapter.rb | 4 ++++ .../connection_adapters/mysql_adapter.rb | 4 ++++ activerecord/lib/active_record/relation.rb | 13 +++++++++---- activerecord/test/cases/relations_test.rb | 8 ++++++++ 5 files changed, 34 insertions(+), 4 deletions(-) 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 2ae655e68d..7543d35d3b 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -306,6 +306,15 @@ module ActiveRecord end end + # The default strategy for an UPDATE with joins is to use a subquery. This doesn't work + # on mysql (even when aliasing the tables), but mysql allows using JOIN directly in + # an UPDATE statement, so in the mysql adapters we redefine this to do that. + def join_to_update(update, select) #:nodoc: + subselect = select.clone + subselect.ast.cores.last.projections = [update.ast.key] + update.wheres = [update.ast.key.in(subselect)] + end + protected # Returns an array of record hashes with the column names as keys and # column values as values. diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb index 18fdfa29ec..c01a64e354 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb @@ -577,6 +577,10 @@ module ActiveRecord where_sql end + def join_to_update(update, select) #:nodoc: + update.table select.ast.cores.last.source + end + protected def quoted_columns_for_index(column_names, options = {}) length = options[:length] if options.is_a?(Hash) diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index 14b950dbb0..ea0970028c 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -491,6 +491,10 @@ module ActiveRecord execute("RELEASE SAVEPOINT #{current_savepoint_name}") end + def join_to_update(update, select) #:nodoc: + update.table select.ast.cores.last.source + end + # SCHEMA STATEMENTS ======================================== def structure_dump #:nodoc: diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index 7e59eb4584..565ece1930 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -217,13 +217,18 @@ module ActiveRecord where(conditions).apply_finder_options(options.slice(:limit, :order)).update_all(updates) else stmt = arel.compile_update(Arel.sql(@klass.send(:sanitize_sql_for_assignment, updates))) + stmt.key = table[primary_key] - if limit = arel.limit - stmt.take limit + if joins_values.any? + @klass.connection.join_to_update(stmt, arel) + else + if limit = arel.limit + stmt.take limit + end + + stmt.order(*arel.orders) end - stmt.order(*arel.orders) - stmt.key = table[primary_key] @klass.connection.update stmt, 'SQL', bind_values end end diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index 821da91f0a..7bd9c44651 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -965,4 +965,12 @@ class RelationTest < ActiveRecord::TestCase def test_ordering_with_extra_spaces assert_equal authors(:david), Author.order('id DESC , name DESC').last end + + def test_update_all_with_joins + comments = Comment.joins(:post).where('posts.id' => posts(:welcome).id) + count = comments.count + + assert_equal count, comments.update_all(:post_id => posts(:thinking).id) + assert_equal posts(:thinking), comments(:greetings).post + end end From 43b99f290a8070196919a68999db87873257b7b8 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Wed, 10 Aug 2011 00:03:49 +0100 Subject: [PATCH 215/345] Support for multi-table updates with limits, offsets and orders --- .../abstract/database_statements.rb | 3 ++ .../connection_adapters/mysql2_adapter.rb | 23 +++++++++++++- .../connection_adapters/mysql_adapter.rb | 23 +++++++++++++- activerecord/test/cases/relations_test.rb | 30 +++++++++++++++++++ 4 files changed, 77 insertions(+), 2 deletions(-) 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 7543d35d3b..83e64d3c43 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -312,6 +312,9 @@ module ActiveRecord def join_to_update(update, select) #:nodoc: subselect = select.clone subselect.ast.cores.last.projections = [update.ast.key] + + update.ast.limit = nil + update.ast.orders = [] update.wheres = [update.ast.key.in(subselect)] end diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb index c01a64e354..172d08b6f4 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb @@ -577,8 +577,29 @@ module ActiveRecord where_sql end + # In the simple case, MySQL allows us to place JOINs directly into the UPDATE + # query. However, this does not allow for LIMIT, OFFSET and ORDER. To support + # these, we must use a subquery. However, MySQL is too stupid to create a + # temporary table for this automatically, so we have to give it some prompting + # in the form of a subsubquery. Ugh! def join_to_update(update, select) #:nodoc: - update.table select.ast.cores.last.source + if select.limit || select.offset || select.orders.any? + subsubselect = select.ast.clone + subsubselect.cores.last.projections = [update.ast.key] + subsubselect = Arel::Nodes::TableAlias.new( + Arel::Nodes::Grouping.new(subsubselect), + '__active_record_temp' + ) + + subselect = Arel::SelectManager.new(select.engine, subsubselect) + subselect.project(Arel::Table.new('__active_record_temp')[update.ast.key.name]) + + update.ast.limit = nil + update.ast.orders = [] + update.wheres = [update.ast.key.in(subselect)] + else + update.table select.ast.cores.last.source + end end protected diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index ea0970028c..bd6cb2d3b8 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -491,8 +491,29 @@ module ActiveRecord execute("RELEASE SAVEPOINT #{current_savepoint_name}") end + # In the simple case, MySQL allows us to place JOINs directly into the UPDATE + # query. However, this does not allow for LIMIT, OFFSET and ORDER. To support + # these, we must use a subquery. However, MySQL is too stupid to create a + # temporary table for this automatically, so we have to give it some prompting + # in the form of a subsubquery. Ugh! def join_to_update(update, select) #:nodoc: - update.table select.ast.cores.last.source + if select.limit || select.offset || select.orders.any? + subsubselect = select.ast.clone + subsubselect.cores.last.projections = [update.ast.key] + subsubselect = Arel::Nodes::TableAlias.new( + Arel::Nodes::Grouping.new(subsubselect), + '__active_record_temp' + ) + + subselect = Arel::SelectManager.new(select.engine, subsubselect) + subselect.project(Arel::Table.new('__active_record_temp')[update.ast.key.name]) + + update.ast.limit = nil + update.ast.orders = [] + update.wheres = [update.ast.key.in(subselect)] + else + update.table select.ast.cores.last.source + end end # SCHEMA STATEMENTS ======================================== diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index 7bd9c44651..97abd67385 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -973,4 +973,34 @@ class RelationTest < ActiveRecord::TestCase assert_equal count, comments.update_all(:post_id => posts(:thinking).id) assert_equal posts(:thinking), comments(:greetings).post end + + def test_update_all_with_joins_and_limit + comments = Comment.joins(:post).where('posts.id' => posts(:welcome).id).limit(1) + assert_equal 1, comments.update_all(:post_id => posts(:thinking).id) + end + + def test_update_all_with_joins_and_limit_and_order + comments = Comment.joins(:post).where('posts.id' => posts(:welcome).id).order('comments.id').limit(1) + assert_equal 1, comments.update_all(:post_id => posts(:thinking).id) + assert_equal posts(:thinking), comments(:greetings).post + assert_equal posts(:welcome), comments(:more_greetings).post + end + + def test_update_all_with_joins_and_offset + all_comments = Comment.joins(:post).where('posts.id' => posts(:welcome).id) + count = all_comments.count + comments = all_comments.offset(1) + + assert_equal count - 1, comments.update_all(:post_id => posts(:thinking).id) + end + + def test_update_all_with_joins_and_offset_and_order + all_comments = Comment.joins(:post).where('posts.id' => posts(:welcome).id).order('posts.id') + count = all_comments.count + comments = all_comments.offset(1) + + assert_equal count - 1, comments.update_all(:post_id => posts(:thinking).id) + assert_equal posts(:thinking), comments(:more_greetings).post + assert_equal posts(:welcome), comments(:greetings).post + end end From fe0ec855419e1deba47277c96275a16ecf79bc9a Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Wed, 10 Aug 2011 00:06:30 +0100 Subject: [PATCH 216/345] Refactor building the update manager --- .../abstract/database_statements.rb | 8 +++----- .../connection_adapters/mysql2_adapter.rb | 5 ++--- .../connection_adapters/mysql_adapter.rb | 5 ++--- activerecord/lib/active_record/relation.rb | 11 ++++++----- 4 files changed, 13 insertions(+), 16 deletions(-) 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 83e64d3c43..d8bd33f72a 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -310,12 +310,10 @@ module ActiveRecord # on mysql (even when aliasing the tables), but mysql allows using JOIN directly in # an UPDATE statement, so in the mysql adapters we redefine this to do that. def join_to_update(update, select) #:nodoc: - subselect = select.clone - subselect.ast.cores.last.projections = [update.ast.key] + subselect = select.ast.clone + subselect.cores.last.projections = [update.ast.key] - update.ast.limit = nil - update.ast.orders = [] - update.wheres = [update.ast.key.in(subselect)] + update.where update.ast.key.in(subselect) end protected diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb index 172d08b6f4..41d410e062 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb @@ -594,11 +594,10 @@ module ActiveRecord subselect = Arel::SelectManager.new(select.engine, subsubselect) subselect.project(Arel::Table.new('__active_record_temp')[update.ast.key.name]) - update.ast.limit = nil - update.ast.orders = [] - update.wheres = [update.ast.key.in(subselect)] + update.where update.ast.key.in(subselect) else update.table select.ast.cores.last.source + update.wheres = select.constraints end end diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index bd6cb2d3b8..d4aaf26bf3 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -508,11 +508,10 @@ module ActiveRecord subselect = Arel::SelectManager.new(select.engine, subsubselect) subselect.project(Arel::Table.new('__active_record_temp')[update.ast.key.name]) - update.ast.limit = nil - update.ast.orders = [] - update.wheres = [update.ast.key.in(subselect)] + update.where update.ast.key.in(subselect) else update.table select.ast.cores.last.source + update.wheres = select.constraints end end diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index 565ece1930..15fd1a58c8 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -216,17 +216,18 @@ module ActiveRecord if conditions || options.present? where(conditions).apply_finder_options(options.slice(:limit, :order)).update_all(updates) else - stmt = arel.compile_update(Arel.sql(@klass.send(:sanitize_sql_for_assignment, updates))) + stmt = Arel::UpdateManager.new(arel.engine) + + stmt.set Arel.sql(@klass.send(:sanitize_sql_for_assignment, updates)) + stmt.table(table) stmt.key = table[primary_key] if joins_values.any? @klass.connection.join_to_update(stmt, arel) else - if limit = arel.limit - stmt.take limit - end - + stmt.take(arel.limit) stmt.order(*arel.orders) + stmt.wheres = arel.constraints end @klass.connection.update stmt, 'SQL', bind_values From 8778c82e32690ed7b25664522d0bd0324ebea840 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Wed, 10 Aug 2011 00:49:20 +0100 Subject: [PATCH 217/345] Use a SelectCore rather than a full SelectManager --- .../lib/active_record/connection_adapters/mysql2_adapter.rb | 5 +++-- .../lib/active_record/connection_adapters/mysql_adapter.rb | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb index 41d410e062..460745fba0 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb @@ -591,8 +591,9 @@ module ActiveRecord '__active_record_temp' ) - subselect = Arel::SelectManager.new(select.engine, subsubselect) - subselect.project(Arel::Table.new('__active_record_temp')[update.ast.key.name]) + subselect = Arel::Nodes::SelectCore.new + subselect.from = subsubselect + subselect.projections << Arel::Table.new('__active_record_temp')[update.ast.key.name] update.where update.ast.key.in(subselect) else diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index d4aaf26bf3..4581c16d25 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -505,8 +505,9 @@ module ActiveRecord '__active_record_temp' ) - subselect = Arel::SelectManager.new(select.engine, subsubselect) - subselect.project(Arel::Table.new('__active_record_temp')[update.ast.key.name]) + subselect = Arel::Nodes::SelectCore.new + subselect.from = subsubselect + subselect.projections << Arel::Table.new('__active_record_temp')[update.ast.key.name] update.where update.ast.key.in(subselect) else From 12aaad0848fb29bf64025043a855b0c0b497a6b8 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Thu, 11 Aug 2011 08:38:47 +0100 Subject: [PATCH 218/345] use update.key instead of update.ast.key. make better use of select manager. --- .../abstract/database_statements.rb | 4 ++-- .../connection_adapters/mysql2_adapter.rb | 16 ++++++---------- .../connection_adapters/mysql_adapter.rb | 16 ++++++---------- 3 files changed, 14 insertions(+), 22 deletions(-) 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 d8bd33f72a..bfbf953a37 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -311,9 +311,9 @@ module ActiveRecord # an UPDATE statement, so in the mysql adapters we redefine this to do that. def join_to_update(update, select) #:nodoc: subselect = select.ast.clone - subselect.cores.last.projections = [update.ast.key] + subselect.cores.last.projections = [update.key] - update.where update.ast.key.in(subselect) + update.where update.key.in(subselect) end protected diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb index 460745fba0..379ba162ed 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb @@ -584,18 +584,14 @@ module ActiveRecord # in the form of a subsubquery. Ugh! def join_to_update(update, select) #:nodoc: if select.limit || select.offset || select.orders.any? - subsubselect = select.ast.clone - subsubselect.cores.last.projections = [update.ast.key] - subsubselect = Arel::Nodes::TableAlias.new( - Arel::Nodes::Grouping.new(subsubselect), - '__active_record_temp' - ) + subsubselect = select.clone + subsubselect.ast.cores.last.projections = [update.key] - subselect = Arel::Nodes::SelectCore.new - subselect.from = subsubselect - subselect.projections << Arel::Table.new('__active_record_temp')[update.ast.key.name] + subselect = Arel::SelectManager.new(select.engine) + subselect.project Arel.sql(update.key.name) + subselect.from subsubselect.as('__active_record_temp') - update.where update.ast.key.in(subselect) + update.where update.key.in(subselect) else update.table select.ast.cores.last.source update.wheres = select.constraints diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index 4581c16d25..a33e2d8cb0 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -498,18 +498,14 @@ module ActiveRecord # in the form of a subsubquery. Ugh! def join_to_update(update, select) #:nodoc: if select.limit || select.offset || select.orders.any? - subsubselect = select.ast.clone - subsubselect.cores.last.projections = [update.ast.key] - subsubselect = Arel::Nodes::TableAlias.new( - Arel::Nodes::Grouping.new(subsubselect), - '__active_record_temp' - ) + subsubselect = select.clone + subsubselect.ast.cores.last.projections = [update.key] - subselect = Arel::Nodes::SelectCore.new - subselect.from = subsubselect - subselect.projections << Arel::Table.new('__active_record_temp')[update.ast.key.name] + subselect = Arel::SelectManager.new(select.engine) + subselect.project Arel.sql(update.key.name) + subselect.from subsubselect.as('__active_record_temp') - update.where update.ast.key.in(subselect) + update.where update.key.in(subselect) else update.table select.ast.cores.last.source update.wheres = select.constraints From cc206a3507699e2c94b2d62ec5226fd20d5d98b3 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Thu, 11 Aug 2011 08:45:42 +0100 Subject: [PATCH 219/345] Use new SelectManager#projections= method --- .../connection_adapters/abstract/database_statements.rb | 4 ++-- .../lib/active_record/connection_adapters/mysql2_adapter.rb | 2 +- .../lib/active_record/connection_adapters/mysql_adapter.rb | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) 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 bfbf953a37..dc4a53034b 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -310,8 +310,8 @@ module ActiveRecord # on mysql (even when aliasing the tables), but mysql allows using JOIN directly in # an UPDATE statement, so in the mysql adapters we redefine this to do that. def join_to_update(update, select) #:nodoc: - subselect = select.ast.clone - subselect.cores.last.projections = [update.key] + subselect = select.clone + subselect.projections = [update.key] update.where update.key.in(subselect) end diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb index 379ba162ed..cba00dc625 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb @@ -585,7 +585,7 @@ module ActiveRecord def join_to_update(update, select) #:nodoc: if select.limit || select.offset || select.orders.any? subsubselect = select.clone - subsubselect.ast.cores.last.projections = [update.key] + subsubselect.projections = [update.key] subselect = Arel::SelectManager.new(select.engine) subselect.project Arel.sql(update.key.name) diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index a33e2d8cb0..c3a066a622 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -499,7 +499,7 @@ module ActiveRecord def join_to_update(update, select) #:nodoc: if select.limit || select.offset || select.orders.any? subsubselect = select.clone - subsubselect.ast.cores.last.projections = [update.key] + subsubselect.projections = [update.key] subselect = Arel::SelectManager.new(select.engine) subselect.project Arel.sql(update.key.name) From c3dcb795f17017cb8c3f819a30e89136540e9584 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Thu, 11 Aug 2011 08:52:48 +0100 Subject: [PATCH 220/345] Use new SelectManager#source method --- .../lib/active_record/connection_adapters/mysql2_adapter.rb | 2 +- .../lib/active_record/connection_adapters/mysql_adapter.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb index cba00dc625..ae5ae16dc7 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb @@ -593,7 +593,7 @@ module ActiveRecord update.where update.key.in(subselect) else - update.table select.ast.cores.last.source + update.table select.source update.wheres = select.constraints end end diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index c3a066a622..a44ac08ce4 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -507,7 +507,7 @@ module ActiveRecord update.where update.key.in(subselect) else - update.table select.ast.cores.last.source + update.table select.source update.wheres = select.constraints end end From 03a045b306768e12bb0f1480040aa9e93e8d6338 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Mon, 15 Aug 2011 23:07:39 +0100 Subject: [PATCH 221/345] Bump arel dependency --- activerecord/activerecord.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/activerecord.gemspec b/activerecord/activerecord.gemspec index c91a6ccd35..2de81c31a3 100644 --- a/activerecord/activerecord.gemspec +++ b/activerecord/activerecord.gemspec @@ -21,6 +21,6 @@ Gem::Specification.new do |s| s.add_dependency('activesupport', version) s.add_dependency('activemodel', version) - s.add_dependency('arel', '~> 2.2.0') + s.add_dependency('arel', '~> 2.2.1') s.add_dependency('tzinfo', '~> 0.3.29') end From 6c5f67cac15c43bafcd917c346cccfcf3fa5fb95 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Tue, 16 Aug 2011 00:59:59 +0100 Subject: [PATCH 222/345] Don't refer to ActionController::Base in the wrap_parameters initializer - use config object instead. Cuts about 15% off the load time. (#734) --- actionpack/lib/action_controller/metal/params_wrapper.rb | 2 ++ actionpack/test/controller/params_wrapper_test.rb | 7 +++++++ .../templates/config/initializers/wrap_parameters.rb.tt | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/actionpack/lib/action_controller/metal/params_wrapper.rb b/actionpack/lib/action_controller/metal/params_wrapper.rb index 2d8afc3a78..dfc4e3d72c 100644 --- a/actionpack/lib/action_controller/metal/params_wrapper.rb +++ b/actionpack/lib/action_controller/metal/params_wrapper.rb @@ -121,6 +121,8 @@ module ActionController _set_wrapper_defaults(_wrapper_options.slice(:format).merge(options), model) end + alias :wrap_parameters= :wrap_parameters + # Sets the default wrapper key or model which will be used to determine # wrapper key and attribute names. Will be called automatically when the # module is inherited. diff --git a/actionpack/test/controller/params_wrapper_test.rb b/actionpack/test/controller/params_wrapper_test.rb index 7bef1e8d5d..e1914cf894 100644 --- a/actionpack/test/controller/params_wrapper_test.rb +++ b/actionpack/test/controller/params_wrapper_test.rb @@ -180,6 +180,13 @@ class ParamsWrapperTest < ActionController::TestCase assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'user' => { 'username' => 'sikachu', 'title' => 'Developer' }}) end end + + def test_assignment_alias + with_default_wrapper_options do + UsersController.wrap_parameters = { :format => [:foo] } + assert_equal({ :format => [:foo], :name => "user" }, UsersController._wrapper_options) + end + end end class NamespacedParamsWrapperTest < ActionController::TestCase diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt index fa1548db8b..45c7e531ba 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt @@ -4,7 +4,7 @@ # is enabled by default. # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. -ActionController::Base.wrap_parameters <%= key_value :format, "[:json]" %> +<%= app_const %>.config.wrap_parameters <%= key_value :format, "[:json]" %> # Disable root element in JSON by default. if defined?(ActiveRecord) From bfb9e61a9f12024ebe999216d4d17fdb53765883 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Tue, 16 Aug 2011 01:33:34 +0100 Subject: [PATCH 223/345] Be more lazy about creating time zone objects. Decreases startup time by about 10%. (#734) --- .../lib/active_support/values/time_zone.rb | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb index 728921a069..323d5d3df7 100644 --- a/activesupport/lib/active_support/values/time_zone.rb +++ b/activesupport/lib/active_support/values/time_zone.rb @@ -337,7 +337,12 @@ module ActiveSupport end def zones_map - @zones_map ||= Hash[MAPPING.map { |place, _| [place, create(place)] }] + @zones_map ||= begin + new_zones_names = MAPPING.keys - lazy_zones_map.keys + new_zones = Hash[new_zones_names.map { |place| [place, create(place)] }] + + lazy_zones_map.merge(new_zones) + end end # Locate a specific time zone object. If the argument is a string, it @@ -349,7 +354,7 @@ module ActiveSupport case arg when String begin - zones_map[arg] ||= lookup(arg).tap { |tz| tz.utc_offset } + lazy_zones_map[arg] ||= lookup(arg).tap { |tz| tz.utc_offset } rescue TZInfo::InvalidTimezoneIdentifier nil end @@ -372,6 +377,12 @@ module ActiveSupport def lookup(name) (tzinfo = find_tzinfo(name)) && create(tzinfo.name.freeze) end + + def lazy_zones_map + @lazy_zones_map ||= Hash.new do |hash, place| + hash[place] = create(place) if MAPPING.has_key?(place) + end + end end end end From f76842f57e3f4e9292867a456abd90c034230916 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Tue, 16 Aug 2011 02:28:13 +0100 Subject: [PATCH 224/345] Fix wrap_parameters initializer template --- .../app/templates/config/initializers/wrap_parameters.rb.tt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt index 45c7e531ba..a52917351d 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt @@ -4,7 +4,7 @@ # is enabled by default. # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. -<%= app_const %>.config.wrap_parameters <%= key_value :format, "[:json]" %> +<%= app_const %>.config.wrap_parameters = { <%= key_value :format, "[:json]" %> } # Disable root element in JSON by default. if defined?(ActiveRecord) From 0d3615f04c79f6e90d8ab33fdfc920b8faac9cb8 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Tue, 16 Aug 2011 02:42:30 +0100 Subject: [PATCH 225/345] Fix tzinfo require (it broke test_raises_when_an_invalid_timezone_is_defined_in_the_config in railties) --- .../lib/active_support/values/time_zone.rb | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb index 323d5d3df7..4fb487ade1 100644 --- a/activesupport/lib/active_support/values/time_zone.rb +++ b/activesupport/lib/active_support/values/time_zone.rb @@ -195,12 +195,8 @@ module ActiveSupport # (GMT). Seconds were chosen as the offset unit because that is the unit that # Ruby uses to represent time zone offsets (see Time#utc_offset). def initialize(name, utc_offset = nil, tzinfo = nil) - begin - require 'tzinfo' - rescue LoadError => e - $stderr.puts "You don't have tzinfo installed in your application. Please add it to your Gemfile and run bundle install" - raise e - end + self.class.send(:require_tzinfo) + @name = name @utc_offset = utc_offset @tzinfo = tzinfo || TimeZone.find_tzinfo(name) @@ -372,6 +368,15 @@ module ActiveSupport @us_zones ||= all.find_all { |z| z.name =~ /US|Arizona|Indiana|Hawaii|Alaska/ } end + protected + + def require_tzinfo + require 'tzinfo' + rescue LoadError + $stderr.puts "You don't have tzinfo installed in your application. Please add it to your Gemfile and run bundle install" + raise + end + private def lookup(name) @@ -379,6 +384,8 @@ module ActiveSupport end def lazy_zones_map + require_tzinfo + @lazy_zones_map ||= Hash.new do |hash, place| hash[place] = create(place) if MAPPING.has_key?(place) end From 21e2eeacff4e9c37be374c4ed67ad3b016c854a2 Mon Sep 17 00:00:00 2001 From: Hendy Tanata Date: Tue, 16 Aug 2011 12:39:13 +0800 Subject: [PATCH 226/345] Remove unused require. --- activerecord/test/cases/attribute_methods_test.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb index dbf5a1ba76..1e38298b87 100644 --- a/activerecord/test/cases/attribute_methods_test.rb +++ b/activerecord/test/cases/attribute_methods_test.rb @@ -8,7 +8,6 @@ require 'models/computer' require 'models/topic' require 'models/company' require 'models/category' -require 'models/reply' require 'models/contact' require 'models/keyboard' From c6e57467a65a3ec998f06676154105f9617c22a6 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 16 Aug 2011 09:24:49 -0300 Subject: [PATCH 227/345] Revert "Merge pull request #2543 from htanata/unused_require_in_ar_test" This reverts commit 87152f2604e73b218df90befda576f0acfed0bbf, reversing changes made to 0d3615f04c79f6e90d8ab33fdfc920b8faac9cb8. --- activerecord/test/cases/attribute_methods_test.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb index 1e38298b87..dbf5a1ba76 100644 --- a/activerecord/test/cases/attribute_methods_test.rb +++ b/activerecord/test/cases/attribute_methods_test.rb @@ -8,6 +8,7 @@ require 'models/computer' require 'models/topic' require 'models/company' require 'models/category' +require 'models/reply' require 'models/contact' require 'models/keyboard' From 0d5a6f68dfb930816392f9711f0a6a52872bc72f Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Tue, 16 Aug 2011 15:01:18 +0100 Subject: [PATCH 228/345] In 1efd88283ef68d912df215125951a87526768a51, ConnectionAdapters was put under eager_autoload. Due to the requires in that file, this caused ConnectionSpecification to be loaded, which references ActiveRecord::Base, which means the database connection is established. We do not want to connect to the database when Active Record is loaded, only when ActiveRecord::Base is first referenced by the user. --- activerecord/lib/active_record.rb | 3 +- activerecord/lib/active_record/base.rb | 3 +- .../connection_adapters/abstract_adapter.rb | 34 ++++++++++++------- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb index d63b9e3f24..511d402ee5 100644 --- a/activerecord/lib/active_record.rb +++ b/activerecord/lib/active_record.rb @@ -42,7 +42,7 @@ module ActiveRecord autoload :ActiveRecordError, 'active_record/errors' autoload :ConnectionNotEstablished, 'active_record/errors' autoload :ConnectionAdapters, 'active_record/connection_adapters/abstract_adapter' - + autoload :Aggregations autoload :Associations autoload :AttributeMethods @@ -72,6 +72,7 @@ module ActiveRecord autoload :Persistence autoload :QueryCache autoload :Reflection + autoload :Result autoload :Schema autoload :SchemaDumper autoload :Serialization diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 59977280b3..c76f98d6a0 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -178,7 +178,7 @@ module ActiveRecord #:nodoc: # Person.find_all_by_last_name(last_name). # # It's possible to add an exclamation point (!) on the end of the dynamic finders to get them to raise an - # ActiveRecord::RecordNotFound error if they do not return any records, + # ActiveRecord::RecordNotFound error if they do not return any records, # like Person.find_by_last_name!. # # It's also possible to use multiple attributes in the same find by separating them with "_and_". @@ -2163,4 +2163,5 @@ MSG end end +require 'active_record/connection_adapters/abstract/connection_specification' ActiveSupport.run_load_hooks(:active_record, ActiveRecord::Base) diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index 077cf7df1b..60e2f811a2 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -4,20 +4,30 @@ require 'bigdecimal/util' require 'active_support/core_ext/benchmark' require 'active_support/deprecation' -# TODO: Autoload these files -require 'active_record/connection_adapters/column' -require 'active_record/connection_adapters/abstract/schema_definitions' -require 'active_record/connection_adapters/abstract/schema_statements' -require 'active_record/connection_adapters/abstract/database_statements' -require 'active_record/connection_adapters/abstract/quoting' -require 'active_record/connection_adapters/abstract/connection_pool' -require 'active_record/connection_adapters/abstract/connection_specification' -require 'active_record/connection_adapters/abstract/query_cache' -require 'active_record/connection_adapters/abstract/database_limits' -require 'active_record/result' - module ActiveRecord module ConnectionAdapters # :nodoc: + extend ActiveSupport::Autoload + + autoload :Column + + autoload_under 'abstract' do + autoload :IndexDefinition, 'active_record/connection_adapters/abstract/schema_definitions' + autoload :ColumnDefinition, 'active_record/connection_adapters/abstract/schema_definitions' + autoload :TableDefinition, 'active_record/connection_adapters/abstract/schema_definitions' + + autoload :SchemaStatements + autoload :DatabaseStatements + autoload :DatabaseLimits + autoload :Quoting + + autoload :ConnectionPool + autoload :ConnectionHandler, 'active_record/connection_adapters/abstract/connection_pool' + autoload :ConnectionManagement, 'active_record/connection_adapters/abstract/connection_pool' + autoload :ConnectionSpecification + + autoload :QueryCache + end + # Active Record supports multiple database systems. AbstractAdapter and # related classes form the abstraction layer which makes this possible. # An AbstractAdapter represents a connection to a database, and provides an From 4dd985ae9514fdb9688eab780d881decff8358fa Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Tue, 16 Aug 2011 15:13:57 +0100 Subject: [PATCH 229/345] Don't reference ActiveRecord::Base in initializers/wrap_parameters.rb. Use config.active_record instead. This yields about a 20% decrease in startup time because it means that the connection is not created immediately on startup. Of course, this is only useful if you are not going to immediately use the database after startup. --- .../config/initializers/wrap_parameters.rb.tt | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt index a52917351d..b7b344a62d 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt @@ -3,10 +3,12 @@ # This file contains settings for ActionController::ParamsWrapper which # is enabled by default. -# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. -<%= app_const %>.config.wrap_parameters = { <%= key_value :format, "[:json]" %> } +<%= app_const %>.configure do + # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. + config.action_controller.wrap_parameters = { <%= key_value :format, "[:json]" %> } -# Disable root element in JSON by default. -if defined?(ActiveRecord) - ActiveRecord::Base.include_root_in_json = false + <%- unless options.skip_active_record? -%> + # Disable root element in JSON by default. + config.active_record.include_root_in_json = false + <%- end -%> end From 590239156714c03ad525b2248a11a3f34da3aa6a Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Tue, 16 Aug 2011 16:37:56 +0100 Subject: [PATCH 230/345] Fix assets tests in railties --- actionpack/lib/sprockets/assets.rake | 4 +++- railties/test/application/assets_test.rb | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/actionpack/lib/sprockets/assets.rake b/actionpack/lib/sprockets/assets.rake index 9b2646b0a2..4cf5caab91 100644 --- a/actionpack/lib/sprockets/assets.rake +++ b/actionpack/lib/sprockets/assets.rake @@ -9,7 +9,9 @@ namespace :assets do Kernel.exec $0, *ARGV else Rake::Task["environment"].invoke - Sprockets::Helpers::RailsHelper + + # Ensure that action view is loaded and the appropriate sprockets hooks get executed + ActionView::Base assets = Rails.application.config.assets.precompile # Always perform caching so that asset_path appends the timestamps to file references. diff --git a/railties/test/application/assets_test.rb b/railties/test/application/assets_test.rb index 7e68de5674..a8d1382e94 100644 --- a/railties/test/application/assets_test.rb +++ b/railties/test/application/assets_test.rb @@ -54,8 +54,8 @@ module ApplicationTests capture(:stdout) do Dir.chdir(app_path){ `bundle exec rake assets:precompile` } end - files = Dir["#{app_path}/public/assets/application-b29a188b3d9c74ef7cbb7ddf9e99f953.js"] - files << Dir["#{app_path}/public/assets/foo/application-b29a188b3d9c74ef7cbb7ddf9e99f953.js"].first + files = Dir["#{app_path}/public/assets/application-*.js"] + files << Dir["#{app_path}/public/assets/foo/application-*.js"].first files.each do |file| assert_not_nil file, "Expected application.js asset to be generated, but none found" assert_equal "alert()", File.read(file) @@ -68,7 +68,7 @@ module ApplicationTests # capture(:stdout) do Dir.chdir(app_path){ `bundle exec rake assets:precompile RAILS_ENV=test` } # end - file = Dir["#{app_path}/public/assets/application-4bd8b7059c5336ec7ad515c9dbd59974.css"].first + file = Dir["#{app_path}/public/assets/application-*.css"].first assert_match /\/assets\/rails-([0-z]+)\.png/, File.read(file) end @@ -79,7 +79,7 @@ module ApplicationTests capture(:stdout) do Dir.chdir(app_path){ `bundle exec rake assets:precompile RAILS_GROUPS=assets` } end - file = Dir["#{app_path}/public/assets/application-8d301a938f1abfd789bbec87ed1ef770.css"].first + file = Dir["#{app_path}/public/assets/application-*.css"].first assert_match /\/assets\/rails-([0-z]+)\.png/, File.read(file) end From 53a13083ecc7f99ff04d3fe54f8cb1d68e486aac Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Tue, 16 Aug 2011 10:34:18 -0700 Subject: [PATCH 231/345] AS guide: document in Module#delegate that the method must be public in the target --- railties/guides/source/active_support_core_extensions.textile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/railties/guides/source/active_support_core_extensions.textile b/railties/guides/source/active_support_core_extensions.textile index 8716e94bd9..38920c2edb 100644 --- a/railties/guides/source/active_support_core_extensions.textile +++ b/railties/guides/source/active_support_core_extensions.textile @@ -888,7 +888,9 @@ end It is shorter, and the intention more obvious. -The macro accepts several methods: +The method must be public in the target. + +The +delegate+ macro accepts several methods: delegate :name, :age, :address, :twitter, :to => :profile From d0d25a9317aaea794f30e067e9388fe4e08bcde5 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Tue, 16 Aug 2011 10:49:20 -0700 Subject: [PATCH 232/345] prefer ends_with? over slicing --- activesupport/lib/active_support/core_ext/module/delegation.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/activesupport/lib/active_support/core_ext/module/delegation.rb b/activesupport/lib/active_support/core_ext/module/delegation.rb index 4a899a7d84..8350753f78 100644 --- a/activesupport/lib/active_support/core_ext/module/delegation.rb +++ b/activesupport/lib/active_support/core_ext/module/delegation.rb @@ -1,4 +1,5 @@ require 'active_support/core_ext/object/public_send' +require 'active_support/core_ext/string/starts_ends_with' class Module # Provides a delegate class method to easily expose contained objects' methods @@ -126,7 +127,7 @@ class Module methods.each do |method| method = method.to_s - call = (method[-1..-1] == '=') ? "public_send(:#{method}, " : "#{method}(" + call = method.ends_with?('=') ? "public_send(:#{method}, " : "#{method}(" if allow_nil module_eval(<<-EOS, file, line - 2) From 8e236152457ed48bb436e9bffb4c5d6d4b6a26d4 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Tue, 16 Aug 2011 19:14:06 +0100 Subject: [PATCH 233/345] Use lazy load hooks to set parameter wrapping configuration. This means that it doesn't force Action Controller / Active Record to load, but it doesn't fail if they have already loaded. Thanks @josevalim for the hint. --- .../action_controller/metal/params_wrapper.rb | 2 -- .../test/controller/params_wrapper_test.rb | 7 ------- .../config/initializers/wrap_parameters.rb.tt | 18 ++++++++++-------- 3 files changed, 10 insertions(+), 17 deletions(-) diff --git a/actionpack/lib/action_controller/metal/params_wrapper.rb b/actionpack/lib/action_controller/metal/params_wrapper.rb index dfc4e3d72c..2d8afc3a78 100644 --- a/actionpack/lib/action_controller/metal/params_wrapper.rb +++ b/actionpack/lib/action_controller/metal/params_wrapper.rb @@ -121,8 +121,6 @@ module ActionController _set_wrapper_defaults(_wrapper_options.slice(:format).merge(options), model) end - alias :wrap_parameters= :wrap_parameters - # Sets the default wrapper key or model which will be used to determine # wrapper key and attribute names. Will be called automatically when the # module is inherited. diff --git a/actionpack/test/controller/params_wrapper_test.rb b/actionpack/test/controller/params_wrapper_test.rb index e1914cf894..7bef1e8d5d 100644 --- a/actionpack/test/controller/params_wrapper_test.rb +++ b/actionpack/test/controller/params_wrapper_test.rb @@ -180,13 +180,6 @@ class ParamsWrapperTest < ActionController::TestCase assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'user' => { 'username' => 'sikachu', 'title' => 'Developer' }}) end end - - def test_assignment_alias - with_default_wrapper_options do - UsersController.wrap_parameters = { :format => [:foo] } - assert_equal({ :format => [:foo], :name => "user" }, UsersController._wrapper_options) - end - end end class NamespacedParamsWrapperTest < ActionController::TestCase diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt index b7b344a62d..d640f578da 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt @@ -3,12 +3,14 @@ # This file contains settings for ActionController::ParamsWrapper which # is enabled by default. -<%= app_const %>.configure do - # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. - config.action_controller.wrap_parameters = { <%= key_value :format, "[:json]" %> } - - <%- unless options.skip_active_record? -%> - # Disable root element in JSON by default. - config.active_record.include_root_in_json = false - <%- end -%> +# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. +ActiveSupport.on_load(:action_controller) do + wrap_parameters <%= key_value :format, "[:json]" %> end + +<%- unless options.skip_active_record? -%> +# Disable root element in JSON by default. +ActiveSupport.on_load(:active_record) do + self.include_root_in_json = false +end +<%- end -%> From b0555bb88b090ca981fcc7661b6f9ea333e7f42e Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 16 Aug 2011 11:29:54 -0700 Subject: [PATCH 234/345] adding security email address --- RELEASING_RAILS.rdoc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/RELEASING_RAILS.rdoc b/RELEASING_RAILS.rdoc index 4a9a875bfa..c2ba4e7857 100644 --- a/RELEASING_RAILS.rdoc +++ b/RELEASING_RAILS.rdoc @@ -149,8 +149,7 @@ more explanation on a particular step, so the RC steps. You can do this, or ask the security team to do it. -FIXME: I can't remember the email addresses, but we should list them here. -FIXME: Possibly we should do this the day of the RC? +Email the security reports to: rubyonrails-security@googlegroups.com * Apply security patches to the release branch * Update CHANGELOG with security fixes. From 8a39f411dc3c806422785b1f4d5c7c9d58e4bf85 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 16 Aug 2011 15:17:17 -0700 Subject: [PATCH 235/345] prevent sql injection attacks by escaping quotes in column names --- .../connection_adapters/mysql2_adapter.rb | 2 +- .../connection_adapters/mysql_adapter.rb | 2 +- .../connection_adapters/sqlite_adapter.rb | 2 +- activerecord/test/cases/base_test.rb | 17 +++++++++++++++++ 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb index ae5ae16dc7..ef51f5ebca 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb @@ -169,7 +169,7 @@ module ActiveRecord end def quote_column_name(name) #:nodoc: - @quoted_column_names[name] ||= "`#{name}`" + @quoted_column_names[name] ||= "`#{name.to_s.gsub('`', '``')}`" end def quote_table_name(name) #:nodoc: diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index a44ac08ce4..b844e5ab10 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -250,7 +250,7 @@ module ActiveRecord end def quote_column_name(name) #:nodoc: - @quoted_column_names[name] ||= "`#{name}`" + @quoted_column_names[name] ||= "`#{name.to_s.gsub('`', '``')}`" end def quote_table_name(name) #:nodoc: diff --git a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb index 486efc5ba0..da86957028 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb @@ -148,7 +148,7 @@ module ActiveRecord end def quote_column_name(name) #:nodoc: - %Q("#{name}") + %Q("#{name.to_s.gsub('"', '""')}") end # Quote date/time values for use in SQL input. Includes microseconds diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index b8ebabfe70..fe46c00b47 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -67,6 +67,23 @@ end class BasicsTest < ActiveRecord::TestCase fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, 'warehouse-things', :authors, :categorizations, :categories, :posts + def test_column_names_are_escaped + conn = ActiveRecord::Base.connection + classname = conn.class.name[/[^:]*$/] + badchar = { + 'SQLite3Adapter' => '"', + 'MysqlAdapter' => '`', + 'Mysql2Adapter' => '`', + 'PostgreSQLAdapter' => '"', + 'OracleAdapter' => '"', + }.fetch(classname) { + raise "need a bad char for #{classname}" + } + + quoted = conn.quote_column_name "foo#{badchar}bar" + assert_equal("#{badchar}foo#{badchar * 2}bar#{badchar}", quoted) + end + def test_columns_should_obey_set_primary_key pk = Subscriber.columns.find { |x| x.name == 'nick' } assert pk.primary, 'nick should be primary key' From 586a944ddd4d03e66dea1093306147594748037a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 16 Aug 2011 15:17:49 -0700 Subject: [PATCH 236/345] Tags with invalid names should also be stripped in order to prevent XSS attacks. Thanks Sascha Depold for the report. --- .../lib/action_controller/vendor/html-scanner/html/node.rb | 2 +- actionpack/test/template/html-scanner/sanitizer_test.rb | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/actionpack/lib/action_controller/vendor/html-scanner/html/node.rb b/actionpack/lib/action_controller/vendor/html-scanner/html/node.rb index 22b3243104..4e1f016431 100644 --- a/actionpack/lib/action_controller/vendor/html-scanner/html/node.rb +++ b/actionpack/lib/action_controller/vendor/html-scanner/html/node.rb @@ -156,7 +156,7 @@ module HTML #:nodoc: end closing = ( scanner.scan(/\//) ? :close : nil ) - return Text.new(parent, line, pos, content) unless name = scanner.scan(/[\w:-]+/) + return Text.new(parent, line, pos, content) unless name = scanner.scan(/[^\s!>\/]+/) name.downcase! unless closing diff --git a/actionpack/test/template/html-scanner/sanitizer_test.rb b/actionpack/test/template/html-scanner/sanitizer_test.rb index 678cb9eeeb..62ad6be680 100644 --- a/actionpack/test/template/html-scanner/sanitizer_test.rb +++ b/actionpack/test/template/html-scanner/sanitizer_test.rb @@ -5,6 +5,13 @@ class SanitizerTest < ActionController::TestCase @sanitizer = nil # used by assert_sanitizer end + def test_strip_tags_with_quote + sanitizer = HTML::FullSanitizer.new + string = '<" hi' + + assert_equal ' hi', sanitizer.sanitize(string) + end + def test_strip_tags sanitizer = HTML::FullSanitizer.new assert_equal("<< Date: Tue, 16 Aug 2011 15:18:53 -0700 Subject: [PATCH 237/345] properly escape html to avoid invalid utf8 causing XSS attacks --- .../lib/active_support/core_ext/string/output_safety.rb | 2 +- activesupport/test/core_ext/string_ext_test.rb | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/activesupport/lib/active_support/core_ext/string/output_safety.rb b/activesupport/lib/active_support/core_ext/string/output_safety.rb index 6d6c4912bb..f111c8e5a3 100644 --- a/activesupport/lib/active_support/core_ext/string/output_safety.rb +++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb @@ -20,7 +20,7 @@ class ERB if s.html_safe? s else - s.gsub(/[&"><]/) { |special| HTML_ESCAPE[special] }.html_safe + s.to_s.gsub(/&/, "&").gsub(/\"/, """).gsub(/>/, ">").gsub(/ Date: Tue, 16 Aug 2011 15:16:45 -0700 Subject: [PATCH 238/345] Properly escape glob characters. --- actionpack/lib/action_view/template/resolver.rb | 15 ++++++++++++--- actionpack/test/controller/render_test.rb | 14 ++++++++++++++ actionpack/test/fixtures/test/hello_w*rld.erb | 1 + 3 files changed, 27 insertions(+), 3 deletions(-) create mode 100644 actionpack/test/fixtures/test/hello_w*rld.erb diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb index 7abaa07bc7..e78d3a82be 100644 --- a/actionpack/lib/action_view/template/resolver.rb +++ b/actionpack/lib/action_view/template/resolver.rb @@ -142,8 +142,12 @@ module ActionView # Helper for building query glob string based on resolver's pattern. def build_query(path, details) query = @pattern.dup - query.gsub!(/\:prefix(\/)?/, path.prefix.empty? ? "" : "#{path.prefix}\\1") # prefix can be empty... - query.gsub!(/\:action/, path.partial? ? "_#{path.name}" : path.name) + + prefix = path.prefix.empty? ? "" : "#{escape_entry(path.prefix)}\\1" + query.gsub!(/\:prefix(\/)?/, prefix) + + partial = escape_entry(path.partial? ? "_#{path.name}" : path.name) + query.gsub!(/\:action/, partial) details.each do |ext, variants| query.gsub!(/\:#{ext}/, "{#{variants.compact.uniq.join(',')}}") @@ -152,6 +156,10 @@ module ActionView File.expand_path(query, @path) end + def escape_entry(entry) + entry.gsub(/(\*|\[|\]|\{|\}|\?)/, "\\\\\\1") + end + # Returns the file mtime from the filesystem. def mtime(p) File.mtime(p) @@ -228,8 +236,9 @@ module ActionView class OptimizedFileSystemResolver < FileSystemResolver #:nodoc: def build_query(path, details) exts = EXTENSIONS.map { |ext| details[ext] } + query = escape_entry(File.join(@path, path)) - File.join(@path, path) + exts.map { |ext| + query + exts.map { |ext| "{#{ext.compact.uniq.map { |e| ".#{e}," }.join}}" }.join end diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index ce4b407c7d..6bcd606bf4 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -405,6 +405,14 @@ class TestController < ActionController::Base render :template => "test/hello_world" end + def render_with_explicit_unescaped_template + render :template => "test/h*llo_world" + end + + def render_with_explicit_escaped_template + render :template => "test/hello_w*rld" + end + def render_with_explicit_string_template render "test/hello_world" end @@ -1057,6 +1065,12 @@ class RenderTest < ActionController::TestCase assert_response :success end + def test_render_with_explicit_unescaped_template + assert_raise(ActionView::MissingTemplate) { get :render_with_explicit_unescaped_template } + get :render_with_explicit_escaped_template + assert_equal "Hello w*rld!", @response.body + end + def test_render_with_explicit_string_template get :render_with_explicit_string_template assert_equal "Hello world!", @response.body diff --git a/actionpack/test/fixtures/test/hello_w*rld.erb b/actionpack/test/fixtures/test/hello_w*rld.erb new file mode 100644 index 0000000000..bc8fa5e0ca --- /dev/null +++ b/actionpack/test/fixtures/test/hello_w*rld.erb @@ -0,0 +1 @@ +Hello w*rld! \ No newline at end of file From 9d9f59139ea4db9ac6e55defc5156f8e8ab580f8 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 16 Aug 2011 16:30:29 -0700 Subject: [PATCH 239/345] adding lessons learned so I do not make the same mistake twice --- RELEASING_RAILS.rdoc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/RELEASING_RAILS.rdoc b/RELEASING_RAILS.rdoc index c2ba4e7857..f4197e0eb2 100644 --- a/RELEASING_RAILS.rdoc +++ b/RELEASING_RAILS.rdoc @@ -145,6 +145,11 @@ commits should be added to the release branch besides regression fixing commits. Many of these steps are the same as for the release candidate, so if you need more explanation on a particular step, so the RC steps. +=== Release the gem. + +See steps for releasing the RC. Make sure to release the gem before +announcing security issues in the next step. + === Email the rails security announce list, once for each vulnerability fixed. You can do this, or ask the security team to do it. From 22e611ed5b0a708d17ef2e7574bcdf2edf2db01b Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 16 Aug 2011 17:39:58 -0700 Subject: [PATCH 240/345] making the order more clear, adding linux distros mailing lists to our cc --- RELEASING_RAILS.rdoc | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/RELEASING_RAILS.rdoc b/RELEASING_RAILS.rdoc index f4197e0eb2..cbc9d0e1de 100644 --- a/RELEASING_RAILS.rdoc +++ b/RELEASING_RAILS.rdoc @@ -145,22 +145,25 @@ commits should be added to the release branch besides regression fixing commits. Many of these steps are the same as for the release candidate, so if you need more explanation on a particular step, so the RC steps. -=== Release the gem. - -See steps for releasing the RC. Make sure to release the gem before -announcing security issues in the next step. - -=== Email the rails security announce list, once for each vulnerability fixed. - -You can do this, or ask the security team to do it. - -Email the security reports to: rubyonrails-security@googlegroups.com +Today, do this stuff in this order: * Apply security patches to the release branch * Update CHANGELOG with security fixes. * Update RAILS_VERSION to remove the rc * Release the gems -* Email announcement +* Email security lists +* Email general announcement lists + +=== Emailing the rails security announce list + +Email the security announce list once for each vulnerability fixed. + +You can do this, or ask the security team to do it. + +Email the security reports to: + +* rubyonrails-security@googlegroups.com +* linux-distros@vs.openwall.org Be sure to note the security fixes in your announcement along with CVE numbers and links to each patch. Some people may not be able to upgrade right away, From 3ebb322f2180e8b9dada05706172f75d185923d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=20Garc=C3=ADa?= Date: Wed, 17 Aug 2011 04:01:07 +0200 Subject: [PATCH 241/345] Cleanup application.css --- .../app/templates/app/assets/stylesheets/application.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/railties/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css b/railties/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css index 9e07c7d9a9..3b5cc6648e 100644 --- a/railties/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css +++ b/railties/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css @@ -4,10 +4,10 @@ * * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path. - * + * * You're free to add application-wide styles to this file and they'll appear at the top of the * compiled file, but it's generally better to create a new file per style scope. * *= require_self - *= require_tree . -*/ \ No newline at end of file + *= require_tree . +*/ From 8620bf90c5e486e1ec44b9aabb63f8c848668ed2 Mon Sep 17 00:00:00 2001 From: Bogdan Gusiev Date: Wed, 17 Aug 2011 17:26:00 +0300 Subject: [PATCH 242/345] Implemented strict validation concept In order to deliver debug information to dev team instead of display error message to end user Implemented strict validation concept that suppose to define validation that always raise exception when fails --- activemodel/lib/active_model/errors.rb | 8 ++++- .../active_model/validations/acceptance.rb | 2 ++ .../active_model/validations/confirmation.rb | 2 ++ .../lib/active_model/validations/exclusion.rb | 2 ++ .../lib/active_model/validations/format.rb | 2 ++ .../lib/active_model/validations/inclusion.rb | 2 ++ .../lib/active_model/validations/length.rb | 2 ++ .../active_model/validations/numericality.rb | 2 ++ .../lib/active_model/validations/presence.rb | 2 ++ .../lib/active_model/validations/validates.rb | 18 ++++++++-- .../lib/active_model/validations/with.rb | 6 ++-- activemodel/test/cases/validations_test.rb | 33 +++++++++++++++++++ 12 files changed, 75 insertions(+), 6 deletions(-) diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb index 36819553ee..843c0c3cb5 100644 --- a/activemodel/lib/active_model/errors.rb +++ b/activemodel/lib/active_model/errors.rb @@ -63,7 +63,7 @@ module ActiveModel class Errors include Enumerable - CALLBACKS_OPTIONS = [:if, :unless, :on, :allow_nil, :allow_blank] + CALLBACKS_OPTIONS = [:if, :unless, :on, :allow_nil, :allow_blank, :strict] attr_reader :messages @@ -218,6 +218,9 @@ module ActiveModel elsif message.is_a?(Proc) message = message.call end + if options[:strict] + raise ActiveModel::StrictValidationFailed, message + end self[attribute] << message end @@ -319,4 +322,7 @@ module ActiveModel I18n.translate(key, options) end end + + class StrictValidationFailed < StandardError + end end diff --git a/activemodel/lib/active_model/validations/acceptance.rb b/activemodel/lib/active_model/validations/acceptance.rb index 01907ac9da..e628c6f306 100644 --- a/activemodel/lib/active_model/validations/acceptance.rb +++ b/activemodel/lib/active_model/validations/acceptance.rb @@ -58,6 +58,8 @@ module ActiveModel # :unless => Proc.new { |user| user.signup_step <= 2 }). # The method, proc or string should return or evaluate to a true or # false value. + # * :strict - Specifies whether validation should be strict. + # See ActiveModel::Validation#validates! for more information def validates_acceptance_of(*attr_names) validates_with AcceptanceValidator, _merge_attributes(attr_names) end diff --git a/activemodel/lib/active_model/validations/confirmation.rb b/activemodel/lib/active_model/validations/confirmation.rb index a9dcb0b505..6573a7d264 100644 --- a/activemodel/lib/active_model/validations/confirmation.rb +++ b/activemodel/lib/active_model/validations/confirmation.rb @@ -58,6 +58,8 @@ module ActiveModel # :unless => :skip_validation, or # :unless => Proc.new { |user| user.signup_step <= 2 }). The # method, proc or string should return or evaluate to a true or false value. + # * :strict - Specifies whether validation should be strict. + # See ActiveModel::Validation#validates! for more information def validates_confirmation_of(*attr_names) validates_with ConfirmationValidator, _merge_attributes(attr_names) end diff --git a/activemodel/lib/active_model/validations/exclusion.rb b/activemodel/lib/active_model/validations/exclusion.rb index d3b8d31502..644cc814a7 100644 --- a/activemodel/lib/active_model/validations/exclusion.rb +++ b/activemodel/lib/active_model/validations/exclusion.rb @@ -59,6 +59,8 @@ module ActiveModel # * :unless - Specifies a method, proc or string to call to determine if the validation should # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The # method, proc or string should return or evaluate to a true or false value. + # * :strict - Specifies whether validation should be strict. + # See ActiveModel::Validation#validates! for more information def validates_exclusion_of(*attr_names) validates_with ExclusionValidator, _merge_attributes(attr_names) end diff --git a/activemodel/lib/active_model/validations/format.rb b/activemodel/lib/active_model/validations/format.rb index 090e8cfbae..d3faa8c6a6 100644 --- a/activemodel/lib/active_model/validations/format.rb +++ b/activemodel/lib/active_model/validations/format.rb @@ -84,6 +84,8 @@ module ActiveModel # * :unless - Specifies a method, proc or string to call to determine if the validation should # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The # method, proc or string should return or evaluate to a true or false value. + # * :strict - Specifies whether validation should be strict. + # See ActiveModel::Validation#validates! for more information def validates_format_of(*attr_names) validates_with FormatValidator, _merge_attributes(attr_names) end diff --git a/activemodel/lib/active_model/validations/inclusion.rb b/activemodel/lib/active_model/validations/inclusion.rb index 9a9270d615..147e2ecb69 100644 --- a/activemodel/lib/active_model/validations/inclusion.rb +++ b/activemodel/lib/active_model/validations/inclusion.rb @@ -59,6 +59,8 @@ module ActiveModel # * :unless - Specifies a method, proc or string to call to determine if the validation should # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The # method, proc or string should return or evaluate to a true or false value. + # * :strict - Specifies whether validation should be strict. + # See ActiveModel::Validation#validates! for more information def validates_inclusion_of(*attr_names) validates_with InclusionValidator, _merge_attributes(attr_names) end diff --git a/activemodel/lib/active_model/validations/length.rb b/activemodel/lib/active_model/validations/length.rb index 144e73904e..eb7aac709d 100644 --- a/activemodel/lib/active_model/validations/length.rb +++ b/activemodel/lib/active_model/validations/length.rb @@ -96,6 +96,8 @@ module ActiveModel # * :tokenizer - Specifies how to split up the attribute string. (e.g. :tokenizer => lambda {|str| str.scan(/\w+/)} to # count words as in above example.) # Defaults to lambda{ |value| value.split(//) } which counts individual characters. + # * :strict - Specifies whether validation should be strict. + # See ActiveModel::Validation#validates! for more information def validates_length_of(*attr_names) validates_with LengthValidator, _merge_attributes(attr_names) end diff --git a/activemodel/lib/active_model/validations/numericality.rb b/activemodel/lib/active_model/validations/numericality.rb index 0d1903362c..34d447a0fa 100644 --- a/activemodel/lib/active_model/validations/numericality.rb +++ b/activemodel/lib/active_model/validations/numericality.rb @@ -107,6 +107,8 @@ module ActiveModel # * :unless - Specifies a method, proc or string to call to determine if the validation should # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The # method, proc or string should return or evaluate to a true or false value. + # * :strict - Specifies whether validation should be strict. + # See ActiveModel::Validation#validates! for more information # # The following checks can also be supplied with a proc or a symbol which corresponds to a method: # * :greater_than diff --git a/activemodel/lib/active_model/validations/presence.rb b/activemodel/lib/active_model/validations/presence.rb index cfb4c33dcc..35af7152db 100644 --- a/activemodel/lib/active_model/validations/presence.rb +++ b/activemodel/lib/active_model/validations/presence.rb @@ -35,6 +35,8 @@ module ActiveModel # * unless - Specifies a method, proc or string to call to determine if the validation should # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). # The method, proc or string should return or evaluate to a true or false value. + # * :strict - Specifies whether validation should be strict. + # See ActiveModel::Validation#validates! for more information # def validates_presence_of(*attr_names) validates_with PresenceValidator, _merge_attributes(attr_names) diff --git a/activemodel/lib/active_model/validations/validates.rb b/activemodel/lib/active_model/validations/validates.rb index 7ff42de00b..43b095d11a 100644 --- a/activemodel/lib/active_model/validations/validates.rb +++ b/activemodel/lib/active_model/validations/validates.rb @@ -70,8 +70,8 @@ module ActiveModel # validator's initializer as +options[:in]+ while other types including # regular expressions and strings are passed as +options[:with]+ # - # Finally, the options +:if+, +:unless+, +:on+, +:allow_blank+ and +:allow_nil+ can be given - # to one specific validator, as a hash: + # Finally, the options +:if+, +:unless+, +:on+, +:allow_blank+, +:allow_nil+ and +:strict+ + # can be given to one specific validator, as a hash: # # validates :password, :presence => { :if => :password_required? }, :confirmation => true # @@ -101,12 +101,24 @@ module ActiveModel end end + # This method is used to define validation that can not be correcterized by end user + # and is considered exceptional. + # So each validator defined with bang or :strict option set to true + # will always raise ActiveModel::InternalValidationFailed instead of adding error + # when validation fails + # See validates for more information about validation itself. + def validates!(*attributes) + options = attributes.extract_options! + options[:strict] = true + validates(*(attributes << options)) + end + protected # When creating custom validators, it might be useful to be able to specify # additional default keys. This can be done by overwriting this method. def _validates_default_keys - [ :if, :unless, :on, :allow_blank, :allow_nil ] + [ :if, :unless, :on, :allow_blank, :allow_nil , :strict] end def _parse_validates_options(options) #:nodoc: diff --git a/activemodel/lib/active_model/validations/with.rb b/activemodel/lib/active_model/validations/with.rb index a87b213fe4..83aae206a6 100644 --- a/activemodel/lib/active_model/validations/with.rb +++ b/activemodel/lib/active_model/validations/with.rb @@ -61,7 +61,9 @@ module ActiveModel # (e.g. :unless => :skip_validation, or # :unless => Proc.new { |user| user.signup_step <= 2 }). # The method, proc or string should return or evaluate to a true or false value. - # + # * :strict - Specifies whether validation should be strict. + # See ActiveModel::Validation#validates! for more information + # If you pass any additional configuration options, they will be passed # to the class and available as options: # @@ -140,4 +142,4 @@ module ActiveModel end end end -end \ No newline at end of file +end diff --git a/activemodel/test/cases/validations_test.rb b/activemodel/test/cases/validations_test.rb index 0b50acf913..2f4376bd41 100644 --- a/activemodel/test/cases/validations_test.rb +++ b/activemodel/test/cases/validations_test.rb @@ -297,4 +297,37 @@ class ValidationsTest < ActiveModel::TestCase assert auto.valid? end + + def test_strict_validation_in_validates + Topic.validates :title, :strict => true, :presence => true + assert_raises ActiveModel::StrictValidationFailed do + Topic.new.valid? + end + end + + def test_strict_validation_not_fails + Topic.validates :title, :strict => true, :presence => true + assert Topic.new(:title => "hello").valid? + end + + def test_strict_validation_particular_validator + Topic.validates :title, :presence => {:strict => true} + assert_raises ActiveModel::StrictValidationFailed do + Topic.new.valid? + end + end + + def test_strict_validation_in_custom_validator_helper + Topic.validates_presence_of :title, :strict => true + assert_raises ActiveModel::StrictValidationFailed do + Topic.new.valid? + end + end + + def test_validates_with_bang + Topic.validates! :title, :presence => true + assert_raises ActiveModel::StrictValidationFailed do + Topic.new.valid? + end + end end From 3b5eb11664b8257d35dced58f1d65e34fa4a6c1f Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Wed, 17 Aug 2011 14:37:27 -0700 Subject: [PATCH 243/345] fixes generation of the AR querying guide --- railties/guides/source/active_record_querying.textile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/railties/guides/source/active_record_querying.textile b/railties/guides/source/active_record_querying.textile index 8ea06d28aa..4e77a6e803 100644 --- a/railties/guides/source/active_record_querying.textile +++ b/railties/guides/source/active_record_querying.textile @@ -560,6 +560,7 @@ Client.where("orders_count > 10").order(:name).reverse_order The SQL that would be executed: + SELECT * FROM clients WHERE orders_count > 10 ORDER BY name DESC @@ -571,6 +572,7 @@ Client.where("orders_count > 10").reverse_order The SQL that would be executed: + SELECT * FROM clients WHERE orders_count > 10 ORDER BY clients.id DESC @@ -621,8 +623,6 @@ You're then responsible for dealing with the conflict by rescuing the exception NOTE: You must ensure that your database schema defaults the +lock_version+ column to +0+. -
- This behavior can be turned off by setting ActiveRecord::Base.lock_optimistically = false. To override the name of the +lock_version+ column, +ActiveRecord::Base+ provides a class method called +set_locking_column+: From cc90adfd2a171c5fc9f90f6a6506c5ac937efab3 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Thu, 18 Aug 2011 02:59:02 -0700 Subject: [PATCH 244/345] minor details revised in a gsub Regexps have a construct to express alternation of characters, which is character classes. In addition to being the most specific idiom to write this pattern, it reads better without the backslashes. Also, it is better not to use a capture if none is needed. As a side-effect of these changes, the gsub is marginally faster, but speed is not the point of this commit. --- actionpack/lib/action_view/template/resolver.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb index e78d3a82be..f855ea257c 100644 --- a/actionpack/lib/action_view/template/resolver.rb +++ b/actionpack/lib/action_view/template/resolver.rb @@ -157,7 +157,7 @@ module ActionView end def escape_entry(entry) - entry.gsub(/(\*|\[|\]|\{|\}|\?)/, "\\\\\\1") + entry.gsub(/[*?{}\[\]]/, '\\\\\\&') end # Returns the file mtime from the filesystem. From 7223f10acda3d5683e6de817bc7131ca109f3f28 Mon Sep 17 00:00:00 2001 From: Guillermo Iguaran Date: Thu, 18 Aug 2011 14:59:27 -0500 Subject: [PATCH 245/345] Debug assets by default in development and test environments --- .../lib/sprockets/helpers/rails_helper.rb | 4 +-- .../test/template/sprockets_helper_test.rb | 30 ++++++++++++++----- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/actionpack/lib/sprockets/helpers/rails_helper.rb b/actionpack/lib/sprockets/helpers/rails_helper.rb index ec3d36d5ad..a65c5992ca 100644 --- a/actionpack/lib/sprockets/helpers/rails_helper.rb +++ b/actionpack/lib/sprockets/helpers/rails_helper.rb @@ -70,8 +70,8 @@ module Sprockets private def debug_assets? - params[:debug_assets] == '1' || - params[:debug_assets] == 'true' + Rails.env.development? || Rails.env.test? || + params[:debug_assets] == '1' || params[:debug_assets] == 'true' rescue NoMethodError false end diff --git a/actionpack/test/template/sprockets_helper_test.rb b/actionpack/test/template/sprockets_helper_test.rb index dfa635335e..d303acad0f 100644 --- a/actionpack/test/template/sprockets_helper_test.rb +++ b/actionpack/test/template/sprockets_helper_test.rb @@ -141,6 +141,8 @@ class SprocketsHelperTest < ActionView::TestCase end test "javascript include tag" do + Rails.env.stubs(:test?).returns(false) + assert_match %r{}, javascript_include_tag(:application) @@ -151,11 +153,17 @@ class SprocketsHelperTest < ActionView::TestCase assert_equal '', javascript_include_tag("http://www.example.com/xmlhr") - assert_match %r{\n}, - javascript_include_tag(:application, :debug => true) - - assert_match %r{\n}, + assert_match %r{\n}, javascript_include_tag("xmlhr", "extra") + + Rails.env.stubs(:test?).returns(true) + + assert_match %r{\n}, + javascript_include_tag(:application) + + assert_match %r{}, + javascript_include_tag(:application, :debug => false) + end test "stylesheet path" do @@ -172,6 +180,8 @@ class SprocketsHelperTest < ActionView::TestCase end test "stylesheet link tag" do + Rails.env.stubs(:test?).returns(false) + assert_match %r{}, stylesheet_link_tag(:application) @@ -187,11 +197,17 @@ class SprocketsHelperTest < ActionView::TestCase assert_match %r{}, stylesheet_link_tag("style", :media => "print") - assert_match %r{\n}, - stylesheet_link_tag(:application, :debug => true) - assert_match %r{\n}, stylesheet_link_tag("style", "extra") + + Rails.env.stubs(:test?).returns(true) + + assert_match %r{\n}, + stylesheet_link_tag(:application) + + assert_match %r{}, + stylesheet_link_tag(:application, :debug => false) + end test "alternate asset prefix" do From 129ad7226d32b19fac1aca2ebccd570b3382d6d5 Mon Sep 17 00:00:00 2001 From: Vijay Dev Date: Sat, 20 Aug 2011 00:17:37 +0530 Subject: [PATCH 246/345] mailer guide: fixes indentation, and use fixed width fonts wherever necessary --- .../source/action_mailer_basics.textile | 57 +++++++++---------- 1 file changed, 26 insertions(+), 31 deletions(-) diff --git a/railties/guides/source/action_mailer_basics.textile b/railties/guides/source/action_mailer_basics.textile index 0941b06cfe..142b9dba7e 100644 --- a/railties/guides/source/action_mailer_basics.textile +++ b/railties/guides/source/action_mailer_basics.textile @@ -8,7 +8,7 @@ WARNING. This Guide is based on Rails 3.0. Some of the code shown here will not h3. Introduction -Action Mailer allows you to send emails from your application using a mailer model and views. So, in Rails, emails are used by creating mailers that inherit from +ActionMailer::Base+ and live in +app/mailers+. Those mailers have associated views that appear alongside controller views in +app/views+. +Action Mailer allows you to send emails from your application using a mailer model and views. So, in Rails, emails are used by creating mailers that inherit from +ActionMailer::Base+ and live in +app/mailers+. Those mailers have associated views that appear alongside controller views in +app/views+. h3. Sending Emails @@ -48,10 +48,8 @@ class UserMailer < ActionMailer::Base def welcome_email(user) @user = user @url = "http://example.com/login" - mail(:to => user.email, - :subject => "Welcome to My Awesome Site") + mail(:to => user.email, :subject => "Welcome to My Awesome Site") end - end @@ -142,17 +140,17 @@ end This provides a much simpler implementation that does not require the registering of observers and the like. -The method +welcome_email+ returns a Mail::Message object which can then just be told +deliver+ to send itself out. +The method +welcome_email+ returns a Mail::Message object which can then just be told +deliver+ to send itself out. NOTE: In previous versions of Rails, you would call +deliver_welcome_email+ or +create_welcome_email+. This has been deprecated in Rails 3.0 in favour of just calling the method name itself. -WARNING: Sending out one email should only take a fraction of a second, if you are planning on sending out many emails, or you have a slow domain resolution service, you might want to investigate using a background process like delayed job. +WARNING: Sending out an email should only take a fraction of a second, but if you are planning on sending out many emails, or you have a slow domain resolution service, you might want to investigate using a background process like Delayed Job. h4. Auto encoding header values Action Mailer now handles the auto encoding of multibyte characters inside of headers and bodies. -If you are using UTF-8 as your character set, you do not have to do anything special, just go ahead and send in UTF-8 data to the address fields, subject, keywords, filenames or body of the email and ActionMailer will auto encode it into quoted printable for you in the case of a header field or Base64 encode any body parts that are non US-ASCII. +If you are using UTF-8 as your character set, you do not have to do anything special, just go ahead and send in UTF-8 data to the address fields, subject, keywords, filenames or body of the email and Action Mailer will auto encode it into quoted printable for you in the case of a header field or Base64 encode any body parts that are non US-ASCII. For more complex examples such as defining alternate character sets or self encoding text first, please refer to the Mail library. @@ -213,7 +211,7 @@ NOTE: If you specify an encoding, Mail will assume that your content is already h5. Making Inline Attachments -ActionMailer 3.0 makes inline attachments, which involved a lot of hacking in pre 3.0 versions, much simpler and trivial as they should be. +Action Mailer 3.0 makes inline attachments, which involved a lot of hacking in pre 3.0 versions, much simpler and trivial as they should be. * Firstly, to tell Mail to turn an attachment into an inline attachment, you just call #inline on the attachments method within your Mailer: @@ -245,15 +243,15 @@ h5. Sending Email To Multiple Recipients It is possible to send email to one or more recipients in one email (for e.g. informing all admins of a new signup) by setting the list of emails to the :to key. The list of emails can be an array of email addresses or a single string with the addresses separated by commas. - class AdminMailer < ActionMailer::Base - default :to => Admin.all.map(&:email), - :from => "notification@example.com" +class AdminMailer < ActionMailer::Base + default :to => Admin.all.map(&:email), + :from => "notification@example.com" - def new_registration(user) - @user = user - mail(:subject => "New User Signup: #{@user.email}") - end + def new_registration(user) + @user = user + mail(:subject => "New User Signup: #{@user.email}") end +end The same format can be used to set carbon copy (Cc:) and blind carbon copy (Bcc:) recipients, by using the :cc and :bcc keys respectively. @@ -264,12 +262,11 @@ Sometimes you wish to show the name of the person instead of just their email ad to format the email address in the format "Name <email>". - def welcome_email(user) - @user = user - email_with_name = "#{@user.name} <#{@user.email}>" - mail(:to => email_with_name, - :subject => "Welcome to My Awesome Site") - end +def welcome_email(user) + @user = user + email_with_name = "#{@user.name} <#{@user.email}>" + mail(:to => email_with_name, :subject => "Welcome to My Awesome Site") +end h4. Mailer Views @@ -289,9 +286,7 @@ class UserMailer < ActionMailer::Base :subject => "Welcome to My Awesome Site", :template_path => 'notifications', :template_name => 'another') - end end - end @@ -461,14 +456,14 @@ h3. Action Mailer Configuration The following configuration options are best made in one of the environment files (environment.rb, production.rb, etc...) -|template_root|Determines the base from which template references will be made.| -|logger|Generates information on the mailing run if available. Can be set to nil for no logging. Compatible with both Ruby's own Logger and Log4r loggers.| -|smtp_settings|Allows detailed configuration for :smtp delivery method:
  • :address - Allows you to use a remote mail server. Just change it from its default "localhost" setting.
  • :port - On the off chance that your mail server doesn't run on port 25, you can change it.
  • :domain - If you need to specify a HELO domain, you can do it here.
  • :user_name - If your mail server requires authentication, set the username in this setting.
  • :password - If your mail server requires authentication, set the password in this setting.
  • :authentication - If your mail server requires authentication, you need to specify the authentication type here. This is a symbol and one of :plain, :login, :cram_md5.
| -|sendmail_settings|Allows you to override options for the :sendmail delivery method.
  • :location - The location of the sendmail executable. Defaults to /usr/sbin/sendmail.
  • :arguments - The command line arguments to be passed to sendmail. Defaults to -i -t.
| -|raise_delivery_errors|Whether or not errors should be raised if the email fails to be delivered.| -|delivery_method|Defines a delivery method. Possible values are :smtp (default), :sendmail, :file and :test.| -|perform_deliveries|Determines whether deliveries are actually carried out when the +deliver+ method is invoked on the Mail message. By default they are, but this can be turned off to help functional testing.| -|deliveries|Keeps an array of all the emails sent out through the Action Mailer with delivery_method :test. Most useful for unit and functional testing.| +|+template_root+|Determines the base from which template references will be made.| +|+logger+|Generates information on the mailing run if available. Can be set to +nil+ for no logging. Compatible with both Ruby's own +Logger+ and +Log4r+ loggers.| +|+smtp_settings+|Allows detailed configuration for :smtp delivery method:
  • :address - Allows you to use a remote mail server. Just change it from its default "localhost" setting.
  • :port - On the off chance that your mail server doesn't run on port 25, you can change it.
  • :domain - If you need to specify a HELO domain, you can do it here.
  • :user_name - If your mail server requires authentication, set the username in this setting.
  • :password - If your mail server requires authentication, set the password in this setting.
  • :authentication - If your mail server requires authentication, you need to specify the authentication type here. This is a symbol and one of :plain, :login, :cram_md5.
| +|+sendmail_settings+|Allows you to override options for the :sendmail delivery method.
  • :location - The location of the sendmail executable. Defaults to /usr/sbin/sendmail.
  • :arguments - The command line arguments to be passed to sendmail. Defaults to -i -t.
| +|+raise_delivery_errors+|Whether or not errors should be raised if the email fails to be delivered.| +|+delivery_method+|Defines a delivery method. Possible values are :smtp (default), :sendmail, :file and :test.| +|+perform_deliveries+|Determines whether deliveries are actually carried out when the +deliver+ method is invoked on the Mail message. By default they are, but this can be turned off to help functional testing.| +|+deliveries+|Keeps an array of all the emails sent out through the Action Mailer with delivery_method :test. Most useful for unit and functional testing.| h4. Example Action Mailer Configuration From 0b3b91cdcdfd54fc4a9e9bcb6be95ff487724e25 Mon Sep 17 00:00:00 2001 From: Sebastian Martinez Date: Fri, 19 Aug 2011 19:45:55 -0300 Subject: [PATCH 247/345] Document debugging assets set by default for dev and test envs in the asset_pipeline guide. --- railties/guides/source/asset_pipeline.textile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/railties/guides/source/asset_pipeline.textile b/railties/guides/source/asset_pipeline.textile index 8094ba18f2..34ab00e80d 100644 --- a/railties/guides/source/asset_pipeline.textile +++ b/railties/guides/source/asset_pipeline.textile @@ -247,6 +247,8 @@ When the +debug_assets+ parameter is set, this line is expanded out into three s This allows the individual parts of an asset to be rendered and debugged separately. +NOTE. Assets debugging is turned on by default in development and test environments. + h3. In Production In the production environment, assets are served slightly differently. From 31d38d37d394f6ebbac57ce48f465805edbfec04 Mon Sep 17 00:00:00 2001 From: dharmatech Date: Sat, 20 Aug 2011 00:07:34 -0500 Subject: [PATCH 248/345] ActionController::Redirecting : fix docs typo --- actionpack/lib/action_controller/metal/redirecting.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/action_controller/metal/redirecting.rb b/actionpack/lib/action_controller/metal/redirecting.rb index dee7eb1ec8..4f311a1cf5 100644 --- a/actionpack/lib/action_controller/metal/redirecting.rb +++ b/actionpack/lib/action_controller/metal/redirecting.rb @@ -45,7 +45,7 @@ module ActionController # integer, or a symbol representing the downcased, underscored and symbolized description. # Note that the status code must be a 3xx HTTP code, or redirection will not occur. # - # It is also possible to assign a flash message as part of the redirection. There are two special accessors for commonly used the flash names + # It is also possible to assign a flash message as part of the redirection. There are two special accessors for the commonly used flash names # +alert+ and +notice+ as well as a general purpose +flash+ bucket. # # Examples: From dfd03fdbd32d25ef0f70e40ab7cb3794b1ffe0c0 Mon Sep 17 00:00:00 2001 From: dharmatech Date: Sat, 20 Aug 2011 00:17:44 -0500 Subject: [PATCH 249/345] actionpack/lib/action_controller/base.rb: docs typo --- actionpack/lib/action_controller/base.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index ce56d8bc71..da93c988c4 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -63,7 +63,7 @@ module ActionController # # == Sessions # - # Sessions allows you to store objects in between requests. This is useful for objects that are not yet ready to be persisted, + # Sessions allow you to store objects in between requests. This is useful for objects that are not yet ready to be persisted, # such as a Signup object constructed in a multi-paged process, or objects that don't change much and are needed all the time, such # as a User object for a system that requires login. The session should not be used, however, as a cache for objects where it's likely # they could be changed unknowingly. It's usually too much work to keep it all synchronized -- something databases already excel at. From e2ae015952c5bdcca044504b5be1c13a518eeaac Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Sat, 20 Aug 2011 13:00:26 -0400 Subject: [PATCH 250/345] Fix assumption of primary key name in PredicateBuilder subquery. --- .../lib/active_record/relation/predicate_builder.rb | 2 +- activerecord/test/cases/relations_test.rb | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb index 2814771002..dc8667b5cd 100644 --- a/activerecord/lib/active_record/relation/predicate_builder.rb +++ b/activerecord/lib/active_record/relation/predicate_builder.rb @@ -19,7 +19,7 @@ module ActiveRecord case value when ActiveRecord::Relation - value.select_values = [value.klass.arel_table['id']] if value.select_values.empty? + value.select_values = [value.klass.arel_table[value.klass.primary_key]] if value.select_values.empty? attribute.in(value.arel.ast) when Array, ActiveRecord::Associations::CollectionProxy values = value.to_a.map { |x| diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index 97abd67385..711b07b113 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -540,6 +540,16 @@ class RelationTest < ActiveRecord::TestCase } end + def test_find_all_using_where_with_relation_and_alternate_primary_key + cool_first = minivans(:cool_first) + # switching the lines below would succeed in current rails + # assert_queries(2) { + assert_queries(1) { + relation = Minivan.where(:minivan_id => Minivan.where(:name => cool_first.name)) + assert_equal [cool_first], relation.all + } + end + def test_find_all_using_where_with_relation_with_joins david = authors(:david) assert_queries(1) { From f74f5f7f00bd591fbca0cbc2b847acb0ec420256 Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Sat, 20 Aug 2011 13:16:39 -0400 Subject: [PATCH 251/345] Fix PredicateBuilder clobbering select_values in subquery. --- .../lib/active_record/relation/predicate_builder.rb | 2 +- activerecord/test/cases/relations_test.rb | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb index dc8667b5cd..7e8ddd1b5d 100644 --- a/activerecord/lib/active_record/relation/predicate_builder.rb +++ b/activerecord/lib/active_record/relation/predicate_builder.rb @@ -19,7 +19,7 @@ module ActiveRecord case value when ActiveRecord::Relation - value.select_values = [value.klass.arel_table[value.klass.primary_key]] if value.select_values.empty? + value = value.select(value.klass.arel_table[value.klass.primary_key]) if value.select_values.empty? attribute.in(value.arel.ast) when Array, ActiveRecord::Associations::CollectionProxy values = value.to_a.map { |x| diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index 711b07b113..615551a279 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -550,6 +550,19 @@ class RelationTest < ActiveRecord::TestCase } end + def test_find_all_using_where_with_relation_does_not_alter_select_values + david = authors(:david) + + subquery = Author.where(:id => david.id) + + assert_queries(1) { + relation = Author.where(:id => subquery) + assert_equal [david], relation.all + } + + assert_equal 0, subquery.select_values.size + end + def test_find_all_using_where_with_relation_with_joins david = authors(:david) assert_queries(1) { From 7444c620cfa88d4ffade121bbbad0d4699c36f8a Mon Sep 17 00:00:00 2001 From: Vijay Dev Date: Sat, 20 Aug 2011 23:27:31 +0530 Subject: [PATCH 252/345] minor change in the 3.1 release notes --- railties/guides/source/3_1_release_notes.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/guides/source/3_1_release_notes.textile b/railties/guides/source/3_1_release_notes.textile index ba36735a0b..087926f98d 100644 --- a/railties/guides/source/3_1_release_notes.textile +++ b/railties/guides/source/3_1_release_notes.textile @@ -115,7 +115,7 @@ h4. Action Controller * URL parameters which return +nil+ for +to_param+ are now removed from the query string. -* Added ActionController::ParamsWrapper to wrap parameters into a nested hash, and will be turned on for JSON request in new applications by default. This can be customized by setting ActionController::Base.wrap_parameters in config/initializer/wrap_parameters.rb. +* Added ActionController::ParamsWrapper to wrap parameters into a nested hash, and will be turned on for JSON request in new applications by default. This can be customized in config/initializers/wrap_parameters.rb. * Added config.action_controller.include_all_helpers. By default helper :all is done in ActionController::Base, which includes all the helpers by default. Setting +include_all_helpers+ to +false+ will result in including only application_helper and the helper corresponding to controller (like foo_helper for foo_controller). From dbe9a9b48280e3210f6c42789c3a2980b72febf4 Mon Sep 17 00:00:00 2001 From: Alan Larkin Date: Sat, 20 Aug 2011 13:12:10 +0100 Subject: [PATCH 253/345] Updated the docs for the has_many :finder_sql option to reflect changes made in #a7e19b30ca71f62af516, i.e. the use of Procs when interpolation of the SQL is required. --- activerecord/lib/active_record/associations.rb | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 2605a54cb6..8d755b6848 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1087,7 +1087,8 @@ module ActiveRecord # # [:finder_sql] # Specify a complete SQL statement to fetch the association. This is a good way to go for complex - # associations that depend on multiple tables. Note: When this option is used, +find_in_collection+ + # associations that depend on multiple tables. May be supplied as a string or a proc where interpolation is + # required. Note: When this option is used, +find_in_collection+ # is _not_ added. # [:counter_sql] # Specify a complete SQL statement to fetch the size of the association. If :finder_sql is @@ -1162,11 +1163,14 @@ module ActiveRecord # has_many :tags, :as => :taggable # has_many :reports, :readonly => true # has_many :subscribers, :through => :subscriptions, :source => :user - # has_many :subscribers, :class_name => "Person", :finder_sql => - # 'SELECT DISTINCT people.* ' + - # 'FROM people p, post_subscriptions ps ' + - # 'WHERE ps.post_id = #{id} AND ps.person_id = p.id ' + - # 'ORDER BY p.first_name' + # has_many :subscribers, :class_name => "Person", :finder_sql => Proc.new { + # %Q{ + # SELECT DISTINCT people.* + # FROM people p, post_subscriptions ps + # WHERE ps.post_id = #{id} AND ps.person_id = p.id + # ORDER BY p.first_name + # } + # } def has_many(name, options = {}, &extension) Builder::HasMany.build(self, name, options, &extension) end From 7da70a431c3c122d3b9425472635bf8368363525 Mon Sep 17 00:00:00 2001 From: Vijay Dev Date: Sat, 20 Aug 2011 23:49:57 +0530 Subject: [PATCH 254/345] params wrapper docs correction --- actionpack/lib/action_controller/metal/params_wrapper.rb | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/actionpack/lib/action_controller/metal/params_wrapper.rb b/actionpack/lib/action_controller/metal/params_wrapper.rb index 2d8afc3a78..f24203db3a 100644 --- a/actionpack/lib/action_controller/metal/params_wrapper.rb +++ b/actionpack/lib/action_controller/metal/params_wrapper.rb @@ -9,10 +9,9 @@ module ActionController # Wraps parameters hash into nested hash. This will allow client to submit # POST request without having to specify a root element in it. # - # By default this functionality won't be enabled. You can enable - # it globally by setting +ActionController::Base.wrap_parameters+: - # - # ActionController::Base.wrap_parameters = [:json] + # This functionality is enabled in +config/initializers/wrap_parameters.rb+ + # and can be customized. If you are upgrading to Rails 3.1, this file will + # need to be created for the functionality to be enabled. # # You could also turn it on per controller by setting the format array to # non-empty array: From 4fb4484cad22e3a3e3cbdcee6c8c5c1c309e4fbb Mon Sep 17 00:00:00 2001 From: Guillermo Iguaran Date: Sat, 20 Aug 2011 15:57:24 -0500 Subject: [PATCH 255/345] Add .rbenv-version to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 2d3c39d885..a5bedb78e1 100644 --- a/.gitignore +++ b/.gitignore @@ -21,4 +21,5 @@ railties/doc railties/guides/output railties/tmp .rvmrc +.rbenv-version RDOC_MAIN.rdoc From f71c481545b8a29c1e8a04f3487c4ef74096d9ce Mon Sep 17 00:00:00 2001 From: Guillermo Iguaran Date: Sat, 20 Aug 2011 17:10:15 -0500 Subject: [PATCH 256/345] Bump sprockets to 2.0.0.beta.14 --- actionpack/actionpack.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec index 620fdc4a72..02758148c0 100644 --- a/actionpack/actionpack.gemspec +++ b/actionpack/actionpack.gemspec @@ -24,7 +24,7 @@ Gem::Specification.new do |s| s.add_dependency('rack', '~> 1.3.2') s.add_dependency('rack-test', '~> 0.6.0') s.add_dependency('rack-mount', '~> 0.8.1') - s.add_dependency('sprockets', '~> 2.0.0.beta.12') + s.add_dependency('sprockets', '~> 2.0.0.beta.14') s.add_dependency('erubis', '~> 2.7.0') s.add_development_dependency('tzinfo', '~> 0.3.29') From ebe91553136e809cd44f0b3ca98d92cda75bf6cd Mon Sep 17 00:00:00 2001 From: asmega Date: Sat, 20 Aug 2011 23:28:49 +0100 Subject: [PATCH 257/345] Use typewriter styling on url_for in documentation --- actionpack/lib/action_view/helpers/url_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb index 51baca8e03..4dbb0135f6 100644 --- a/actionpack/lib/action_view/helpers/url_helper.rb +++ b/actionpack/lib/action_view/helpers/url_helper.rb @@ -268,7 +268,7 @@ module ActionView # to change the HTTP verb used to submit the form. # # ==== Options - # The +options+ hash accepts the same options as url_for. + # The +options+ hash accepts the same options as +url_for+. # # There are a few special +html_options+: # * :method - Symbol of HTTP verb. Supported verbs are :post, :get, From f6ceb944eaea525362db38aa990cac3e6f76ac5a Mon Sep 17 00:00:00 2001 From: Teng Siong Ong Date: Sun, 21 Aug 2011 15:14:45 -0500 Subject: [PATCH 258/345] fix escape_javascript for unicode character \u2028. --- actionpack/lib/action_view/helpers/javascript_helper.rb | 5 +++-- actionpack/test/template/javascript_helper_test.rb | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/actionpack/lib/action_view/helpers/javascript_helper.rb b/actionpack/lib/action_view/helpers/javascript_helper.rb index 4484390fde..f1b071caf7 100644 --- a/actionpack/lib/action_view/helpers/javascript_helper.rb +++ b/actionpack/lib/action_view/helpers/javascript_helper.rb @@ -10,7 +10,8 @@ module ActionView "\n" => '\n', "\r" => '\n', '"' => '\\"', - "'" => "\\'" } + "'" => "\\'", + "\342\200\250" => '
' } # Escape carrier returns and single and double quotes for JavaScript segments. # Also available through the alias j(). This is particularly helpful in JavaScript responses, like: @@ -18,7 +19,7 @@ module ActionView # $('some_element').replaceWith('<%=j render 'some/element_template' %>'); def escape_javascript(javascript) if javascript - result = javascript.gsub(/(\\|<\/|\r\n|[\n\r"'])/) {|match| JS_ESCAPE_MAP[match] } + result = javascript.gsub(/(\\|<\/|\r\n|\342\200\250|[\n\r"'])/) {|match| JS_ESCAPE_MAP[match] } javascript.html_safe? ? result.html_safe : result else '' diff --git a/actionpack/test/template/javascript_helper_test.rb b/actionpack/test/template/javascript_helper_test.rb index dd8b7b7cd5..bab9d42472 100644 --- a/actionpack/test/template/javascript_helper_test.rb +++ b/actionpack/test/template/javascript_helper_test.rb @@ -27,6 +27,7 @@ class JavaScriptHelperTest < ActionView::TestCase assert_equal %(This \\"thing\\" is really\\n netos\\'), escape_javascript(%(This "thing" is really\n netos')) assert_equal %(backslash\\\\test), escape_javascript( %(backslash\\test) ) assert_equal %(dont <\\/close> tags), escape_javascript(%(dont tags)) + assert_equal %(unicode 
 newline), escape_javascript(%(unicode \342\200\250 newline)) assert_equal %(dont <\\/close> tags), j(%(dont tags)) end From 95bece9155c46a2273a3febc3a2e176b8c15df8f Mon Sep 17 00:00:00 2001 From: Joost Baaij Date: Mon, 22 Aug 2011 00:10:01 +0300 Subject: [PATCH 259/345] Removed my name from the changelog as the amount of blogspam became ridiculous. When will docrails be back? :-p --- railties/guides/source/getting_started.textile | 1 - 1 file changed, 1 deletion(-) diff --git a/railties/guides/source/getting_started.textile b/railties/guides/source/getting_started.textile index 092ca90a30..755f59f8f9 100644 --- a/railties/guides/source/getting_started.textile +++ b/railties/guides/source/getting_started.textile @@ -1890,7 +1890,6 @@ h3. Changelog * April 26, 2011: Change migration code from +up+, +down+ pair to +change+ method by "Prem Sichanugrist":http://sikachu.com * April 11, 2011: Change scaffold_controller generator to create format block for JSON instead of XML by "Sebastian Martinez":http://www.wyeworks.com -* August 30, 2010: Minor editing after Rails 3 release by "Joost Baaij":http://www.spacebabies.nl * July 12, 2010: Fixes, editing and updating of code samples by "Jaime Iniesta":http://jaimeiniesta.com * May 16, 2010: Added a section on configuration gotchas to address common encoding problems that people might have by "Yehuda Katz":http://www.yehudakatz.com * April 30, 2010: Fixes, editing and updating of code samples by "Rohit Arondekar":http://rohitarondekar.com From 63d3809e31cc9c0ed3b2e30617310407ae614fd4 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sun, 21 Aug 2011 16:42:06 -0500 Subject: [PATCH 260/345] Fix sprockets warnings Fixes #2598 --- actionpack/lib/sprockets/assets.rake | 9 ++++++--- actionpack/lib/sprockets/helpers/rails_helper.rb | 13 ++++++++++++- actionpack/lib/sprockets/railtie.rb | 5 ++--- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/actionpack/lib/sprockets/assets.rake b/actionpack/lib/sprockets/assets.rake index 4cf5caab91..acf2f256c2 100644 --- a/actionpack/lib/sprockets/assets.rake +++ b/actionpack/lib/sprockets/assets.rake @@ -13,17 +13,20 @@ namespace :assets do # Ensure that action view is loaded and the appropriate sprockets hooks get executed ActionView::Base - assets = Rails.application.config.assets.precompile # Always perform caching so that asset_path appends the timestamps to file references. Rails.application.config.action_controller.perform_caching = true + + config = Rails.application.config + assets = config.assets.precompile.dup + assets << {:to => File.join(Rails.public_path, config.assets.prefix)} Rails.application.assets.precompile(*assets) end end desc "Remove compiled assets" task :clean => [:environment, 'tmp:cache:clear'] do - assets = Rails.application.config.assets - public_asset_path = Rails.public_path + assets.prefix + config = Rails.application.config + public_asset_path = File.join(Rails.public_path, config.assets.prefix) rm_rf public_asset_path, :secure => true end end diff --git a/actionpack/lib/sprockets/helpers/rails_helper.rb b/actionpack/lib/sprockets/helpers/rails_helper.rb index a65c5992ca..69306ef631 100644 --- a/actionpack/lib/sprockets/helpers/rails_helper.rb +++ b/actionpack/lib/sprockets/helpers/rails_helper.rb @@ -112,11 +112,22 @@ module Sprockets asset_environment[source] end + def digest_for(logical_path) + if asset = asset_environment[logical_path] + return asset.digest_path + end + + logical_path + end + def rewrite_asset_path(source, dir) if source[0] == ?/ source else - asset_environment.path(source, performing_caching?, dir) + source = digest_for(source) if performing_caching? + source = File.join(dir, source) + source = "/#{url}" unless source =~ /^\// + source end end diff --git a/actionpack/lib/sprockets/railtie.rb b/actionpack/lib/sprockets/railtie.rb index 0a2c8c1ea3..c21bf57935 100644 --- a/actionpack/lib/sprockets/railtie.rb +++ b/actionpack/lib/sprockets/railtie.rb @@ -18,9 +18,8 @@ module Sprockets require 'sprockets' app.assets = Sprockets::Environment.new(app.root.to_s) do |env| - env.static_root = File.join(app.root.join('public'), config.assets.prefix) - env.logger = ::Rails.logger - env.version = ::Rails.env + "#{'-' + config.assets.version if config.assets.version.present?}" + env.logger = ::Rails.logger + env.version = ::Rails.env + "-#{config.assets.version}" if config.assets.cache_store != false env.cache = ActiveSupport::Cache.lookup_store(config.assets.cache_store) || ::Rails.cache From 18b2223b3290c4b3daa310edfc06b4d51161c312 Mon Sep 17 00:00:00 2001 From: "Andrey A.I. Sitnik" Date: Mon, 22 Aug 2011 09:36:36 +1100 Subject: [PATCH 261/345] Allow to debug assets by config.assets.debug --- .../lib/sprockets/helpers/rails_helper.rb | 10 ++++++---- .../test/template/sprockets_helper_test.rb | 20 ++++++------------- railties/guides/source/asset_pipeline.textile | 2 +- .../lib/rails/application/configuration.rb | 1 + .../config/environments/development.rb.tt | 3 +++ 5 files changed, 17 insertions(+), 19 deletions(-) diff --git a/actionpack/lib/sprockets/helpers/rails_helper.rb b/actionpack/lib/sprockets/helpers/rails_helper.rb index 69306ef631..38df9cbf6e 100644 --- a/actionpack/lib/sprockets/helpers/rails_helper.rb +++ b/actionpack/lib/sprockets/helpers/rails_helper.rb @@ -70,10 +70,12 @@ module Sprockets private def debug_assets? - Rails.env.development? || Rails.env.test? || - params[:debug_assets] == '1' || params[:debug_assets] == 'true' - rescue NoMethodError - false + begin + params[:debug_assets] == '1' || + params[:debug_assets] == 'true' + rescue NoMethodError + false + end || Rails.application.config.assets.debug end # Override to specify an alternative prefix for asset path generation. diff --git a/actionpack/test/template/sprockets_helper_test.rb b/actionpack/test/template/sprockets_helper_test.rb index d303acad0f..cac277cf11 100644 --- a/actionpack/test/template/sprockets_helper_test.rb +++ b/actionpack/test/template/sprockets_helper_test.rb @@ -141,8 +141,6 @@ class SprocketsHelperTest < ActionView::TestCase end test "javascript include tag" do - Rails.env.stubs(:test?).returns(false) - assert_match %r{}, javascript_include_tag(:application) @@ -156,14 +154,12 @@ class SprocketsHelperTest < ActionView::TestCase assert_match %r{\n}, javascript_include_tag("xmlhr", "extra") - Rails.env.stubs(:test?).returns(true) + assert_match %r{\n}, + javascript_include_tag(:application, :debug => true) + @config.assets.debug = true assert_match %r{\n}, javascript_include_tag(:application) - - assert_match %r{}, - javascript_include_tag(:application, :debug => false) - end test "stylesheet path" do @@ -180,8 +176,6 @@ class SprocketsHelperTest < ActionView::TestCase end test "stylesheet link tag" do - Rails.env.stubs(:test?).returns(false) - assert_match %r{}, stylesheet_link_tag(:application) @@ -200,14 +194,12 @@ class SprocketsHelperTest < ActionView::TestCase assert_match %r{\n}, stylesheet_link_tag("style", "extra") - Rails.env.stubs(:test?).returns(true) + assert_match %r{\n}, + stylesheet_link_tag(:application, :debug => true) + @config.assets.debug = true assert_match %r{\n}, stylesheet_link_tag(:application) - - assert_match %r{}, - stylesheet_link_tag(:application, :debug => false) - end test "alternate asset prefix" do diff --git a/railties/guides/source/asset_pipeline.textile b/railties/guides/source/asset_pipeline.textile index 34ab00e80d..012149c40e 100644 --- a/railties/guides/source/asset_pipeline.textile +++ b/railties/guides/source/asset_pipeline.textile @@ -224,7 +224,7 @@ If any of the files in the manifest have changed between requests, the server re h4. Debugging Assets -You can put +?debug_assets=true+ or +?debug_assets=1+ at the end of a URL and Sprockets expands the lines which load the assets. For example, if you had an +app/assets/javascripts/application.js+ file containing these lines: +You can put +?debug_assets=true+ or +?debug_assets=1+ at the end of a URL or set +config.assets.debug+ and Sprockets expands the lines which load the assets. For example, if you had an +app/assets/javascripts/application.js+ file containing these lines: //= require "projects" diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index cd850b6a75..f1add68890 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -38,6 +38,7 @@ module Rails @assets.precompile = [ /\w+\.(?!js|css).+/, /application.(css|js)$/ ] @assets.prefix = "/assets" @assets.version = '' + @assets.debug = false @assets.cache_store = [ :file_store, "#{root}/tmp/cache/assets/" ] @assets.js_compressor = nil diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt index 3e0c29a587..47078e3af9 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt @@ -29,4 +29,7 @@ # Do not compress assets config.assets.compress = false + + # Expands the lines which load the assets + config.assets.debug = true end From 35c8a896fc75c222834e1324fe4710c1ba2645c4 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sun, 21 Aug 2011 15:55:15 -0700 Subject: [PATCH 262/345] Merge pull request #2620 from cesario/3-1-0 Fix CI and rename 1 misleading test case. --- railties/test/generators/app_generator_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index fb7ebaa1fa..2415195a17 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -189,7 +189,7 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_file "test/performance/browsing_test.rb" end - def test_generator_if_skip_active_record_is_given + def test_generator_if_skip_sprockets_is_given run_generator [destination_root, "--skip-sprockets"] assert_file "config/application.rb" do |content| assert_match(/#\s+require\s+["']sprockets\/railtie["']/, content) From 44f0d94469fb6c5d400776c3307b16fb8e4d1eb1 Mon Sep 17 00:00:00 2001 From: Andrey Ognevsky Date: Sun, 21 Aug 2011 01:25:11 +0300 Subject: [PATCH 263/345] Add Destroy Alias * Added destroy alias to rails generator * add alias info for destroy command * Updated command line guides --- railties/guides/source/command_line.textile | 2 ++ railties/lib/rails/commands.rb | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/railties/guides/source/command_line.textile b/railties/guides/source/command_line.textile index 6d5132a1bf..f6b33d283c 100644 --- a/railties/guides/source/command_line.textile +++ b/railties/guides/source/command_line.textile @@ -325,6 +325,8 @@ h4. +rails destroy+ Think of +destroy+ as the opposite of +generate+. It'll figure out what generate did, and undo it. +You can also use the alias "d" to invoke the destroy command: rails d. + $ rails generate model Oops exists app/models/ diff --git a/railties/lib/rails/commands.rb b/railties/lib/rails/commands.rb index a21484e5cb..ada150ceec 100644 --- a/railties/lib/rails/commands.rb +++ b/railties/lib/rails/commands.rb @@ -4,6 +4,7 @@ ARGV << '--help' if ARGV.empty? aliases = { "g" => "generate", + "d" => "destroy", "c" => "console", "s" => "server", "db" => "dbconsole", @@ -87,7 +88,7 @@ The most common rails commands are: In addition to those, there are: application Generate the Rails application code - destroy Undo code generated with "generate" + destroy Undo code generated with "generate" (short-cut alias: "d") benchmarker See how fast a piece of code runs profiler Get profile information from a piece of code plugin Install a plugin From db181bddb646ff22c85218072ba5c69ca680dabd Mon Sep 17 00:00:00 2001 From: Daniel Schierbeck Date: Mon, 22 Aug 2011 16:50:33 +0200 Subject: [PATCH 264/345] Refactor Sprockets::Helpers::RailsHelper#performing_caching? No need for them lines to get so long! Also, move that comment into the method body where it belongs! --- actionpack/lib/sprockets/helpers/rails_helper.rb | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/actionpack/lib/sprockets/helpers/rails_helper.rb b/actionpack/lib/sprockets/helpers/rails_helper.rb index 69306ef631..cb01532449 100644 --- a/actionpack/lib/sprockets/helpers/rails_helper.rb +++ b/actionpack/lib/sprockets/helpers/rails_helper.rb @@ -139,9 +139,14 @@ module Sprockets end end - # When included in Sprockets::Context, we need to ask the top-level config as the controller is not available def performing_caching? - config.action_controller.present? ? config.action_controller.perform_caching : config.perform_caching + # When included in Sprockets::Context, we need to ask the + # top-level config as the controller is not available. + if config.action_controller.present? + config.action_controller.perform_caching + else + config.perform_caching + end end end end From e1f11ff37f79d72b3afd5b718529186f2bc1417f Mon Sep 17 00:00:00 2001 From: Guillermo Iguaran Date: Mon, 22 Aug 2011 11:12:54 -0500 Subject: [PATCH 265/345] Fix Sprockets rewrite_asset_path --- actionpack/lib/sprockets/helpers/rails_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/sprockets/helpers/rails_helper.rb b/actionpack/lib/sprockets/helpers/rails_helper.rb index cb01532449..c239af77bc 100644 --- a/actionpack/lib/sprockets/helpers/rails_helper.rb +++ b/actionpack/lib/sprockets/helpers/rails_helper.rb @@ -126,7 +126,7 @@ module Sprockets else source = digest_for(source) if performing_caching? source = File.join(dir, source) - source = "/#{url}" unless source =~ /^\// + source = "/#{source}" unless source =~ /^\// source end end From 71232f5d5d88d5390ff790b7b3336f5168e9f270 Mon Sep 17 00:00:00 2001 From: Anand Date: Mon, 22 Aug 2011 17:07:23 +0530 Subject: [PATCH 266/345] Travis status image added to GitHub README, excluding API pages. --- README.rdoc | 2 +- Rakefile | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/README.rdoc b/README.rdoc index 1e78799e83..f0aa962272 100644 --- a/README.rdoc +++ b/README.rdoc @@ -62,7 +62,7 @@ can read more about Action Pack in its {README}[link:/rails/rails/blob/master/ac * The {API Documentation}[http://api.rubyonrails.org]. -== Contributing +== Contributing http://travis-ci.org/rails/rails.png We encourage you to contribute to Ruby on Rails! Please check out the {Contributing to Rails guide}[http://edgeguides.rubyonrails.org/contributing_to_ruby_on_rails.html] for guidelines about how diff --git a/Rakefile b/Rakefile index 36007f6e91..4cf01cf063 100755 --- a/Rakefile +++ b/Rakefile @@ -76,6 +76,9 @@ RDoc::Task.new do |rdoc| rdoc_main.gsub!(/^(?=\S).*?\b(?=Rails)\b/) { "#$&\\" } rdoc_main.gsub!(%r{link:/rails/rails/blob/master/(\w+)/README\.rdoc}, "link:files/\\1/README_rdoc.html") + # Remove Travis build status image from API pages. Only GitHub README page gets this image + rdoc_main.gsub!("http://travis-ci.org/rails/rails.png", "") + File.open(RDOC_MAIN, 'w') do |f| f.write(rdoc_main) end From d17954c7d826b64ae7d04aac4db6f919d5e22589 Mon Sep 17 00:00:00 2001 From: Guillermo Iguaran Date: Mon, 22 Aug 2011 23:39:17 -0500 Subject: [PATCH 267/345] Add destroy alias to engines --- railties/lib/rails/engine/commands.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/railties/lib/rails/engine/commands.rb b/railties/lib/rails/engine/commands.rb index 3b0920e213..b71119af77 100644 --- a/railties/lib/rails/engine/commands.rb +++ b/railties/lib/rails/engine/commands.rb @@ -3,7 +3,8 @@ require 'active_support/core_ext/object/inclusion' ARGV << '--help' if ARGV.empty? aliases = { - "g" => "generate" + "g" => "generate", + "d" => "destroy" } command = ARGV.shift @@ -30,7 +31,7 @@ Usage: rails COMMAND [ARGS] The common rails commands available for engines are: generate Generate new code (short-cut alias: "g") - destroy Undo code generated with "generate" + destroy Undo code generated with "generate" (short-cut alias: "d") All commands can be run with -h for more information. EOT From 14cf4b2e353f923155aab1ae0eaafed3c2924b12 Mon Sep 17 00:00:00 2001 From: Andrew White Date: Tue, 23 Aug 2011 11:07:37 +0100 Subject: [PATCH 268/345] Don't modify params in place - fixes #2624 --- actionpack/lib/action_controller/test_case.rb | 8 +++----- actionpack/test/controller/test_test.rb | 6 ++++++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb index c8cf04bb69..a38e5a46da 100644 --- a/actionpack/lib/action_controller/test_case.rb +++ b/actionpack/lib/action_controller/test_case.rb @@ -401,9 +401,7 @@ module ActionController def paramify_values(hash_or_array_or_value) case hash_or_array_or_value when Hash - hash_or_array_or_value.each do |key, value| - hash_or_array_or_value[key] = paramify_values(value) - end + Hash[hash_or_array_or_value.map{|key, value| [key, paramify_values(value)] }] when Array hash_or_array_or_value.map {|i| paramify_values(i)} when Rack::Test::UploadedFile @@ -416,7 +414,7 @@ module ActionController def process(action, parameters = nil, session = nil, flash = nil, http_method = 'GET') # Ensure that numbers and symbols passed as params are converted to # proper params, as is the case when engaging rack. - paramify_values(parameters) + parameters = paramify_values(parameters) # Sanity check for required instance variables so we can give an # understandable error message. @@ -450,7 +448,7 @@ module ActionController @controller.params.merge!(parameters) build_request_uri(action, parameters) @controller.class.class_eval { include Testing } - @controller.recycle! + @controller.recycle! @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? diff --git a/actionpack/test/controller/test_test.rb b/actionpack/test/controller/test_test.rb index 043d44500a..eae5a3d472 100644 --- a/actionpack/test/controller/test_test.rb +++ b/actionpack/test/controller/test_test.rb @@ -515,6 +515,12 @@ XML ) end + def test_params_passing_doesnt_modify_in_place + page = {:name => "Page name", :month => 4, :year => 2004, :day => 6} + get :test_params, :page => page + assert_equal 2004, page[:year] + end + def test_id_converted_to_string get :test_params, :id => 20, :foo => Object.new assert_kind_of String, @request.path_parameters['id'] From 56e32ad40f8a1658c507ab0565767b82018369af Mon Sep 17 00:00:00 2001 From: Anand Date: Tue, 23 Aug 2011 16:03:58 +0530 Subject: [PATCH 269/345] added more tests for only-include and except-include options in serialization --- activemodel/test/cases/serialization_test.rb | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/activemodel/test/cases/serialization_test.rb b/activemodel/test/cases/serialization_test.rb index 5122f08eec..071cb9ff4e 100644 --- a/activemodel/test/cases/serialization_test.rb +++ b/activemodel/test/cases/serialization_test.rb @@ -114,8 +114,21 @@ class SerializationTest < ActiveModel::TestCase @user.friends.first.friends = [@user] expected = {"email"=>"david@example.com", "gender"=>"male", "name"=>"David", :friends=>[{"name"=>'Joe', "email"=>'joe@example.com', "gender"=>'male', - :friends => ["email"=>"david@example.com", "gender"=>"male", "name"=>"David"]}, + :friends => [{"email"=>"david@example.com", "gender"=>"male", "name"=>"David"}]}, {"name"=>'Sue', "email"=>'sue@example.com', "gender"=>'female', :friends => []}]} assert_equal expected , @user.serializable_hash(:include => {:friends => {:include => :friends}}) end + + def test_only_include + expected = {"name"=>"David", :friends => [{"name" => "Joe"}, {"name" => "Sue"}]} + assert_equal expected , @user.serializable_hash(:only => :name, :include => {:friends => {:only => :name}}) + end + + def test_except_include + expected = {"name"=>"David", "email"=>"david@example.com", + :friends => [{"name" => 'Joe', "email" => 'joe@example.com'}, + {"name" => "Sue", "email" => 'sue@example.com'}]} + assert_equal expected , @user.serializable_hash(:except => :gender, :include => {:friends => {:except => :gender}}) + end + end From cacdbb94374ebdc1c1fa5445467fca3d12ca31cd Mon Sep 17 00:00:00 2001 From: Daniel Schierbeck Date: Tue, 23 Aug 2011 12:39:07 +0200 Subject: [PATCH 270/345] Remove trailing whitespace --- activesupport/test/core_ext/array_ext_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/activesupport/test/core_ext/array_ext_test.rb b/activesupport/test/core_ext/array_ext_test.rb index f035505a01..52231aaeb0 100644 --- a/activesupport/test/core_ext/array_ext_test.rb +++ b/activesupport/test/core_ext/array_ext_test.rb @@ -470,8 +470,8 @@ class ArrayPrependAppendTest < Test::Unit::TestCase def test_append assert_equal [1, 2], [1].append(2) end - + def test_prepend assert_equal [2, 1], [1].prepend(2) end -end \ No newline at end of file +end From 1be3442a0a6df37525ff706fecfd65de7eae65cf Mon Sep 17 00:00:00 2001 From: Anand Date: Tue, 23 Aug 2011 16:30:02 +0530 Subject: [PATCH 271/345] added missing require array/wrap in serialization --- activemodel/lib/active_model/serialization.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/activemodel/lib/active_model/serialization.rb b/activemodel/lib/active_model/serialization.rb index 9260c5082d..b9f6f6cbbf 100644 --- a/activemodel/lib/active_model/serialization.rb +++ b/activemodel/lib/active_model/serialization.rb @@ -1,5 +1,7 @@ require 'active_support/core_ext/hash/except' require 'active_support/core_ext/hash/slice' +require 'active_support/core_ext/array/wrap' + module ActiveModel # == Active Model Serialization From c46befbce300722650e324047a9342f628acc36d Mon Sep 17 00:00:00 2001 From: Joost Baaij Date: Tue, 23 Aug 2011 14:17:29 +0200 Subject: [PATCH 272/345] Revert "Removed my name from the changelog as the amount of blogspam became ridiculous. " This reverts commit 95bece9155c46a2273a3febc3a2e176b8c15df8f. --- railties/guides/source/getting_started.textile | 1 + 1 file changed, 1 insertion(+) diff --git a/railties/guides/source/getting_started.textile b/railties/guides/source/getting_started.textile index 755f59f8f9..092ca90a30 100644 --- a/railties/guides/source/getting_started.textile +++ b/railties/guides/source/getting_started.textile @@ -1890,6 +1890,7 @@ h3. Changelog * April 26, 2011: Change migration code from +up+, +down+ pair to +change+ method by "Prem Sichanugrist":http://sikachu.com * April 11, 2011: Change scaffold_controller generator to create format block for JSON instead of XML by "Sebastian Martinez":http://www.wyeworks.com +* August 30, 2010: Minor editing after Rails 3 release by "Joost Baaij":http://www.spacebabies.nl * July 12, 2010: Fixes, editing and updating of code samples by "Jaime Iniesta":http://jaimeiniesta.com * May 16, 2010: Added a section on configuration gotchas to address common encoding problems that people might have by "Yehuda Katz":http://www.yehudakatz.com * April 30, 2010: Fixes, editing and updating of code samples by "Rohit Arondekar":http://rohitarondekar.com From 707378c4892a4666c8b7ed73bef577338bca3c38 Mon Sep 17 00:00:00 2001 From: Joost Baaij Date: Tue, 23 Aug 2011 14:18:06 +0200 Subject: [PATCH 273/345] removed the link to my blog to help stop endless comments --- railties/guides/source/getting_started.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/guides/source/getting_started.textile b/railties/guides/source/getting_started.textile index 092ca90a30..d2bfcfdbb4 100644 --- a/railties/guides/source/getting_started.textile +++ b/railties/guides/source/getting_started.textile @@ -1890,7 +1890,7 @@ h3. Changelog * April 26, 2011: Change migration code from +up+, +down+ pair to +change+ method by "Prem Sichanugrist":http://sikachu.com * April 11, 2011: Change scaffold_controller generator to create format block for JSON instead of XML by "Sebastian Martinez":http://www.wyeworks.com -* August 30, 2010: Minor editing after Rails 3 release by "Joost Baaij":http://www.spacebabies.nl +* August 30, 2010: Minor editing after Rails 3 release by Joost Baaij * July 12, 2010: Fixes, editing and updating of code samples by "Jaime Iniesta":http://jaimeiniesta.com * May 16, 2010: Added a section on configuration gotchas to address common encoding problems that people might have by "Yehuda Katz":http://www.yehudakatz.com * April 30, 2010: Fixes, editing and updating of code samples by "Rohit Arondekar":http://rohitarondekar.com From 13400ac289344dae002c77a3c2b820268f08745e Mon Sep 17 00:00:00 2001 From: Andrew White Date: Tue, 23 Aug 2011 14:55:31 +0100 Subject: [PATCH 274/345] Ensure regexp and hash key are UTF-8 --- .../lib/action_view/helpers/javascript_helper.rb | 13 ++++++++++--- actionpack/test/template/javascript_helper_test.rb | 7 ++++++- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/actionpack/lib/action_view/helpers/javascript_helper.rb b/actionpack/lib/action_view/helpers/javascript_helper.rb index f1b071caf7..474ea53f91 100644 --- a/actionpack/lib/action_view/helpers/javascript_helper.rb +++ b/actionpack/lib/action_view/helpers/javascript_helper.rb @@ -1,4 +1,5 @@ require 'action_view/helpers/tag_helper' +require 'active_support/core_ext/string/encoding' module ActionView module Helpers @@ -10,8 +11,14 @@ module ActionView "\n" => '\n', "\r" => '\n', '"' => '\\"', - "'" => "\\'", - "\342\200\250" => '
' } + "'" => "\\'" + } + + if "ruby".encoding_aware? + JS_ESCAPE_MAP["\342\200\250".force_encoding('UTF-8').encode!] = '
' + else + JS_ESCAPE_MAP["\342\200\250"] = '
' + end # Escape carrier returns and single and double quotes for JavaScript segments. # Also available through the alias j(). This is particularly helpful in JavaScript responses, like: @@ -19,7 +26,7 @@ module ActionView # $('some_element').replaceWith('<%=j render 'some/element_template' %>'); def escape_javascript(javascript) if javascript - result = javascript.gsub(/(\\|<\/|\r\n|\342\200\250|[\n\r"'])/) {|match| JS_ESCAPE_MAP[match] } + result = javascript.gsub(/(\\|<\/|\r\n|\342\200\250|[\n\r"'])/u) {|match| JS_ESCAPE_MAP[match] } javascript.html_safe? ? result.html_safe : result else '' diff --git a/actionpack/test/template/javascript_helper_test.rb b/actionpack/test/template/javascript_helper_test.rb index bab9d42472..4b9c3c97b1 100644 --- a/actionpack/test/template/javascript_helper_test.rb +++ b/actionpack/test/template/javascript_helper_test.rb @@ -1,4 +1,5 @@ require 'abstract_unit' +require 'active_support/core_ext/string/encoding' class JavaScriptHelperTest < ActionView::TestCase tests ActionView::Helpers::JavaScriptHelper @@ -27,7 +28,11 @@ class JavaScriptHelperTest < ActionView::TestCase assert_equal %(This \\"thing\\" is really\\n netos\\'), escape_javascript(%(This "thing" is really\n netos')) assert_equal %(backslash\\\\test), escape_javascript( %(backslash\\test) ) assert_equal %(dont <\\/close> tags), escape_javascript(%(dont tags)) - assert_equal %(unicode 
 newline), escape_javascript(%(unicode \342\200\250 newline)) + if "ruby".encoding_aware? + assert_equal %(unicode 
 newline), escape_javascript(%(unicode \342\200\250 newline).force_encoding('UTF-8').encode!) + else + assert_equal %(unicode 
 newline), escape_javascript(%(unicode \342\200\250 newline)) + end assert_equal %(dont <\\/close> tags), j(%(dont tags)) end From ebea387e4bb9f44d8c678ed9bad2ab2091d1f9c6 Mon Sep 17 00:00:00 2001 From: Andrew White Date: Tue, 23 Aug 2011 15:33:59 +0100 Subject: [PATCH 275/345] Add failing test case for #2654 --- actionpack/test/controller/test_test.rb | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/actionpack/test/controller/test_test.rb b/actionpack/test/controller/test_test.rb index eae5a3d472..cba3aded2f 100644 --- a/actionpack/test/controller/test_test.rb +++ b/actionpack/test/controller/test_test.rb @@ -50,6 +50,10 @@ class TestTest < ActionController::TestCase render :text => request.query_string end + def test_protocol + render :text => request.protocol + end + def test_html_output render :text => < @@ -598,6 +602,19 @@ XML assert_nil @request.symbolized_path_parameters[:id] end + def test_request_protocol_is_reset_after_request + get :test_protocol + assert_equal "http://", @response.body + + @request.env["HTTPS"] = "on" + get :test_protocol + assert_equal "https://", @response.body + + @request.env.delete("HTTPS") + get :test_protocol + assert_equal "http://", @response.body + end + def test_should_have_knowledge_of_client_side_cookie_state_even_if_they_are_not_set cookies['foo'] = 'bar' get :no_op From 68a13eded347248fb9d4c8ef7f0ed2af52bba994 Mon Sep 17 00:00:00 2001 From: David Majda Date: Tue, 23 Aug 2011 14:12:41 +0200 Subject: [PATCH 276/345] Make ActionController::TestCase#recycle! set @protocol to nil This ensures that the protocol does not get carried over when there are two or more requests in functional tests. This was a problem when e.g. the first request was HTTP and the second request was HTTPS. Closes #2654. Signed-off-by: Andrew White --- actionpack/lib/action_controller/test_case.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb index a38e5a46da..40332da321 100644 --- a/actionpack/lib/action_controller/test_case.rb +++ b/actionpack/lib/action_controller/test_case.rb @@ -180,7 +180,7 @@ module ActionController @env.delete_if { |k, v| k =~ /^action_dispatch\.rescue/ } @symbolized_path_params = nil @method = @request_method = nil - @fullpath = @ip = @remote_ip = nil + @fullpath = @ip = @remote_ip = @protocol = nil @env['action_dispatch.request.query_parameters'] = {} @set_cookies ||= {} @set_cookies.update(Hash[cookie_jar.instance_variable_get("@set_cookies").map{ |k,o| [k,o[:value]] }]) From a10606c490471d8e1483acb3b31d7f2d51e9ebbe Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 23 Aug 2011 16:55:11 -0700 Subject: [PATCH 277/345] require needs to return true or false. thank you Ryan "zenspider" Davis --- activesupport/lib/active_support/dependencies.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb index 3f6c93e860..cc6e811224 100644 --- a/activesupport/lib/active_support/dependencies.rb +++ b/activesupport/lib/active_support/dependencies.rb @@ -233,7 +233,9 @@ module ActiveSupport #:nodoc: end def require(file, *) - load_dependency(file) { super } + result = false + load_dependency(file) { result = super } + result end # Mark the given constant as unloadable. Unloadable constants are removed each From 29004de1a2ded5e8705d421ffe60ff6f631110b1 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 23 Aug 2011 17:04:05 -0700 Subject: [PATCH 278/345] `load` should also return the value from `super` --- activesupport/lib/active_support/dependencies.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb index cc6e811224..6252e7f7c3 100644 --- a/activesupport/lib/active_support/dependencies.rb +++ b/activesupport/lib/active_support/dependencies.rb @@ -229,7 +229,9 @@ module ActiveSupport #:nodoc: end def load(file, *) - load_dependency(file) { super } + result = false + load_dependency(file) { result = super } + result end def require(file, *) From d133fd6d290a4812a17cc58c0d7e5cd3895e23f6 Mon Sep 17 00:00:00 2001 From: Guillermo Iguaran Date: Tue, 23 Aug 2011 21:36:21 -0500 Subject: [PATCH 279/345] Debug assets shouldn't ignore media type for stylesheets. Closes #2625 --- actionpack/lib/sprockets/helpers/rails_helper.rb | 5 +++-- actionpack/test/template/sprockets_helper_test.rb | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/actionpack/lib/sprockets/helpers/rails_helper.rb b/actionpack/lib/sprockets/helpers/rails_helper.rb index 7200ab1ddd..051624d05e 100644 --- a/actionpack/lib/sprockets/helpers/rails_helper.rb +++ b/actionpack/lib/sprockets/helpers/rails_helper.rb @@ -43,17 +43,18 @@ module Sprockets options = sources.extract_options! debug = options.key?(:debug) ? options.delete(:debug) : debug_assets? body = options.key?(:body) ? options.delete(:body) : false + media = options.key?(:media) ? options.delete(:media) : "screen" sources.collect do |source| if debug && asset = asset_paths.asset_for(source, 'css') asset.to_a.map { |dep| - stylesheet_link_tag(dep, :debug => false, :body => true) + stylesheet_link_tag(dep, :media => media, :debug => false, :body => true) }.join("\n").html_safe else tag_options = { 'rel' => "stylesheet", 'type' => "text/css", - 'media' => "screen", + 'media' => media, 'href' => asset_path(source, 'css', body, :request) }.merge(options.stringify_keys) diff --git a/actionpack/test/template/sprockets_helper_test.rb b/actionpack/test/template/sprockets_helper_test.rb index cac277cf11..b5a0e6cf04 100644 --- a/actionpack/test/template/sprockets_helper_test.rb +++ b/actionpack/test/template/sprockets_helper_test.rb @@ -200,6 +200,9 @@ class SprocketsHelperTest < ActionView::TestCase @config.assets.debug = true assert_match %r{\n}, stylesheet_link_tag(:application) + + assert_match %r{\n}, + stylesheet_link_tag(:application, :media => "print") end test "alternate asset prefix" do From 11146f1485ac83950c1079a458bd5fbae6ab405b Mon Sep 17 00:00:00 2001 From: Brian Morearty Date: Tue, 23 Aug 2011 21:34:43 -0700 Subject: [PATCH 280/345] Remove extra word from sentence in initialization guide. --- railties/guides/source/initialization.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/guides/source/initialization.textile b/railties/guides/source/initialization.textile index b93c4f35ac..9cc4dd5f04 100644 --- a/railties/guides/source/initialization.textile +++ b/railties/guides/source/initialization.textile @@ -1,6 +1,6 @@ h2. The Rails Initialization Process -This guide explains the internals of the initialization process in Rails works as of Rails 3.1. It is an extremely in-depth guide and recommended for advanced Rails developers. +This guide explains the internals of the initialization process in Rails as of Rails 3.1. It is an extremely in-depth guide and recommended for advanced Rails developers. * Using +rails server+ * Using Passenger From a5e925c1d35ff10a22a98841f6a02925d4263947 Mon Sep 17 00:00:00 2001 From: Bogdan Gusiev Date: Wed, 24 Aug 2011 10:25:29 +0300 Subject: [PATCH 281/345] Add strict validation example to guides --- railties/guides/source/active_model_basics.textile | 7 +++++-- .../source/active_record_validations_callbacks.textile | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/railties/guides/source/active_model_basics.textile b/railties/guides/source/active_model_basics.textile index f3a2b2edbc..7d435456bd 100644 --- a/railties/guides/source/active_model_basics.textile +++ b/railties/guides/source/active_model_basics.textile @@ -184,20 +184,23 @@ Validations module adds the ability to class objects to validate them in Active class Person include ActiveModel::Validations - attr_accessor :name, :email + attr_accessor :name, :email, :token validates :name, :presence => true validates_format_of :email, :with => /^([^\s]+)((?:[-a-z0-9]\.)[a-z]{2,})$/i + validates! :token, :presence => true end -person = Person.new +person = Person.new(:token => "2b1f325") person.valid? #=> false person.name = 'vishnu' person.email = 'me' person.valid? #=> false person.email = 'me@vishnuatrai.com' person.valid? #=> true +person.token = nil +person.valid? #=> raises ActiveModel::StrictValidationFailed h3. Changelog diff --git a/railties/guides/source/active_record_validations_callbacks.textile b/railties/guides/source/active_record_validations_callbacks.textile index aba3224ba7..18fc77c660 100644 --- a/railties/guides/source/active_record_validations_callbacks.textile +++ b/railties/guides/source/active_record_validations_callbacks.textile @@ -1270,6 +1270,7 @@ The +after_commit+ and +after_rollback+ callbacks are guaranteed to be called fo h3. Changelog +* August 24, 2011: Add strict validation usage example. "Bogdan Gusiev":http://gusiev.com * February 17, 2011: Add description of transaction callbacks. * July 20, 2010: Fixed typos and rephrased some paragraphs for clarity. "Jaime Iniesta":http://jaimeiniesta.com * May 24, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com From afe04da10b241434f7e1b4aed3d83b59971b379a Mon Sep 17 00:00:00 2001 From: Bogdan Gusiev Date: Wed, 24 Aug 2011 10:26:18 +0300 Subject: [PATCH 282/345] Add change log entry on strict validation --- activemodel/CHANGELOG | 2 ++ 1 file changed, 2 insertions(+) diff --git a/activemodel/CHANGELOG b/activemodel/CHANGELOG index 9b7d2d026d..20e5816532 100644 --- a/activemodel/CHANGELOG +++ b/activemodel/CHANGELOG @@ -1,3 +1,5 @@ +* Add ability to define strict validation(with :strict => true option) that always raises exception when fails [Bogdan Gusiev] + * Deprecate "Model.model_name.partial_path" in favor of "model.to_partial_path" [Grant Hutchins, Peter Jaros] * Provide mass_assignment_sanitizer as an easy API to replace the sanitizer behavior. Also support both :logger (default) and :strict sanitizer behavior [Bogdan Gusiev] From 13dd7758cedf6152835c4c72b69b1fe631a60733 Mon Sep 17 00:00:00 2001 From: Damien Mathieu <42@dmathieu.com> Date: Tue, 23 Aug 2011 11:02:44 +0200 Subject: [PATCH 283/345] remove useless rescue params is a method, defined in every controller, which always returns a hash. If it raises a NoMethodError, it means there's a bug somewhere else, which we want to know about. --- actionpack/lib/sprockets/helpers/rails_helper.rb | 9 +++------ actionpack/test/abstract_unit.rb | 6 +++++- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/actionpack/lib/sprockets/helpers/rails_helper.rb b/actionpack/lib/sprockets/helpers/rails_helper.rb index 7200ab1ddd..4fb8d0af37 100644 --- a/actionpack/lib/sprockets/helpers/rails_helper.rb +++ b/actionpack/lib/sprockets/helpers/rails_helper.rb @@ -70,12 +70,9 @@ module Sprockets private def debug_assets? - begin - params[:debug_assets] == '1' || - params[:debug_assets] == 'true' - rescue NoMethodError - false - end || Rails.application.config.assets.debug + params[:debug_assets] == '1' || + params[:debug_assets] == 'true' || + Rails.application.config.assets.debug end # Override to specify an alternative prefix for asset path generation. diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index 24d071df39..aa7a01f6c9 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -142,7 +142,11 @@ class RoutedRackApp end class BasicController - attr_accessor :request + attr_accessor :request, :params + + def initialize + @params = {} + end def config @config ||= ActiveSupport::InheritableOptions.new(ActionController::Base.config).tap do |config| From eb0b71478ad4c37fdc4ec77bf2cf7c6b65dd36c4 Mon Sep 17 00:00:00 2001 From: Daniel Schierbeck Date: Tue, 23 Aug 2011 13:42:36 +0200 Subject: [PATCH 284/345] Simplify JavaScriptHelper#escape_javascript Use the Linus-style conditional. Also fix the documentation slightly. Signed-off-by: Andrew White --- .../lib/action_view/helpers/javascript_helper.rb | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/actionpack/lib/action_view/helpers/javascript_helper.rb b/actionpack/lib/action_view/helpers/javascript_helper.rb index 474ea53f91..d01e62378b 100644 --- a/actionpack/lib/action_view/helpers/javascript_helper.rb +++ b/actionpack/lib/action_view/helpers/javascript_helper.rb @@ -20,17 +20,16 @@ module ActionView JS_ESCAPE_MAP["\342\200\250"] = '
' end - # Escape carrier returns and single and double quotes for JavaScript segments. + # Escapes carriage returns and single and double quotes for JavaScript segments. + # # Also available through the alias j(). This is particularly helpful in JavaScript responses, like: # # $('some_element').replaceWith('<%=j render 'some/element_template' %>'); def escape_javascript(javascript) - if javascript - result = javascript.gsub(/(\\|<\/|\r\n|\342\200\250|[\n\r"'])/u) {|match| JS_ESCAPE_MAP[match] } - javascript.html_safe? ? result.html_safe : result - else - '' - end + return "" if javascript.empty? + + result = javascript.gsub(/(\\|<\/|\r\n|\342\200\250|[\n\r"'])/u) {|match| JS_ESCAPE_MAP[match] } + javascript.html_safe? ? result.html_safe : result end alias_method :j, :escape_javascript From 0a0da9d554490f01fe57d69fe8d98f29b02be3e5 Mon Sep 17 00:00:00 2001 From: Akira Matsuda Date: Wed, 24 Aug 2011 21:09:41 +0900 Subject: [PATCH 285/345] do not compute table names for abstract classes --- activerecord/lib/active_record/base.rb | 2 ++ activerecord/test/cases/base_test.rb | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index c76f98d6a0..03aea81d2c 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -624,6 +624,8 @@ module ActiveRecord #:nodoc: # Computes the table name, (re)sets it internally, and returns it. def reset_table_name #:nodoc: + return if abstract_class? + self.table_name = compute_table_name end diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index fe46c00b47..bee183cc67 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -1625,6 +1625,10 @@ class BasicsTest < ActiveRecord::TestCase assert !LooseDescendant.abstract_class? end + def test_abstract_class_table_name + assert_nil AbstractCompany.table_name + end + def test_base_class assert_equal LoosePerson, LoosePerson.base_class assert_equal LooseDescendant, LooseDescendant.base_class From 827cdae6fb5e21056b68ab8a89047ae82738871f Mon Sep 17 00:00:00 2001 From: Guillermo Iguaran Date: Mon, 22 Aug 2011 23:19:25 -0500 Subject: [PATCH 286/345] Add config.allow_debugging option to determine if the debug_assets query param can be passed by user --- .../lib/sprockets/helpers/rails_helper.rb | 7 ++-- .../test/template/sprockets_helper_test.rb | 2 + .../lib/rails/application/configuration.rb | 13 +++--- .../config/environments/development.rb.tt | 3 ++ .../templates/config/environments/test.rb.tt | 3 ++ railties/test/application/assets_test.rb | 42 +++++++++++++++++++ 6 files changed, 61 insertions(+), 9 deletions(-) diff --git a/actionpack/lib/sprockets/helpers/rails_helper.rb b/actionpack/lib/sprockets/helpers/rails_helper.rb index 4fb8d0af37..50a8db4000 100644 --- a/actionpack/lib/sprockets/helpers/rails_helper.rb +++ b/actionpack/lib/sprockets/helpers/rails_helper.rb @@ -70,9 +70,10 @@ module Sprockets private def debug_assets? - params[:debug_assets] == '1' || - params[:debug_assets] == 'true' || - Rails.application.config.assets.debug + Rails.application.config.assets.allow_debugging && + (Rails.application.config.assets.debug || + params[:debug_assets] == '1' || + params[:debug_assets] == 'true') end # Override to specify an alternative prefix for asset path generation. diff --git a/actionpack/test/template/sprockets_helper_test.rb b/actionpack/test/template/sprockets_helper_test.rb index cac277cf11..5b4023809d 100644 --- a/actionpack/test/template/sprockets_helper_test.rb +++ b/actionpack/test/template/sprockets_helper_test.rb @@ -157,6 +157,7 @@ class SprocketsHelperTest < ActionView::TestCase assert_match %r{\n}, javascript_include_tag(:application, :debug => true) + @config.assets.allow_debugging = true @config.assets.debug = true assert_match %r{\n}, javascript_include_tag(:application) @@ -197,6 +198,7 @@ class SprocketsHelperTest < ActionView::TestCase assert_match %r{\n}, stylesheet_link_tag(:application, :debug => true) + @config.assets.allow_debugging = true @config.assets.debug = true assert_match %r{\n}, stylesheet_link_tag(:application) diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index f1add68890..c4a02ba5c0 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -33,12 +33,13 @@ module Rails @cache_store = [ :file_store, "#{root}/tmp/cache/" ] @assets = ActiveSupport::OrderedOptions.new - @assets.enabled = false - @assets.paths = [] - @assets.precompile = [ /\w+\.(?!js|css).+/, /application.(css|js)$/ ] - @assets.prefix = "/assets" - @assets.version = '' - @assets.debug = false + @assets.enabled = false + @assets.paths = [] + @assets.precompile = [ /\w+\.(?!js|css).+/, /application.(css|js)$/ ] + @assets.prefix = "/assets" + @assets.version = '' + @assets.debug = false + @assets.allow_debugging = false @assets.cache_store = [ :file_store, "#{root}/tmp/cache/assets/" ] @assets.js_compressor = nil diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt index 47078e3af9..33f9939ffe 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt @@ -30,6 +30,9 @@ # Do not compress assets config.assets.compress = false + # Allow pass debug_assets=true as a query parameter to load pages with unpackaged assets + config.assets.allow_debugging = true + # Expands the lines which load the assets config.assets.debug = true end diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt index 80198cc21e..8e33a65b2d 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt @@ -41,4 +41,7 @@ # Print deprecation notices to the stderr config.active_support.deprecation = :stderr + + # Allow pass debug_assets=true as a query parameter to load pages with unpackaged assets + config.assets.allow_debugging = true end diff --git a/railties/test/application/assets_test.rb b/railties/test/application/assets_test.rb index a8d1382e94..1e6a93dbdf 100644 --- a/railties/test/application/assets_test.rb +++ b/railties/test/application/assets_test.rb @@ -135,5 +135,47 @@ module ApplicationTests assert_match "alert();", last_response.body assert_equal 200, last_response.status end + + test "assets are concatenated when debug is off and allow_debugging is off either if debug_assets param is provided" do + app_with_assets_in_view + + # config.assets.debug and config.assets.allow_debugging are false for production environment + ENV["RAILS_ENV"] = "production" + require "#{app_path}/config/environment" + + class ::PostsController < ActionController::Base ; end + + # the debug_assets params isn't used if allow_debugging is off + get '/posts?debug_assets=true' + assert_match /}, last_response.body + assert_not_match %r{}, last_response.body + end + + test "assets aren't concatened when allow_debugging is on and debug_assets params is true" do + app_file "config/initializers/allow_debugging.rb", "Rails.application.config.assets.allow_debugging = true" + + require "#{app_path}/config/environment" + + get '/posts?debug_assets=true' + assert_match %r{}, last_response.body + assert_match %r{}, last_response.body + end + end +end diff --git a/railties/test/application/assets_test.rb b/railties/test/application/assets_test.rb index 1e6a93dbdf..a8d1382e94 100644 --- a/railties/test/application/assets_test.rb +++ b/railties/test/application/assets_test.rb @@ -135,47 +135,5 @@ module ApplicationTests assert_match "alert();", last_response.body assert_equal 200, last_response.status end - - test "assets are concatenated when debug is off and allow_debugging is off either if debug_assets param is provided" do - app_with_assets_in_view - - # config.assets.debug and config.assets.allow_debugging are false for production environment - ENV["RAILS_ENV"] = "production" - require "#{app_path}/config/environment" - - class ::PostsController < ActionController::Base ; end - - # the debug_assets params isn't used if allow_debugging is off - get '/posts?debug_assets=true' - assert_match /}, last_response.body - assert_not_match %r{}, last_response.body + assert_no_match %r{}, last_response.body end test "assets aren't concatened when allow_debugging is on and debug_assets params is true" do From 651ef614f1934578886ca792bb5e3eca8b5d1b48 Mon Sep 17 00:00:00 2001 From: Arun Agrawal Date: Fri, 26 Aug 2011 11:29:05 +0530 Subject: [PATCH 316/345] Removed Unused Variable. --- actionpack/test/template/form_tag_helper_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/test/template/form_tag_helper_test.rb b/actionpack/test/template/form_tag_helper_test.rb index 091f4e65b7..6eae9bf846 100644 --- a/actionpack/test/template/form_tag_helper_test.rb +++ b/actionpack/test/template/form_tag_helper_test.rb @@ -532,7 +532,7 @@ class FormTagHelperTest < ActionView::TestCase def test_image_label_tag_options_symbolize_keys_side_effects options = { :option => "random_option" } - actual = label_tag "submit source", "title", options + label_tag "submit source", "title", options assert_equal options, { :option => "random_option" } end From e8b525f16906458001fb1d10ed84d787760f19f3 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 26 Aug 2011 10:14:57 -0700 Subject: [PATCH 317/345] stop messing with the load path, load path should be adjusted in the test task --- activerecord/lib/active_record.rb | 7 ------- 1 file changed, 7 deletions(-) diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb index 511d402ee5..132dc12680 100644 --- a/activerecord/lib/active_record.rb +++ b/activerecord/lib/active_record.rb @@ -21,13 +21,6 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #++ - -activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__) -$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path) - -activemodel_path = File.expand_path('../../../activemodel/lib', __FILE__) -$:.unshift(activemodel_path) if File.directory?(activemodel_path) && !$:.include?(activemodel_path) - require 'active_support' require 'active_support/i18n' require 'active_model' From 6bdf4a3829acd089adddfb2b534ed66d974b902a Mon Sep 17 00:00:00 2001 From: Waynn Lue Date: Wed, 24 Aug 2011 23:00:43 -0700 Subject: [PATCH 318/345] incorporate feedback from vijaydev and dasch to rephrase this to sound more natural, and some grammar fixes. --- railties/README.rdoc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/railties/README.rdoc b/railties/README.rdoc index eb7ed961e3..501541eb06 100644 --- a/railties/README.rdoc +++ b/railties/README.rdoc @@ -1,12 +1,12 @@ = Railties -- Gluing the Engine to the Rails -Railties is responsible to glue all frameworks together. Overall, it: +Railties is responsible for gluing all frameworks together. Overall, it: -* handles all the bootstrapping process for a Rails application; +* handles the bootstrapping process for a Rails application; -* manages rails command line interface; +* manages the +rails+ command line interface; -* provides Rails generators core; +* and provides Rails generators core. == Download From 827a0fee07eff7ca35ecdf5ca650f2094ad4825a Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Sat, 27 Aug 2011 03:55:01 -0700 Subject: [PATCH 319/345] use sdoc to generate the API --- Gemfile | 2 +- Rakefile | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Gemfile b/Gemfile index e11514d5e6..f0880926a3 100644 --- a/Gemfile +++ b/Gemfile @@ -21,7 +21,7 @@ gem "mocha", ">= 0.9.8" group :doc do gem "rdoc", "~> 3.4" - gem "horo", "= 1.0.3" + gem "sdoc", "~> 0.3" gem "RedCloth", "~> 4.2" if RUBY_VERSION < "1.9.3" gem "w3c_validators" end diff --git a/Rakefile b/Rakefile index 4cf01cf063..ae857036c5 100755 --- a/Rakefile +++ b/Rakefile @@ -1,6 +1,7 @@ #!/usr/bin/env rake require 'rdoc/task' +require 'sdoc' require 'net/http' $:.unshift File.expand_path('..', __FILE__) @@ -89,7 +90,8 @@ RDoc::Task.new do |rdoc| rdoc.rdoc_dir = 'doc/rdoc' rdoc.title = "Ruby on Rails Documentation" - rdoc.options << '-f' << 'horo' + rdoc.options << '-f' << 'sdoc' + rdoc.options << '-T' << 'rails' rdoc.options << '-c' << 'utf-8' rdoc.options << '-m' << RDOC_MAIN From 8526f727cfadb49e629e7ac3a0bbcbf9a89ec3cd Mon Sep 17 00:00:00 2001 From: Vijay Dev Date: Sun, 28 Aug 2011 02:25:54 +0530 Subject: [PATCH 320/345] doc fixes --- README.rdoc | 6 +++--- .../action_controller/metal/params_wrapper.rb | 16 ++++++++-------- .../lib/action_dispatch/routing/url_for.rb | 12 ++++++++---- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/README.rdoc b/README.rdoc index f0aa962272..9f017cd05f 100644 --- a/README.rdoc +++ b/README.rdoc @@ -8,12 +8,12 @@ into three layers, each with a specific responsibility. The View layer is composed of "templates" that are responsible for providing appropriate representations of your application's resources. Templates -can come in a variety of formats, but most view templates are HTML with embedded Ruby +can come in a variety of formats, but most view templates are \HTML with embedded Ruby code (.erb files). The Model layer represents your domain model (such as Account, Product, Person, Post) and encapsulates the business logic that is specific to your application. In Rails, -database-backed model classes are derived from ActiveRecord::Base. ActiveRecord allows +database-backed model classes are derived from ActiveRecord::Base. Active Record allows you to present the data from database rows as objects and embellish these data objects with business logic methods. Although most Rails models are backed by a database, models can also be ordinary Ruby classes, or Ruby classes that implement a set of interfaces as @@ -21,7 +21,7 @@ provided by the ActiveModel module. You can read more about Active Record in its {README}[link:/rails/rails/blob/master/activerecord/README.rdoc]. The Controller layer is responsible for handling incoming HTTP requests and providing a -suitable response. Usually this means returning HTML, but Rails controllers can also +suitable response. Usually this means returning \HTML, but Rails controllers can also generate XML, JSON, PDFs, mobile-specific views, and more. Controllers manipulate models and render view templates in order to generate the appropriate HTTP response. diff --git a/actionpack/lib/action_controller/metal/params_wrapper.rb b/actionpack/lib/action_controller/metal/params_wrapper.rb index f24203db3a..6acbb23907 100644 --- a/actionpack/lib/action_controller/metal/params_wrapper.rb +++ b/actionpack/lib/action_controller/metal/params_wrapper.rb @@ -6,30 +6,30 @@ require 'active_support/core_ext/module/anonymous' require 'action_dispatch/http/mime_types' module ActionController - # Wraps parameters hash into nested hash. This will allow client to submit - # POST request without having to specify a root element in it. + # Wraps the parameters hash into a nested hash. This will allow clients to submit + # POST requests without having to specify any root elements. # # This functionality is enabled in +config/initializers/wrap_parameters.rb+ - # and can be customized. If you are upgrading to Rails 3.1, this file will + # and can be customized. If you are upgrading to \Rails 3.1, this file will # need to be created for the functionality to be enabled. # # You could also turn it on per controller by setting the format array to - # non-empty array: + # a non-empty array: # # class UsersController < ApplicationController # wrap_parameters :format => [:json, :xml] # end # - # If you enable +ParamsWrapper+ for +:json+ format. Instead of having to + # If you enable +ParamsWrapper+ for +:json+ format, instead of having to # send JSON parameters like this: # # {"user": {"name": "Konata"}} # - # You can now just send a parameters like this: + # You can send parameters like this: # # {"name": "Konata"} # - # And it will be wrapped into a nested hash with the key name matching + # And it will be wrapped into a nested hash with the key name matching the # controller's name. For example, if you're posting to +UsersController+, # your new +params+ hash will look like this: # @@ -81,7 +81,7 @@ module ActionController # # ==== Examples # wrap_parameters :format => :xml - # # enables the parmeter wrapper for XML format + # # enables the parameter wrapper for XML format # # wrap_parameters :person # # wraps parameters into +params[:person]+ hash diff --git a/actionpack/lib/action_dispatch/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb index de14113c51..30048cd48a 100644 --- a/actionpack/lib/action_dispatch/routing/url_for.rb +++ b/actionpack/lib/action_dispatch/routing/url_for.rb @@ -131,10 +131,14 @@ module ActionDispatch # # Examples: # - # url_for :controller => 'tasks', :action => 'testing', :host => 'somehost.org', :port => '8080' # => 'http://somehost.org:8080/tasks/testing' - # url_for :controller => 'tasks', :action => 'testing', :host => 'somehost.org', :anchor => 'ok', :only_path => true # => '/tasks/testing#ok' - # url_for :controller => 'tasks', :action => 'testing', :trailing_slash => true # => 'http://somehost.org/tasks/testing/' - # url_for :controller => 'tasks', :action => 'testing', :host => 'somehost.org', :number => '33' # => 'http://somehost.org/tasks/testing?number=33' + # url_for :controller => 'tasks', :action => 'testing', :host => 'somehost.org', :port => '8080' + # # => 'http://somehost.org:8080/tasks/testing' + # url_for :controller => 'tasks', :action => 'testing', :host => 'somehost.org', :anchor => 'ok', :only_path => true + # # => '/tasks/testing#ok' + # url_for :controller => 'tasks', :action => 'testing', :trailing_slash => true + # # => 'http://somehost.org/tasks/testing/' + # url_for :controller => 'tasks', :action => 'testing', :host => 'somehost.org', :number => '33' + # # => 'http://somehost.org/tasks/testing?number=33' def url_for(options = nil) case options when String From bb4dedbc2cc7b96b95bf4519f56ed9624949a7ef Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Sat, 27 Aug 2011 15:34:33 -0700 Subject: [PATCH 321/345] deletes spurious arrow --- actionpack/lib/action_controller/metal/url_for.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/action_controller/metal/url_for.rb b/actionpack/lib/action_controller/metal/url_for.rb index 08132b1900..0b40b1fc4c 100644 --- a/actionpack/lib/action_controller/metal/url_for.rb +++ b/actionpack/lib/action_controller/metal/url_for.rb @@ -18,7 +18,7 @@ # @url = root_path # named route from the application. # end # end -# => +# module ActionController module UrlFor extend ActiveSupport::Concern From 62a61add7e7555aae80660f3694e09624be192f3 Mon Sep 17 00:00:00 2001 From: Daniel Schierbeck Date: Sun, 28 Aug 2011 07:24:58 +0300 Subject: [PATCH 322/345] Refactor ActionDispatch::Http::UploadedFile --- actionpack/lib/action_dispatch/http/upload.rb | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/actionpack/lib/action_dispatch/http/upload.rb b/actionpack/lib/action_dispatch/http/upload.rb index a15ad28f16..94fa747a79 100644 --- a/actionpack/lib/action_dispatch/http/upload.rb +++ b/actionpack/lib/action_dispatch/http/upload.rb @@ -11,24 +11,13 @@ module ActionDispatch raise(ArgumentError, ':tempfile is required') unless @tempfile end - def open - @tempfile.open - end - - def path - @tempfile.path - end - def read(*args) @tempfile.read(*args) end - def rewind - @tempfile.rewind - end - - def size - @tempfile.size + # Delegate these methods to the tempfile. + [:open, :path, :rewind, :size].each do |method| + class_eval "def #{method}; @tempfile.#{method}; end" end private From b4ff82a79177757509cefa2b103ae56d84b84f6d Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 28 Aug 2011 14:15:51 -0700 Subject: [PATCH 323/345] clear and disable query cache when an exception is raised from called middleware --- activerecord/lib/active_record/query_cache.rb | 6 ++++ activerecord/test/cases/query_cache_test.rb | 28 ++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/query_cache.rb b/activerecord/lib/active_record/query_cache.rb index e485901440..10c0dc6f2a 100644 --- a/activerecord/lib/active_record/query_cache.rb +++ b/activerecord/lib/active_record/query_cache.rb @@ -61,6 +61,12 @@ module ActiveRecord status, headers, body = @app.call(env) [status, headers, BodyProxy.new(old, body)] + rescue Exception => e + ActiveRecord::Base.connection.clear_query_cache + unless old + ActiveRecord::Base.connection.disable_query_cache! + end + raise e end end end diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb index ad17f6f83a..fd5e69935e 100644 --- a/activerecord/test/cases/query_cache_test.rb +++ b/activerecord/test/cases/query_cache_test.rb @@ -13,6 +13,32 @@ class QueryCacheTest < ActiveRecord::TestCase ActiveRecord::Base.connection.disable_query_cache! end + def test_exceptional_middleware_clears_and_disables_cache_on_error + assert !ActiveRecord::Base.connection.query_cache_enabled, 'cache off' + + mw = ActiveRecord::QueryCache.new lambda { |env| + Task.find 1 + Task.find 1 + assert_equal 1, ActiveRecord::Base.connection.query_cache.length + raise "lol borked" + } + assert_raises(RuntimeError) { mw.call({}) } + + assert_equal 0, ActiveRecord::Base.connection.query_cache.length + assert !ActiveRecord::Base.connection.query_cache_enabled, 'cache off' + end + + def test_exceptional_middleware_leaves_enabled_cache_alone + ActiveRecord::Base.connection.enable_query_cache! + + mw = ActiveRecord::QueryCache.new lambda { |env| + raise "lol borked" + } + assert_raises(RuntimeError) { mw.call({}) } + + assert ActiveRecord::Base.connection.query_cache_enabled, 'cache off' + end + def test_middleware_delegates called = false mw = ActiveRecord::QueryCache.new lambda { |env| @@ -213,4 +239,4 @@ class QueryCacheBodyProxyTest < ActiveRecord::TestCase assert_equal proxy.to_path, "/path" end -end \ No newline at end of file +end From 49af31eada829148bc7b4053fa56692fa8527928 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sun, 28 Aug 2011 19:04:38 -0300 Subject: [PATCH 324/345] Bump rack-cache, rack-test, rack-mount and sprockets up --- actionpack/actionpack.gemspec | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec index 02758148c0..59d5bbc5ed 100644 --- a/actionpack/actionpack.gemspec +++ b/actionpack/actionpack.gemspec @@ -18,13 +18,13 @@ Gem::Specification.new do |s| s.add_dependency('activesupport', version) s.add_dependency('activemodel', version) - s.add_dependency('rack-cache', '~> 1.0.2') + s.add_dependency('rack-cache', '~> 1.0.3') s.add_dependency('builder', '~> 3.0.0') s.add_dependency('i18n', '~> 0.6') s.add_dependency('rack', '~> 1.3.2') - s.add_dependency('rack-test', '~> 0.6.0') - s.add_dependency('rack-mount', '~> 0.8.1') - s.add_dependency('sprockets', '~> 2.0.0.beta.14') + s.add_dependency('rack-test', '~> 0.6.1') + s.add_dependency('rack-mount', '~> 0.8.2') + s.add_dependency('sprockets', '~> 2.0.0.beta.15') s.add_dependency('erubis', '~> 2.7.0') s.add_development_dependency('tzinfo', '~> 0.3.29') From d63688d9e69d2440a35ab89c9b21866272a74fe3 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 28 Aug 2011 16:31:04 -0700 Subject: [PATCH 325/345] fixing typo --- activerecord/test/cases/query_cache_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb index fd5e69935e..e3ad0cad90 100644 --- a/activerecord/test/cases/query_cache_test.rb +++ b/activerecord/test/cases/query_cache_test.rb @@ -36,7 +36,7 @@ class QueryCacheTest < ActiveRecord::TestCase } assert_raises(RuntimeError) { mw.call({}) } - assert ActiveRecord::Base.connection.query_cache_enabled, 'cache off' + assert ActiveRecord::Base.connection.query_cache_enabled, 'cache on' end def test_middleware_delegates From 871696a01af853f10a33c4ff53f6d6ed795144b7 Mon Sep 17 00:00:00 2001 From: Igor Zubkov Date: Sun, 28 Aug 2011 23:08:06 +0300 Subject: [PATCH 326/345] Documentation fixes --- railties/guides/source/asset_pipeline.textile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/railties/guides/source/asset_pipeline.textile b/railties/guides/source/asset_pipeline.textile index 4fbdda4c07..554246acb3 100644 --- a/railties/guides/source/asset_pipeline.textile +++ b/railties/guides/source/asset_pipeline.textile @@ -29,7 +29,7 @@ It is recommended that you use the defaults for all new apps. h4. Main Features -The first feature of the pipeline is to concatenate assets. This is important in a production environment, as it reduces the number of requests that a browser must make to render a web page. While Rails already has a feature to concatenate these types of assetsi -- by placing +:cache => true+ at the end of tags such as +javascript_include_tag+ and +stylesheet_link_tag+ -- many people do not use it. +The first feature of the pipeline is to concatenate assets. This is important in a production environment, as it reduces the number of requests that a browser must make to render a web page. While Rails already has a feature to concatenate these types of assets -- by placing +:cache => true+ at the end of tags such as +javascript_include_tag+ and +stylesheet_link_tag+ -- many people do not use it. The default behavior in Rails 3.1 and onward is to concatenate all files into one master file each for JS and CSS. However, you can separate files or groups of files if required (see below). In production, an MD5 fingerprint is inserted into each filename so that the file is cached by the web browser but can be invalidated if the fingerprint is altered. @@ -133,7 +133,7 @@ Otherwise, Sprockets looks through the available paths until it finds a file tha If you want to use a "css data URI":http://en.wikipedia.org/wiki/Data_URI_scheme -- a method of embedding the image data directly into the CSS file -- you can use the +asset_data_uri+ helper. -#logo { background: url(<%= asset_data_uri 'logo.png' %>) +#logo { background: url(<%= asset_data_uri 'logo.png' %>) } This inserts a correctly-formatted data URI into the CSS source. @@ -143,7 +143,7 @@ h5. CSS and ERB If you add an +erb+ extension to a CSS asset, making it something such as +application.css.erb+, then you can use the +asset_path+ helper in your CSS rules: -.class{background-image:<%= asset_path 'image.png' %>} +.class { background-image: <%= asset_path 'image.png' %> } This writes the path to the particular asset being referenced. In this example, it would make sense to have an image in one of the asset load paths, such as +app/assets/images/image.png+, which would be referenced here. If this image is already available in +public/assets+ as a fingerprinted file, then that path is referenced. @@ -282,7 +282,7 @@ Rails comes bundled with a rake task to compile the manifests to files on disc. The rake task is: -rake assets:precompile +bundle exec rake assets:precompile Capistrano (v2.8.0+) has a recipe to handle this in deployment. Add the following line to +Capfile+: From 734792aaaab07cd7b4340b76ae66be3533088b11 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sun, 28 Aug 2011 16:41:15 -0700 Subject: [PATCH 327/345] Merge pull request #2723 from guilleiguaran/3-1-0-changelogs Update changelogs for Rails 3.1.0 --- actionpack/CHANGELOG | 2 ++ activesupport/CHANGELOG | 12 ++++++++++++ railties/CHANGELOG | 13 +++++++++++++ 3 files changed, 27 insertions(+) diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index b1286d04cc..6b654e149e 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -30,6 +30,8 @@ *Rails 3.1.0 (unreleased)* +* Param values are `paramified` in controller tests. [David Chelimsky] + * x_sendfile_header now defaults to nil and config/environments/production.rb doesn't set a particular value for it. This allows servers to set it through X-Sendfile-Type. [Santiago Pastorino] * The submit form helper does not generate an id "object_name_id" anymore. [fbrusatti] diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG index 1697d346b5..3508ec0f34 100644 --- a/activesupport/CHANGELOG +++ b/activesupport/CHANGELOG @@ -20,6 +20,18 @@ Also, in 1.8 the ideographic space U+3000 is considered to be whitespace. [Akira *Rails 3.1.0 (unreleased)* +* ActiveSupport::Dependencies#load and ActiveSupport::Dependencies#require now +return the value from `super` [Aaron Patterson] + +* Fixed ActiveSupport::Gzip to work properly in Ruby 1.8 [Guillermo Iguaran] + +* Kernel.require_library_or_gem was deprecated and will be removed in Rails 3.2.0 [Josh Kalderimis] + +* ActiveSupport::Duration#duplicable? was fixed for Ruby 1.8 [thedarkone] + +* ActiveSupport::BufferedLogger set log encoding to BINARY, but still use text +mode to output portable newlines. [fxn] + * ActiveSupport::Dependencies now raises NameError if it finds an existing constant in load_missing_constant. This better reflects the nature of the error which is usually caused by calling constantize on a nested constant. [Andrew White] * Deprecated ActiveSupport::SecureRandom in favour of SecureRandom from the standard library [Jon Leighton] diff --git a/railties/CHANGELOG b/railties/CHANGELOG index 76453f4e9a..6ed76974b4 100644 --- a/railties/CHANGELOG +++ b/railties/CHANGELOG @@ -12,6 +12,19 @@ *Rails 3.1.0 (unreleased)* +* The default database schema file is written as UTF-8. [Aaron Patterson] + +* Generated apps with --dev or --edge flags depend on git versions of +sass-rails and coffee-rails. [Santiago Pastorino] + +* Rack::Sendfile middleware is used only if x_sendfile_header is present. [Santiago Pastorino] + +* Add JavaScript Runtime name to the Rails Info properties. [DHH] + +* Make pp enabled by default in Rails console. [Akira Matsuda] + +* Add alias `r` for rails runner. [Jordi Romero] + * Make sprockets/railtie require explicit and add --skip-sprockets to app generator [José Valim] * Added Rails.groups that automatically handles Rails.env and ENV["RAILS_GROUPS"] [José Valim] From 381904d26b601c89e2a8496612a7c76db8ae9359 Mon Sep 17 00:00:00 2001 From: Guillermo Iguaran Date: Sun, 28 Aug 2011 19:00:58 -0500 Subject: [PATCH 328/345] Avoid extra recursive call in Sprockets helpers --- actionpack/lib/sprockets/helpers/rails_helper.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/actionpack/lib/sprockets/helpers/rails_helper.rb b/actionpack/lib/sprockets/helpers/rails_helper.rb index 7ad4d30d9e..7a2bf8bef6 100644 --- a/actionpack/lib/sprockets/helpers/rails_helper.rb +++ b/actionpack/lib/sprockets/helpers/rails_helper.rb @@ -26,7 +26,7 @@ module Sprockets sources.collect do |source| if debug && asset = asset_paths.asset_for(source, 'js') asset.to_a.map { |dep| - javascript_include_tag(dep, options.merge({ :debug => false, :body => true })) + super(dep.to_s, { :src => asset_path(dep, 'js', true) }.merge!(options)) } else super(source.to_s, { :src => asset_path(source, 'js', body) }.merge!(options)) @@ -42,7 +42,7 @@ module Sprockets sources.collect do |source| if debug && asset = asset_paths.asset_for(source, 'css') asset.to_a.map { |dep| - stylesheet_link_tag(dep, options.merge({ :debug => false, :body => true })) + super(dep.to_s, { :href => asset_path(dep, 'css', true, :request) }.merge!(options)) } else super(source.to_s, { :href => asset_path(source, 'css', body, :request) }.merge!(options)) From 5766539342426e956980bf6f54ef99600cbfc33e Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Thu, 25 Aug 2011 22:28:46 +0100 Subject: [PATCH 329/345] Create an AbstractMysqlAdapter to abstract the common code between MysqlAdapter and Mysql2Adapter. --- .../abstract_mysql_adapter.rb | 552 ++++++++++++++ .../connection_adapters/mysql2_adapter.rb | 588 ++------------- .../connection_adapters/mysql_adapter.rb | 697 +++--------------- .../adapters/mysql/active_schema_test.rb | 8 +- .../test/cases/column_definition_test.rb | 32 +- 5 files changed, 743 insertions(+), 1134 deletions(-) create mode 100644 activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb new file mode 100644 index 0000000000..72cf490d7e --- /dev/null +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -0,0 +1,552 @@ +require 'active_support/core_ext/object/blank' + +module ActiveRecord + module ConnectionAdapters + class AbstractMysqlAdapter < AbstractAdapter + class Column < ConnectionAdapters::Column + def extract_default(default) + if sql_type =~ /blob/i || type == :text + if default.blank? + return null ? nil : '' + else + raise ArgumentError, "#{type} columns cannot have a default value: #{default.inspect}" + end + elsif missing_default_forged_as_empty_string?(default) + nil + else + super + end + end + + def has_default? + return false if sql_type =~ /blob/i || type == :text #mysql forbids defaults on blob and text columns + super + end + + private + + def extract_limit(sql_type) + case sql_type + when /blob|text/i + case sql_type + when /tiny/i + 255 + when /medium/i + 16777215 + when /long/i + 2147483647 # mysql only allows 2^31-1, not 2^32-1, somewhat inconsistently with the tiny/medium/normal cases + else + super # we could return 65535 here, but we leave it undecorated by default + end + when /^bigint/i; 8 + when /^int/i; 4 + when /^mediumint/i; 3 + when /^smallint/i; 2 + when /^tinyint/i; 1 + else + super + end + end + + # MySQL misreports NOT NULL column default when none is given. + # We can't detect this for columns which may have a legitimate '' + # default (string) but we can for others (integer, datetime, boolean, + # and the rest). + # + # Test whether the column has default '', is not null, and is not + # a type allowing default ''. + def missing_default_forged_as_empty_string?(default) + type != :string && !null && default == '' + end + end + + ## + # :singleton-method: + # By default, the MysqlAdapter will consider all columns of type tinyint(1) + # as boolean. If you wish to disable this emulation (which was the default + # behavior in versions 0.13.1 and earlier) you can add the following line + # to your application.rb file: + # + # ActiveRecord::ConnectionAdapters::Mysql[2]Adapter.emulate_booleans = false + class_attribute :emulate_booleans + self.emulate_booleans = true + + LOST_CONNECTION_ERROR_MESSAGES = [ + "Server shutdown in progress", + "Broken pipe", + "Lost connection to MySQL server during query", + "MySQL server has gone away" ] + + QUOTED_TRUE, QUOTED_FALSE = '1', '0' + + NATIVE_DATABASE_TYPES = { + :primary_key => "int(11) DEFAULT NULL auto_increment PRIMARY KEY", + :string => { :name => "varchar", :limit => 255 }, + :text => { :name => "text" }, + :integer => { :name => "int", :limit => 4 }, + :float => { :name => "float" }, + :decimal => { :name => "decimal" }, + :datetime => { :name => "datetime" }, + :timestamp => { :name => "datetime" }, + :time => { :name => "time" }, + :date => { :name => "date" }, + :binary => { :name => "blob" }, + :boolean => { :name => "tinyint", :limit => 1 } + } + + # FIXME: Make the first parameter more similar for the two adapters + def initialize(connection, logger, connection_options, config) + super(connection, logger) + @connection_options, @config = connection_options, config + @quoted_column_names, @quoted_table_names = {}, {} + end + + def self.visitor_for(pool) # :nodoc: + Arel::Visitors::MySQL.new(pool) + end + + def adapter_name #:nodoc: + self.class::ADAPTER_NAME + end + + # Returns true, since this connection adapter supports migrations. + def supports_migrations? + true + end + + def supports_primary_key? + true + end + + # Returns true, since this connection adapter supports savepoints. + def supports_savepoints? + true + end + + def native_database_types + NATIVE_DATABASE_TYPES + end + + # HELPER METHODS =========================================== + + # The two drivers have slightly different ways of yielding hashes of results, so + # this method must be implemented to provide a uniform interface. + def each_hash(result) # :nodoc: + raise NotImplementedError + end + + # Overridden by the adapters to instantiate their specific Column type. + def new_column(field, default, type, null) # :nodoc: + Column.new(field, default, type, null) + end + + # Must return the Mysql error number from the exception, if the exception has an + # error number. + def error_number(exception) # :nodoc: + raise NotImplementedError + end + + # QUOTING ================================================== + + def quote(value, column = nil) + if value.kind_of?(String) && column && column.type == :binary && column.class.respond_to?(:string_to_binary) + s = column.class.string_to_binary(value).unpack("H*")[0] + "x'#{s}'" + elsif value.kind_of?(BigDecimal) + value.to_s("F") + else + super + end + end + + def quote_column_name(name) #:nodoc: + @quoted_column_names[name] ||= "`#{name.to_s.gsub('`', '``')}`" + end + + def quote_table_name(name) #:nodoc: + @quoted_table_names[name] ||= quote_column_name(name).gsub('.', '`.`') + end + + def quoted_true + QUOTED_TRUE + end + + def quoted_false + QUOTED_FALSE + end + + # REFERENTIAL INTEGRITY ==================================== + + def disable_referential_integrity(&block) #:nodoc: + old = select_value("SELECT @@FOREIGN_KEY_CHECKS") + + begin + update("SET FOREIGN_KEY_CHECKS = 0") + yield + ensure + update("SET FOREIGN_KEY_CHECKS = #{old}") + end + end + + # DATABASE STATEMENTS ====================================== + + # Executes the SQL statement in the context of this connection. + def execute(sql, name = nil) + if name == :skip_logging + @connection.query(sql) + else + log(sql, name) { @connection.query(sql) } + end + rescue ActiveRecord::StatementInvalid => exception + if exception.message.split(":").first =~ /Packets out of order/ + raise ActiveRecord::StatementInvalid, "'Packets out of order' error was received from the database. Please update your mysql bindings (gem install mysql) and read http://dev.mysql.com/doc/mysql/en/password-hashing.html for more information. If you're on Windows, use the Instant Rails installer to get the updated mysql bindings." + else + raise + end + end + + # MysqlAdapter has to free a result after using it, so we use this method to write + # stuff in a abstract way without concerning ourselves about whether it needs to be + # explicitly freed or not. + def execute_and_free(sql, name = nil) #:nodoc: + yield execute(sql, name) + end + + def update_sql(sql, name = nil) #:nodoc: + super + @connection.affected_rows + end + + def begin_db_transaction + execute "BEGIN" + rescue Exception + # Transactions aren't supported + end + + def commit_db_transaction #:nodoc: + execute "COMMIT" + rescue Exception + # Transactions aren't supported + end + + def rollback_db_transaction #:nodoc: + execute "ROLLBACK" + rescue Exception + # Transactions aren't supported + end + + def create_savepoint + execute("SAVEPOINT #{current_savepoint_name}") + end + + def rollback_to_savepoint + execute("ROLLBACK TO SAVEPOINT #{current_savepoint_name}") + end + + def release_savepoint + execute("RELEASE SAVEPOINT #{current_savepoint_name}") + end + + # In the simple case, MySQL allows us to place JOINs directly into the UPDATE + # query. However, this does not allow for LIMIT, OFFSET and ORDER. To support + # these, we must use a subquery. However, MySQL is too stupid to create a + # temporary table for this automatically, so we have to give it some prompting + # in the form of a subsubquery. Ugh! + def join_to_update(update, select) #:nodoc: + if select.limit || select.offset || select.orders.any? + subsubselect = select.clone + subsubselect.projections = [update.key] + + subselect = Arel::SelectManager.new(select.engine) + subselect.project Arel.sql(update.key.name) + subselect.from subsubselect.as('__active_record_temp') + + update.where update.key.in(subselect) + else + update.table select.source + update.wheres = select.constraints + end + end + + # SCHEMA STATEMENTS ======================================== + + def structure_dump #:nodoc: + if supports_views? + sql = "SHOW FULL TABLES WHERE Table_type = 'BASE TABLE'" + else + sql = "SHOW TABLES" + end + + select_all(sql).map do |table| + table.delete('Table_type') + sql = "SHOW CREATE TABLE #{quote_table_name(table.to_a.first.last)}" + exec_without_stmt(sql).first['Create Table'] + ";\n\n" + end.join("") + end + + # Drops the database specified on the +name+ attribute + # and creates it again using the provided +options+. + def recreate_database(name, options = {}) + drop_database(name) + create_database(name, options) + end + + # Create a new MySQL database with optional :charset and :collation. + # Charset defaults to utf8. + # + # Example: + # create_database 'charset_test', :charset => 'latin1', :collation => 'latin1_bin' + # create_database 'matt_development' + # create_database 'matt_development', :charset => :big5 + def create_database(name, options = {}) + if options[:collation] + execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}` COLLATE `#{options[:collation]}`" + else + execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}`" + end + end + + # Drops a MySQL database. + # + # Example: + # drop_database('sebastian_development') + def drop_database(name) #:nodoc: + execute "DROP DATABASE IF EXISTS `#{name}`" + end + + def current_database + select_value 'SELECT DATABASE() as db' + end + + # Returns the database character set. + def charset + show_variable 'character_set_database' + end + + # Returns the database collation strategy. + def collation + show_variable 'collation_database' + end + + def tables(name = nil, database = nil) #:nodoc: + sql = ["SHOW TABLES", database].compact.join(' IN ') + + execute_and_free(sql, 'SCHEMA') do |result| + result.collect { |field| field.first } + end + end + + def table_exists?(name) + return true if super + + name = name.to_s + schema, table = name.split('.', 2) + + unless table # A table was provided without a schema + table = schema + schema = nil + end + + tables(nil, schema).include? table + end + + # Returns an array of indexes for the given table. + def indexes(table_name, name = nil) #:nodoc: + indexes = [] + current_index = nil + execute_and_free("SHOW KEYS FROM #{quote_table_name(table_name)}", 'SCHEMA') do |result| + each_hash(result) do |row| + if current_index != row[:Key_name] + next if row[:Key_name] == 'PRIMARY' # skip the primary key + current_index = row[:Key_name] + indexes << IndexDefinition.new(row[:Table], row[:Key_name], row[:Non_unique].to_i == 0, [], []) + end + + indexes.last.columns << row[:Column_name] + indexes.last.lengths << row[:Sub_part] + end + end + + indexes + end + + # Returns an array of +Column+ objects for the table specified by +table_name+. + def columns(table_name, name = nil)#:nodoc: + sql = "SHOW FIELDS FROM #{quote_table_name(table_name)}" + execute_and_free(sql, 'SCHEMA') do |result| + each_hash(result).map do |field| + new_column(field[:Field], field[:Default], field[:Type], field[:Null] == "YES") + end + end + end + + def create_table(table_name, options = {}) #:nodoc: + super(table_name, options.reverse_merge(:options => "ENGINE=InnoDB")) + end + + # Renames a table. + # + # Example: + # rename_table('octopuses', 'octopi') + def rename_table(table_name, new_name) + execute "RENAME TABLE #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}" + end + + def add_column(table_name, column_name, type, options = {}) + execute("ALTER TABLE #{quote_table_name(table_name)} #{add_column_sql(table_name, column_name, type, options)}") + end + + def change_column_default(table_name, column_name, default) + column = column_for(table_name, column_name) + change_column table_name, column_name, column.sql_type, :default => default + end + + def change_column_null(table_name, column_name, null, default = nil) + column = column_for(table_name, column_name) + + unless null || default.nil? + execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL") + end + + change_column table_name, column_name, column.sql_type, :null => null + end + + def change_column(table_name, column_name, type, options = {}) #:nodoc: + execute("ALTER TABLE #{quote_table_name(table_name)} #{change_column_sql(table_name, column_name, type, options)}") + end + + def rename_column(table_name, column_name, new_column_name) #:nodoc: + execute("ALTER TABLE #{quote_table_name(table_name)} #{rename_column_sql(table_name, column_name, new_column_name)}") + end + + # Maps logical Rails types to MySQL-specific data types. + def type_to_sql(type, limit = nil, precision = nil, scale = nil) + return super unless type.to_s == 'integer' + + case limit + when 1; 'tinyint' + when 2; 'smallint' + when 3; 'mediumint' + when nil, 4, 11; 'int(11)' # compatibility with MySQL default + when 5..8; 'bigint' + else raise(ActiveRecordError, "No integer type has byte size #{limit}") + end + end + + def add_column_position!(sql, options) + if options[:first] + sql << " FIRST" + elsif options[:after] + sql << " AFTER #{quote_column_name(options[:after])}" + end + end + + # SHOW VARIABLES LIKE 'name' + def show_variable(name) + variables = select_all("SHOW VARIABLES LIKE '#{name}'") + variables.first['Value'] unless variables.empty? + end + + # Returns a table's primary key and belonging sequence. + def pk_and_sequence_for(table) + execute_and_free("DESCRIBE #{quote_table_name(table)}", 'SCHEMA') do |result| + keys = each_hash(result).select { |row| row[:Key] == 'PRI' }.map { |row| row[:Field] } + keys.length == 1 ? [keys.first, nil] : nil + end + end + + # Returns just a table's primary key + def primary_key(table) + pk_and_sequence = pk_and_sequence_for(table) + pk_and_sequence && pk_and_sequence.first + end + + def case_sensitive_modifier(node) + Arel::Nodes::Bin.new(node) + end + + def limited_update_conditions(where_sql, quoted_table_name, quoted_primary_key) + where_sql + end + + protected + + def quoted_columns_for_index(column_names, options = {}) + length = options[:length] if options.is_a?(Hash) + + case length + when Hash + column_names.map {|name| length[name] ? "#{quote_column_name(name)}(#{length[name]})" : quote_column_name(name) } + when Fixnum + column_names.map {|name| "#{quote_column_name(name)}(#{length})"} + else + column_names.map {|name| quote_column_name(name) } + end + end + + def translate_exception(exception, message) + case error_number(exception) + when 1062 + RecordNotUnique.new(message, exception) + when 1452 + InvalidForeignKey.new(message, exception) + else + super + end + end + + def add_column_sql(table_name, column_name, type, options = {}) + add_column_sql = "ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}" + add_column_options!(add_column_sql, options) + add_column_position!(add_column_sql, options) + add_column_sql + end + + def change_column_sql(table_name, column_name, type, options = {}) + column = column_for(table_name, column_name) + + unless options_include_default?(options) + options[:default] = column.default + end + + unless options.has_key?(:null) + options[:null] = column.null + end + + change_column_sql = "CHANGE #{quote_column_name(column_name)} #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}" + add_column_options!(change_column_sql, options) + add_column_position!(change_column_sql, options) + change_column_sql + end + + def rename_column_sql(table_name, column_name, new_column_name) + options = {} + + if column = columns(table_name).find { |c| c.name == column_name.to_s } + options[:default] = column.default + options[:null] = column.null + else + raise ActiveRecordError, "No such column: #{table_name}.#{column_name}" + end + + current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'")["Type"] + rename_column_sql = "CHANGE #{quote_column_name(column_name)} #{quote_column_name(new_column_name)} #{current_type}" + add_column_options!(rename_column_sql, options) + rename_column_sql + end + + private + + def supports_views? + version[0] >= 5 + end + + def column_for(table_name, column_name) + unless column = columns(table_name).find { |c| c.name == column_name.to_s } + raise "No such column: #{table_name}.#{column_name}" + end + column + end + end + end +end diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb index ef51f5ebca..00d9caa8ee 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb @@ -1,4 +1,4 @@ -# encoding: utf-8 +require 'active_record/connection_adapters/abstract_mysql_adapter' gem 'mysql2', '~> 0.3.6' require 'mysql2' @@ -20,31 +20,13 @@ module ActiveRecord end module ConnectionAdapters - class Mysql2IndexDefinition < Struct.new(:table, :name, :unique, :columns, :lengths) #:nodoc: - end + class Mysql2Adapter < AbstractMysqlAdapter + class Column < AbstractMysqlAdapter::Column # :nodoc: + BOOL = "tinyint(1)" - class Mysql2Column < Column - BOOL = "tinyint(1)" - def extract_default(default) - if sql_type =~ /blob/i || type == :text - if default.blank? - return null ? nil : '' - else - raise ArgumentError, "#{type} columns cannot have a default value: #{default.inspect}" - end - elsif missing_default_forged_as_empty_string?(default) - nil - else - super - end - end + private - def has_default? - return false if sql_type =~ /blob/i || type == :text #mysql forbids defaults on blob and text columns - super - end - - private + # FIXME: Combine with the mysql version and move to abstract adapter def simplified_type(field_type) return :boolean if Mysql2Adapter.emulate_booleans && field_type.downcase.index(BOOL) @@ -56,155 +38,45 @@ module ActiveRecord super end end - - def extract_limit(sql_type) - case sql_type - when /blob|text/i - case sql_type - when /tiny/i - 255 - when /medium/i - 16777215 - when /long/i - 2147483647 # mysql only allows 2^31-1, not 2^32-1, somewhat inconsistently with the tiny/medium/normal cases - else - super # we could return 65535 here, but we leave it undecorated by default - end - when /^bigint/i; 8 - when /^int/i; 4 - when /^mediumint/i; 3 - when /^smallint/i; 2 - when /^tinyint/i; 1 - else - super - end - end - - # MySQL misreports NOT NULL column default when none is given. - # We can't detect this for columns which may have a legitimate '' - # default (string) but we can for others (integer, datetime, boolean, - # and the rest). - # - # Test whether the column has default '', is not null, and is not - # a type allowing default ''. - def missing_default_forged_as_empty_string?(default) - type != :string && !null && default == '' - end - end - - class Mysql2Adapter < AbstractAdapter - cattr_accessor :emulate_booleans - self.emulate_booleans = true + end ADAPTER_NAME = 'Mysql2' - PRIMARY = "PRIMARY" - - LOST_CONNECTION_ERROR_MESSAGES = [ - "Server shutdown in progress", - "Broken pipe", - "Lost connection to MySQL server during query", - "MySQL server has gone away" ] - - QUOTED_TRUE, QUOTED_FALSE = '1', '0' - - NATIVE_DATABASE_TYPES = { - :primary_key => "int(11) DEFAULT NULL auto_increment PRIMARY KEY", - :string => { :name => "varchar", :limit => 255 }, - :text => { :name => "text" }, - :integer => { :name => "int", :limit => 4 }, - :float => { :name => "float" }, - :decimal => { :name => "decimal" }, - :datetime => { :name => "datetime" }, - :timestamp => { :name => "datetime" }, - :time => { :name => "time" }, - :date => { :name => "date" }, - :binary => { :name => "blob" }, - :boolean => { :name => "tinyint", :limit => 1 } - } def initialize(connection, logger, connection_options, config) - super(connection, logger) - @connection_options, @config = connection_options, config - @quoted_column_names, @quoted_table_names = {}, {} + super configure_connection end - def self.visitor_for(pool) # :nodoc: - Arel::Visitors::MySQL.new(pool) - end + # HELPER METHODS =========================================== - def adapter_name - ADAPTER_NAME - end - - # Returns true, since this connection adapter supports migrations. - def supports_migrations? - true - end - - def supports_primary_key? - true - end - - # Returns true, since this connection adapter supports savepoints. - def supports_savepoints? - true - end - - def native_database_types - NATIVE_DATABASE_TYPES - end - - # QUOTING ================================================== - - def quote(value, column = nil) - if value.kind_of?(String) && column && column.type == :binary && column.class.respond_to?(:string_to_binary) - s = column.class.string_to_binary(value).unpack("H*")[0] - "x'#{s}'" - elsif value.kind_of?(BigDecimal) - value.to_s("F") + def each_hash(result) # :nodoc: + if block_given? + result.each(:as => :hash, :symbolize_keys => true) do |row| + yield row + end else - super + to_enum(:each_hash, result) end end - def quote_column_name(name) #:nodoc: - @quoted_column_names[name] ||= "`#{name.to_s.gsub('`', '``')}`" + def new_column(field, default, type, null) # :nodoc: + Column.new(field, default, type, null) end - def quote_table_name(name) #:nodoc: - @quoted_table_names[name] ||= quote_column_name(name).gsub('.', '`.`') + def error_number(exception) + exception.error_number if exception.respond_to?(:error_number) end + # QUOTING ================================================== + def quote_string(string) @connection.escape(string) end - def quoted_true - QUOTED_TRUE - end - - def quoted_false - QUOTED_FALSE - end - def substitute_at(column, index) Arel.sql "\0" end - # REFERENTIAL INTEGRITY ==================================== - - def disable_referential_integrity(&block) #:nodoc: - old = select_value("SELECT @@FOREIGN_KEY_CHECKS") - - begin - update("SET FOREIGN_KEY_CHECKS = 0") - yield - ensure - update("SET FOREIGN_KEY_CHECKS = #{old}") - end - end - # CONNECTION MANAGEMENT ==================================== def active? @@ -217,11 +89,6 @@ module ActiveRecord connect end - # this is set to true in 2.3, but we don't want it to be - def requires_reloading? - false - end - # Disconnects from the database if already connected. # Otherwise, this method does nothing. def disconnect! @@ -277,17 +144,22 @@ module ActiveRecord # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been # made since we established the connection @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone - if name == :skip_logging - @connection.query(sql) - else - log(sql, name) { @connection.query(sql) } - end - rescue ActiveRecord::StatementInvalid => exception - if exception.message.split(":").first =~ /Packets out of order/ - raise ActiveRecord::StatementInvalid, "'Packets out of order' error was received from the database. Please update your mysql bindings (gem install mysql) and read http://dev.mysql.com/doc/mysql/en/password-hashing.html for more information. If you're on Windows, use the Instant Rails installer to get the updated mysql bindings." - else - raise - end + + super + end + + def exec_query(sql, name = 'SQL', binds = []) + result = execute(sql, name) + ActiveRecord::Result.new(result.fields, result.to_a) + end + + alias exec_without_stmt exec_query + + # Returns an array of record hashes with the column names as keys and + # column values as values. + def select(sql, name = nil, binds = []) + binds = binds.dup + exec_query(sql.gsub("\0") { quote(*binds.shift.reverse) }, name).to_a end def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) @@ -316,379 +188,35 @@ module ActiveRecord @connection.last_id end - def update_sql(sql, name = nil) - super - @connection.affected_rows - end - - def begin_db_transaction - execute "BEGIN" - rescue Exception - # Transactions aren't supported - end - - def commit_db_transaction - execute "COMMIT" - rescue Exception - # Transactions aren't supported - end - - def rollback_db_transaction - execute "ROLLBACK" - rescue Exception - # Transactions aren't supported - end - - def create_savepoint - execute("SAVEPOINT #{current_savepoint_name}") - end - - def rollback_to_savepoint - execute("ROLLBACK TO SAVEPOINT #{current_savepoint_name}") - end - - def release_savepoint - execute("RELEASE SAVEPOINT #{current_savepoint_name}") - end - - # SCHEMA STATEMENTS ======================================== - - def structure_dump - if supports_views? - sql = "SHOW FULL TABLES WHERE Table_type = 'BASE TABLE'" - else - sql = "SHOW TABLES" - end - - select_all(sql).inject("") do |structure, table| - table.delete('Table_type') - structure += select_one("SHOW CREATE TABLE #{quote_table_name(table.to_a.first.last)}")["Create Table"] + ";\n\n" - end - end - - # Drops the database specified on the +name+ attribute - # and creates it again using the provided +options+. - def recreate_database(name, options = {}) - drop_database(name) - create_database(name, options) - end - - # Create a new MySQL database with optional :charset and :collation. - # Charset defaults to utf8. - # - # Example: - # create_database 'charset_test', :charset => 'latin1', :collation => 'latin1_bin' - # create_database 'matt_development' - # create_database 'matt_development', :charset => :big5 - def create_database(name, options = {}) - if options[:collation] - execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}` COLLATE `#{options[:collation]}`" - else - execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}`" - end - end - - # Drops a MySQL database. - # - # Example: - # drop_database('sebastian_development') - def drop_database(name) #:nodoc: - execute "DROP DATABASE IF EXISTS `#{name}`" - end - - def current_database - select_value 'SELECT DATABASE() as db' - end - - # Returns the database character set. - def charset - show_variable 'character_set_database' - end - - # Returns the database collation strategy. - def collation - show_variable 'collation_database' - end - - def tables(name = nil, database = nil) #:nodoc: - sql = ["SHOW TABLES", database].compact.join(' IN ') - execute(sql, 'SCHEMA').collect do |field| - field.first - end - end - - def table_exists?(name) - return true if super - - name = name.to_s - schema, table = name.split('.', 2) - - unless table # A table was provided without a schema - table = schema - schema = nil - end - - tables(nil, schema).include? table - end - - # Returns an array of indexes for the given table. - def indexes(table_name, name = nil) - indexes = [] - current_index = nil - result = execute("SHOW KEYS FROM #{quote_table_name(table_name)}", 'SCHEMA') - result.each(:symbolize_keys => true, :as => :hash) do |row| - if current_index != row[:Key_name] - next if row[:Key_name] == PRIMARY # skip the primary key - current_index = row[:Key_name] - indexes << Mysql2IndexDefinition.new(row[:Table], row[:Key_name], row[:Non_unique] == 0, [], []) - end - - indexes.last.columns << row[:Column_name] - indexes.last.lengths << row[:Sub_part] - end - indexes - end - - # Returns an array of +Mysql2Column+ objects for the table specified by +table_name+. - def columns(table_name, name = nil) - sql = "SHOW FIELDS FROM #{quote_table_name(table_name)}" - columns = [] - result = execute(sql, 'SCHEMA') - result.each(:symbolize_keys => true, :as => :hash) { |field| - columns << Mysql2Column.new(field[:Field], field[:Default], field[:Type], field[:Null] == "YES") - } - columns - end - - def create_table(table_name, options = {}) - super(table_name, options.reverse_merge(:options => "ENGINE=InnoDB")) - end - - # Renames a table. - # - # Example: - # rename_table('octopuses', 'octopi') - def rename_table(table_name, new_name) - execute "RENAME TABLE #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}" - end - - def add_column(table_name, column_name, type, options = {}) - add_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}" - add_column_options!(add_column_sql, options) - add_column_position!(add_column_sql, options) - execute(add_column_sql) - end - - def change_column_default(table_name, column_name, default) - column = column_for(table_name, column_name) - change_column table_name, column_name, column.sql_type, :default => default - end - - def change_column_null(table_name, column_name, null, default = nil) - column = column_for(table_name, column_name) - - unless null || default.nil? - execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL") - end - - change_column table_name, column_name, column.sql_type, :null => null - end - - def change_column(table_name, column_name, type, options = {}) - column = column_for(table_name, column_name) - - unless options_include_default?(options) - options[:default] = column.default - end - - unless options.has_key?(:null) - options[:null] = column.null - end - - change_column_sql = "ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}" - add_column_options!(change_column_sql, options) - add_column_position!(change_column_sql, options) - execute(change_column_sql) - end - - def rename_column(table_name, column_name, new_column_name) - options = {} - if column = columns(table_name).find { |c| c.name == column_name.to_s } - options[:default] = column.default - options[:null] = column.null - else - raise ActiveRecordError, "No such column: #{table_name}.#{column_name}" - end - current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'")["Type"] - rename_column_sql = "ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(new_column_name)} #{current_type}" - add_column_options!(rename_column_sql, options) - execute(rename_column_sql) - end - - # Maps logical Rails types to MySQL-specific data types. - def type_to_sql(type, limit = nil, precision = nil, scale = nil) - return super unless type.to_s == 'integer' - - case limit - when 1; 'tinyint' - when 2; 'smallint' - when 3; 'mediumint' - when nil, 4, 11; 'int(11)' # compatibility with MySQL default - when 5..8; 'bigint' - else raise(ActiveRecordError, "No integer type has byte size #{limit}") - end - end - - def add_column_position!(sql, options) - if options[:first] - sql << " FIRST" - elsif options[:after] - sql << " AFTER #{quote_column_name(options[:after])}" - end - end - - # SHOW VARIABLES LIKE 'name'. - def show_variable(name) - variables = select_all("SHOW VARIABLES LIKE '#{name}'") - variables.first['Value'] unless variables.empty? - end - - # Returns a table's primary key and belonging sequence. - def pk_and_sequence_for(table) - keys = [] - result = execute("DESCRIBE #{quote_table_name(table)}", 'SCHEMA') - result.each(:symbolize_keys => true, :as => :hash) do |row| - keys << row[:Field] if row[:Key] == "PRI" - end - keys.length == 1 ? [keys.first, nil] : nil - end - - # Returns just a table's primary key - def primary_key(table) - pk_and_sequence = pk_and_sequence_for(table) - pk_and_sequence && pk_and_sequence.first - end - - def case_sensitive_modifier(node) - Arel::Nodes::Bin.new(node) - end - - def limited_update_conditions(where_sql, quoted_table_name, quoted_primary_key) - where_sql - end - - # In the simple case, MySQL allows us to place JOINs directly into the UPDATE - # query. However, this does not allow for LIMIT, OFFSET and ORDER. To support - # these, we must use a subquery. However, MySQL is too stupid to create a - # temporary table for this automatically, so we have to give it some prompting - # in the form of a subsubquery. Ugh! - def join_to_update(update, select) #:nodoc: - if select.limit || select.offset || select.orders.any? - subsubselect = select.clone - subsubselect.projections = [update.key] - - subselect = Arel::SelectManager.new(select.engine) - subselect.project Arel.sql(update.key.name) - subselect.from subsubselect.as('__active_record_temp') - - update.where update.key.in(subselect) - else - update.table select.source - update.wheres = select.constraints - end - end - - protected - def quoted_columns_for_index(column_names, options = {}) - length = options[:length] if options.is_a?(Hash) - - case length - when Hash - column_names.map {|name| length[name] ? "#{quote_column_name(name)}(#{length[name]})" : quote_column_name(name) } - when Fixnum - column_names.map {|name| "#{quote_column_name(name)}(#{length})"} - else - column_names.map {|name| quote_column_name(name) } - end - end - - def translate_exception(exception, message) - return super unless exception.respond_to?(:error_number) - - case exception.error_number - when 1062 - RecordNotUnique.new(message, exception) - when 1452 - InvalidForeignKey.new(message, exception) - else - super - end - end - private - def connect - @connection = Mysql2::Client.new(@config) - configure_connection - end - def configure_connection - @connection.query_options.merge!(:as => :array) + def connect + @connection = Mysql2::Client.new(@config) + configure_connection + end - # By default, MySQL 'where id is null' selects the last inserted id. - # Turn this off. http://dev.rubyonrails.org/ticket/6778 - variable_assignments = ['SQL_AUTO_IS_NULL=0'] - encoding = @config[:encoding] + def configure_connection + @connection.query_options.merge!(:as => :array) - # make sure we set the encoding - variable_assignments << "NAMES '#{encoding}'" if encoding + # By default, MySQL 'where id is null' selects the last inserted id. + # Turn this off. http://dev.rubyonrails.org/ticket/6778 + variable_assignments = ['SQL_AUTO_IS_NULL=0'] + encoding = @config[:encoding] - # increase timeout so mysql server doesn't disconnect us - wait_timeout = @config[:wait_timeout] - wait_timeout = 2592000 unless wait_timeout.is_a?(Fixnum) - variable_assignments << "@@wait_timeout = #{wait_timeout}" + # make sure we set the encoding + variable_assignments << "NAMES '#{encoding}'" if encoding - execute("SET #{variable_assignments.join(', ')}", :skip_logging) - end + # increase timeout so mysql server doesn't disconnect us + wait_timeout = @config[:wait_timeout] + wait_timeout = 2592000 unless wait_timeout.is_a?(Fixnum) + variable_assignments << "@@wait_timeout = #{wait_timeout}" - # Returns an array of record hashes with the column names as keys and - # column values as values. - def select(sql, name = nil, binds = []) - binds = binds.dup - exec_query(sql.gsub("\0") { quote(*binds.shift.reverse) }, name).to_a - end + execute("SET #{variable_assignments.join(', ')}", :skip_logging) + end - def exec_query(sql, name = 'SQL', binds = []) - @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone - - log(sql, name, binds) do - begin - result = @connection.query(sql) - rescue ActiveRecord::StatementInvalid => exception - if exception.message.split(":").first =~ /Packets out of order/ - raise ActiveRecord::StatementInvalid, "'Packets out of order' error was received from the database. Please update your mysql bindings (gem install mysql) and read http://dev.mysql.com/doc/mysql/en/password-hashing.html for more information. If you're on Windows, use the Instant Rails installer to get the updated mysql bindings." - else - raise - end - end - - ActiveRecord::Result.new(result.fields, result.to_a) - end - end - - def supports_views? - version[0] >= 5 - end - - def version - @version ||= @connection.info[:version].scan(/^(\d+)\.(\d+)\.(\d+)/).flatten.map { |v| v.to_i } - end - - def column_for(table_name, column_name) - unless column = columns(table_name).find { |c| c.name == column_name.to_s } - raise "No such column: #{table_name}.#{column_name}" - end - column - end + def version + @version ||= @connection.info[:version].scan(/^(\d+)\.(\d+)\.(\d+)/).flatten.map { |v| v.to_i } + end end end end diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index b844e5ab10..d61875195a 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -1,6 +1,5 @@ -require 'active_record/connection_adapters/abstract_adapter' -require 'active_support/core_ext/object/blank' -require 'set' +require 'active_record/connection_adapters/abstract_mysql_adapter' +require 'active_support/core_ext/hash/keys' gem 'mysql', '~> 2.8.1' require 'mysql' @@ -40,92 +39,6 @@ module ActiveRecord end module ConnectionAdapters - class MysqlColumn < Column #:nodoc: - class << self - def string_to_time(value) - return super unless Mysql::Time === value - new_time( - value.year, - value.month, - value.day, - value.hour, - value.minute, - value.second, - value.second_part) - end - - def string_to_dummy_time(v) - return super unless Mysql::Time === v - new_time(2000, 01, 01, v.hour, v.minute, v.second, v.second_part) - end - - def string_to_date(v) - return super unless Mysql::Time === v - new_date(v.year, v.month, v.day) - end - end - - def extract_default(default) - if sql_type =~ /blob/i || type == :text - if default.blank? - return null ? nil : '' - else - raise ArgumentError, "#{type} columns cannot have a default value: #{default.inspect}" - end - elsif missing_default_forged_as_empty_string?(default) - nil - else - super - end - end - - def has_default? - return false if sql_type =~ /blob/i || type == :text #mysql forbids defaults on blob and text columns - super - end - - private - def simplified_type(field_type) - return :boolean if MysqlAdapter.emulate_booleans && field_type.downcase.index("tinyint(1)") - return :string if field_type =~ /enum/i - super - end - - def extract_limit(sql_type) - case sql_type - when /blob|text/i - case sql_type - when /tiny/i - 255 - when /medium/i - 16777215 - when /long/i - 2147483647 # mysql only allows 2^31-1, not 2^32-1, somewhat inconsistently with the tiny/medium/normal cases - else - super # we could return 65535 here, but we leave it undecorated by default - end - when /^bigint/i; 8 - when /^int/i; 4 - when /^mediumint/i; 3 - when /^smallint/i; 2 - when /^tinyint/i; 1 - else - super - end - end - - # MySQL misreports NOT NULL column default when none is given. - # We can't detect this for columns which may have a legitimate '' - # default (string) but we can for others (integer, datetime, boolean, - # and the rest). - # - # Test whether the column has default '', is not null, and is not - # a type allowing default ''. - def missing_default_forged_as_empty_string?(default) - type != :string && !null && default == '' - end - end - # The MySQL adapter will work with both Ruby/MySQL, which is a Ruby-based MySQL adapter that comes bundled with Active Record, and with # the faster C-based MySQL/Ruby adapter (available both as a gem and from http://www.tmtm.org/en/mysql/ruby/). # @@ -145,61 +58,50 @@ module ActiveRecord # * :sslcapath - Necessary to use MySQL with an SSL connection. # * :sslcipher - Necessary to use MySQL with an SSL connection. # - class MysqlAdapter < AbstractAdapter + class MysqlAdapter < AbstractMysqlAdapter + class Column < AbstractMysqlAdapter::Column #:nodoc: + def self.string_to_time(value) + return super unless Mysql::Time === value + new_time( + value.year, + value.month, + value.day, + value.hour, + value.minute, + value.second, + value.second_part) + end - ## - # :singleton-method: - # By default, the MysqlAdapter will consider all columns of type tinyint(1) - # as boolean. If you wish to disable this emulation (which was the default - # behavior in versions 0.13.1 and earlier) you can add the following line - # to your application.rb file: - # - # ActiveRecord::ConnectionAdapters::MysqlAdapter.emulate_booleans = false - cattr_accessor :emulate_booleans - self.emulate_booleans = true + def self.string_to_dummy_time(v) + return super unless Mysql::Time === v + new_time(2000, 01, 01, v.hour, v.minute, v.second, v.second_part) + end + + def self.string_to_date(v) + return super unless Mysql::Time === v + new_date(v.year, v.month, v.day) + end + + private + + # FIXME: Combine with the mysql2 version and move to abstract adapter + def simplified_type(field_type) + return :boolean if MysqlAdapter.emulate_booleans && field_type.downcase.index("tinyint(1)") + return :string if field_type =~ /enum/i + super + end + end ADAPTER_NAME = 'MySQL' - LOST_CONNECTION_ERROR_MESSAGES = [ - "Server shutdown in progress", - "Broken pipe", - "Lost connection to MySQL server during query", - "MySQL server has gone away" ] - - QUOTED_TRUE, QUOTED_FALSE = '1', '0' - - NATIVE_DATABASE_TYPES = { - :primary_key => "int(11) DEFAULT NULL auto_increment PRIMARY KEY", - :string => { :name => "varchar", :limit => 255 }, - :text => { :name => "text" }, - :integer => { :name => "int", :limit => 4 }, - :float => { :name => "float" }, - :decimal => { :name => "decimal" }, - :datetime => { :name => "datetime" }, - :timestamp => { :name => "datetime" }, - :time => { :name => "time" }, - :date => { :name => "date" }, - :binary => { :name => "blob" }, - :boolean => { :name => "tinyint", :limit => 1 } - } - def initialize(connection, logger, connection_options, config) - super(connection, logger) - @connection_options, @config = connection_options, config - @quoted_column_names, @quoted_table_names = {}, {} + super @statements = {} @client_encoding = nil connect end - def self.visitor_for(pool) # :nodoc: - Arel::Visitors::MySQL.new(pool) - end - - def adapter_name #:nodoc: - ADAPTER_NAME - end - + # FIXME: Move to abstract adapter def supports_bulk_alter? #:nodoc: true end @@ -210,78 +112,39 @@ module ActiveRecord true end - # Returns true, since this connection adapter supports migrations. - def supports_migrations? #:nodoc: - true - end + # HELPER METHODS =========================================== - # Returns true. - def supports_primary_key? #:nodoc: - true - end - - # Returns true, since this connection adapter supports savepoints. - def supports_savepoints? #:nodoc: - true - end - - def native_database_types #:nodoc: - NATIVE_DATABASE_TYPES - end - - - # QUOTING ================================================== - - def quote(value, column = nil) - if value.kind_of?(String) && column && column.type == :binary && column.class.respond_to?(:string_to_binary) - s = column.class.string_to_binary(value).unpack("H*")[0] - "x'#{s}'" - elsif value.kind_of?(BigDecimal) - value.to_s("F") + def each_hash(result) # :nodoc: + if block_given? + result.each_hash do |row| + row.symbolize_keys! + yield row + end else - super + to_enum(:each_hash, result) end end + def new_column(field, default, type, null) # :nodoc: + Column.new(field, default, type, null) + end + + def error_number(exception) # :nodoc: + exception.errno if exception.respond_to?(:errno) + end + + # QUOTING ================================================== + def type_cast(value, column) return super unless value == true || value == false value ? 1 : 0 end - def quote_column_name(name) #:nodoc: - @quoted_column_names[name] ||= "`#{name.to_s.gsub('`', '``')}`" - end - - def quote_table_name(name) #:nodoc: - @quoted_table_names[name] ||= quote_column_name(name).gsub('.', '`.`') - end - def quote_string(string) #:nodoc: @connection.quote(string) end - def quoted_true - QUOTED_TRUE - end - - def quoted_false - QUOTED_FALSE - end - - # REFERENTIAL INTEGRITY ==================================== - - def disable_referential_integrity #:nodoc: - old = select_value("SELECT @@FOREIGN_KEY_CHECKS") - - begin - update("SET FOREIGN_KEY_CHECKS = 0") - yield - ensure - update("SET FOREIGN_KEY_CHECKS = #{old}") - end - end - # CONNECTION MANAGEMENT ==================================== def active? @@ -425,20 +288,11 @@ module ActiveRecord end end - # Executes an SQL query and returns a MySQL::Result object. Note that you have to free - # the Result object after you're done using it. - def execute(sql, name = nil) #:nodoc: - if name == :skip_logging - @connection.query(sql) - else - log(sql, name) { @connection.query(sql) } - end - rescue ActiveRecord::StatementInvalid => exception - if exception.message.split(":").first =~ /Packets out of order/ - raise ActiveRecord::StatementInvalid, "'Packets out of order' error was received from the database. Please update your mysql bindings (gem install mysql) and read http://dev.mysql.com/doc/mysql/en/password-hashing.html for more information. If you're on Windows, use the Instant Rails installer to get the updated mysql bindings." - else - raise - end + def execute_and_free(sql, name = nil) + result = execute(sql, name) + ret = yield result + result.free + ret end def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc: @@ -447,11 +301,6 @@ module ActiveRecord end alias :create :insert_sql - def update_sql(sql, name = nil) #:nodoc: - super - @connection.affected_rows - end - def exec_delete(sql, name, binds) log(sql, name, binds) do exec_stmt(sql, name, binds) do |cols, stmt| @@ -467,172 +316,8 @@ module ActiveRecord # Transactions aren't supported end - def commit_db_transaction #:nodoc: - execute "COMMIT" - rescue Exception - # Transactions aren't supported - end - - def rollback_db_transaction #:nodoc: - execute "ROLLBACK" - rescue Exception - # Transactions aren't supported - end - - def create_savepoint - execute("SAVEPOINT #{current_savepoint_name}") - end - - def rollback_to_savepoint - execute("ROLLBACK TO SAVEPOINT #{current_savepoint_name}") - end - - def release_savepoint - execute("RELEASE SAVEPOINT #{current_savepoint_name}") - end - - # In the simple case, MySQL allows us to place JOINs directly into the UPDATE - # query. However, this does not allow for LIMIT, OFFSET and ORDER. To support - # these, we must use a subquery. However, MySQL is too stupid to create a - # temporary table for this automatically, so we have to give it some prompting - # in the form of a subsubquery. Ugh! - def join_to_update(update, select) #:nodoc: - if select.limit || select.offset || select.orders.any? - subsubselect = select.clone - subsubselect.projections = [update.key] - - subselect = Arel::SelectManager.new(select.engine) - subselect.project Arel.sql(update.key.name) - subselect.from subsubselect.as('__active_record_temp') - - update.where update.key.in(subselect) - else - update.table select.source - update.wheres = select.constraints - end - end - # SCHEMA STATEMENTS ======================================== - def structure_dump #:nodoc: - if supports_views? - sql = "SHOW FULL TABLES WHERE Table_type = 'BASE TABLE'" - else - sql = "SHOW TABLES" - end - - select_all(sql).map do |table| - table.delete('Table_type') - sql = "SHOW CREATE TABLE #{quote_table_name(table.to_a.first.last)}" - exec_without_stmt(sql).first['Create Table'] + ";\n\n" - end.join("") - end - - # Drops the database specified on the +name+ attribute - # and creates it again using the provided +options+. - def recreate_database(name, options = {}) #:nodoc: - drop_database(name) - create_database(name, options) - end - - # Create a new MySQL database with optional :charset and :collation. - # Charset defaults to utf8. - # - # Example: - # create_database 'charset_test', :charset => 'latin1', :collation => 'latin1_bin' - # create_database 'matt_development' - # create_database 'matt_development', :charset => :big5 - def create_database(name, options = {}) - if options[:collation] - execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}` COLLATE `#{options[:collation]}`" - else - execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}`" - end - end - - # Drops a MySQL database. - # - # Example: - # drop_database 'sebastian_development' - def drop_database(name) #:nodoc: - execute "DROP DATABASE IF EXISTS `#{name}`" - end - - def current_database - select_value 'SELECT DATABASE() as db' - end - - # Returns the database character set. - def charset - show_variable 'character_set_database' - end - - # Returns the database collation strategy. - def collation - show_variable 'collation_database' - end - - def tables(name = nil, database = nil) #:nodoc: - result = execute(["SHOW TABLES", database].compact.join(' IN '), 'SCHEMA') - tables = result.collect { |field| field[0] } - result.free - tables - end - - def table_exists?(name) - return true if super - - name = name.to_s - schema, table = name.split('.', 2) - - unless table # A table was provided without a schema - table = schema - schema = nil - end - - tables(nil, schema).include? table - end - - # Returns an array of indexes for the given table. - def indexes(table_name, name = nil)#:nodoc: - indexes = [] - current_index = nil - result = execute("SHOW KEYS FROM #{quote_table_name(table_name)}", name) - result.each do |row| - if current_index != row[2] - next if row[2] == "PRIMARY" # skip the primary key - current_index = row[2] - indexes << IndexDefinition.new(row[0], row[2], row[1] == "0", [], []) - end - - indexes.last.columns << row[4] - indexes.last.lengths << row[7] - end - result.free - indexes - end - - # Returns an array of +MysqlColumn+ objects for the table specified by +table_name+. - def columns(table_name, name = nil)#:nodoc: - sql = "SHOW FIELDS FROM #{quote_table_name(table_name)}" - result = execute(sql, 'SCHEMA') - columns = result.collect { |field| MysqlColumn.new(field[0], field[4], field[1], field[2] == "YES") } - result.free - columns - end - - def create_table(table_name, options = {}) #:nodoc: - super(table_name, options.reverse_merge(:options => "ENGINE=InnoDB")) - end - - # Renames a table. - # - # Example: - # rename_table('octopuses', 'octopi') - def rename_table(table_name, new_name) - execute "RENAME TABLE #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}" - end - def bulk_change_table(table_name, operations) #:nodoc: sqls = operations.map do |command, args| table, arguments = args.shift, args @@ -648,177 +333,33 @@ module ActiveRecord execute("ALTER TABLE #{quote_table_name(table_name)} #{sqls}") end - def add_column(table_name, column_name, type, options = {}) - execute("ALTER TABLE #{quote_table_name(table_name)} #{add_column_sql(table_name, column_name, type, options)}") - end - - def change_column_default(table_name, column_name, default) #:nodoc: - column = column_for(table_name, column_name) - change_column table_name, column_name, column.sql_type, :default => default - end - - def change_column_null(table_name, column_name, null, default = nil) - column = column_for(table_name, column_name) - - unless null || default.nil? - execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL") - end - - change_column table_name, column_name, column.sql_type, :null => null - end - - def change_column(table_name, column_name, type, options = {}) #:nodoc: - execute("ALTER TABLE #{quote_table_name(table_name)} #{change_column_sql(table_name, column_name, type, options)}") - end - - def rename_column(table_name, column_name, new_column_name) #:nodoc: - execute("ALTER TABLE #{quote_table_name(table_name)} #{rename_column_sql(table_name, column_name, new_column_name)}") - end - - # Maps logical Rails types to MySQL-specific data types. - def type_to_sql(type, limit = nil, precision = nil, scale = nil) - return super unless type.to_s == 'integer' - - case limit - when 1; 'tinyint' - when 2; 'smallint' - when 3; 'mediumint' - when nil, 4, 11; 'int(11)' # compatibility with MySQL default - when 5..8; 'bigint' - else raise(ActiveRecordError, "No integer type has byte size #{limit}") - end - end - - def add_column_position!(sql, options) - if options[:first] - sql << " FIRST" - elsif options[:after] - sql << " AFTER #{quote_column_name(options[:after])}" - end - end - - # SHOW VARIABLES LIKE 'name' - def show_variable(name) - variables = select_all("SHOW VARIABLES LIKE '#{name}'") - variables.first['Value'] unless variables.empty? - end - - # Returns a table's primary key and belonging sequence. - def pk_and_sequence_for(table) #:nodoc: - keys = [] - result = execute("describe #{quote_table_name(table)}", 'SCHEMA') - result.each_hash do |h| - keys << h["Field"]if h["Key"] == "PRI" - end - result.free - keys.length == 1 ? [keys.first, nil] : nil - end - - # Returns just a table's primary key - def primary_key(table) - pk_and_sequence = pk_and_sequence_for(table) - pk_and_sequence && pk_and_sequence.first - end - - def case_sensitive_modifier(node) - Arel::Nodes::Bin.new(node) - end - - def limited_update_conditions(where_sql, quoted_table_name, quoted_primary_key) - where_sql - end - protected - def quoted_columns_for_index(column_names, options = {}) - length = options[:length] if options.is_a?(Hash) - case length - when Hash - column_names.map {|name| length[name] ? "#{quote_column_name(name)}(#{length[name]})" : quote_column_name(name) } - when Fixnum - column_names.map {|name| "#{quote_column_name(name)}(#{length})"} - else - column_names.map {|name| quote_column_name(name) } - end - end + def remove_column_sql(table_name, *column_names) + columns_for_remove(table_name, *column_names).map {|column_name| "DROP #{column_name}" } + end + alias :remove_columns_sql :remove_column - def translate_exception(exception, message) - return super unless exception.respond_to?(:errno) + def add_index_sql(table_name, column_name, options = {}) + index_name, index_type, index_columns = add_index_options(table_name, column_name, options) + "ADD #{index_type} INDEX #{index_name} (#{index_columns})" + end - case exception.errno - when 1062 - RecordNotUnique.new(message, exception) - when 1452 - InvalidForeignKey.new(message, exception) - else - super - end - end + def remove_index_sql(table_name, options = {}) + index_name = index_name_for_remove(table_name, options) + "DROP INDEX #{index_name}" + end - def add_column_sql(table_name, column_name, type, options = {}) - add_column_sql = "ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}" - add_column_options!(add_column_sql, options) - add_column_position!(add_column_sql, options) - add_column_sql - end + def add_timestamps_sql(table_name) + [add_column_sql(table_name, :created_at, :datetime), add_column_sql(table_name, :updated_at, :datetime)] + end - def remove_column_sql(table_name, *column_names) - columns_for_remove(table_name, *column_names).map {|column_name| "DROP #{column_name}" } - end - alias :remove_columns_sql :remove_column - - def change_column_sql(table_name, column_name, type, options = {}) - column = column_for(table_name, column_name) - - unless options_include_default?(options) - options[:default] = column.default - end - - unless options.has_key?(:null) - options[:null] = column.null - end - - change_column_sql = "CHANGE #{quote_column_name(column_name)} #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}" - add_column_options!(change_column_sql, options) - add_column_position!(change_column_sql, options) - change_column_sql - end - - def rename_column_sql(table_name, column_name, new_column_name) - options = {} - - if column = columns(table_name).find { |c| c.name == column_name.to_s } - options[:default] = column.default - options[:null] = column.null - else - raise ActiveRecordError, "No such column: #{table_name}.#{column_name}" - end - - current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'")["Type"] - rename_column_sql = "CHANGE #{quote_column_name(column_name)} #{quote_column_name(new_column_name)} #{current_type}" - add_column_options!(rename_column_sql, options) - rename_column_sql - end - - def add_index_sql(table_name, column_name, options = {}) - index_name, index_type, index_columns = add_index_options(table_name, column_name, options) - "ADD #{index_type} INDEX #{index_name} (#{index_columns})" - end - - def remove_index_sql(table_name, options = {}) - index_name = index_name_for_remove(table_name, options) - "DROP INDEX #{index_name}" - end - - def add_timestamps_sql(table_name) - [add_column_sql(table_name, :created_at, :datetime), add_column_sql(table_name, :updated_at, :datetime)] - end - - def remove_timestamps_sql(table_name) - [remove_column_sql(table_name, :updated_at), remove_column_sql(table_name, :created_at)] - end + def remove_timestamps_sql(table_name) + [remove_column_sql(table_name, :updated_at), remove_column_sql(table_name, :created_at)] + end private + def exec_stmt(sql, name, binds) cache = {} if binds.empty? @@ -830,7 +371,6 @@ module ActiveRecord stmt = cache[:stmt] end - begin stmt.execute(*binds.map { |col, val| type_cast(val, col) }) rescue Mysql::Error => e @@ -859,59 +399,48 @@ module ActiveRecord result end - def connect - encoding = @config[:encoding] - if encoding - @connection.options(Mysql::SET_CHARSET_NAME, encoding) rescue nil - end - - if @config[:sslca] || @config[:sslkey] - @connection.ssl_set(@config[:sslkey], @config[:sslcert], @config[:sslca], @config[:sslcapath], @config[:sslcipher]) - end - - @connection.options(Mysql::OPT_CONNECT_TIMEOUT, @config[:connect_timeout]) if @config[:connect_timeout] - @connection.options(Mysql::OPT_READ_TIMEOUT, @config[:read_timeout]) if @config[:read_timeout] - @connection.options(Mysql::OPT_WRITE_TIMEOUT, @config[:write_timeout]) if @config[:write_timeout] - - @connection.real_connect(*@connection_options) - - # reconnect must be set after real_connect is called, because real_connect sets it to false internally - @connection.reconnect = !!@config[:reconnect] if @connection.respond_to?(:reconnect=) - - configure_connection + def connect + encoding = @config[:encoding] + if encoding + @connection.options(Mysql::SET_CHARSET_NAME, encoding) rescue nil end - def configure_connection - encoding = @config[:encoding] - execute("SET NAMES '#{encoding}'", :skip_logging) if encoding - - # By default, MySQL 'where id is null' selects the last inserted id. - # Turn this off. http://dev.rubyonrails.org/ticket/6778 - execute("SET SQL_AUTO_IS_NULL=0", :skip_logging) + if @config[:sslca] || @config[:sslkey] + @connection.ssl_set(@config[:sslkey], @config[:sslcert], @config[:sslca], @config[:sslcapath], @config[:sslcipher]) end - def select(sql, name = nil, binds = []) - @connection.query_with_result = true - 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 + @connection.options(Mysql::OPT_CONNECT_TIMEOUT, @config[:connect_timeout]) if @config[:connect_timeout] + @connection.options(Mysql::OPT_READ_TIMEOUT, @config[:read_timeout]) if @config[:read_timeout] + @connection.options(Mysql::OPT_WRITE_TIMEOUT, @config[:write_timeout]) if @config[:write_timeout] - def supports_views? - version[0] >= 5 - end + @connection.real_connect(*@connection_options) - # Returns the version of the connected MySQL server. - def version - @version ||= @connection.server_info.scan(/^(\d+)\.(\d+)\.(\d+)/).flatten.map { |v| v.to_i } - end + # reconnect must be set after real_connect is called, because real_connect sets it to false internally + @connection.reconnect = !!@config[:reconnect] if @connection.respond_to?(:reconnect=) - def column_for(table_name, column_name) - unless column = columns(table_name).find { |c| c.name == column_name.to_s } - raise "No such column: #{table_name}.#{column_name}" - end - column - end + configure_connection + end + + def configure_connection + encoding = @config[:encoding] + execute("SET NAMES '#{encoding}'", :skip_logging) if encoding + + # By default, MySQL 'where id is null' selects the last inserted id. + # Turn this off. http://dev.rubyonrails.org/ticket/6778 + execute("SET SQL_AUTO_IS_NULL=0", :skip_logging) + end + + def select(sql, name = nil, binds = []) + @connection.query_with_result = true + 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 + + # Returns the version of the connected MySQL server. + def version + @version ||= @connection.server_info.scan(/^(\d+)\.(\d+)\.(\d+)/).flatten.map { |v| v.to_i } + end end end end diff --git a/activerecord/test/cases/adapters/mysql/active_schema_test.rb b/activerecord/test/cases/adapters/mysql/active_schema_test.rb index 509baacaef..94fc3564df 100644 --- a/activerecord/test/cases/adapters/mysql/active_schema_test.rb +++ b/activerecord/test/cases/adapters/mysql/active_schema_test.rb @@ -2,7 +2,7 @@ require "cases/helper" class ActiveSchemaTest < ActiveRecord::TestCase def setup - ActiveRecord::ConnectionAdapters::MysqlAdapter.class_eval do + ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter.class_eval do alias_method :execute_without_stub, :execute remove_method :execute def execute(sql, name = nil) return sql end @@ -10,7 +10,7 @@ class ActiveSchemaTest < ActiveRecord::TestCase end def teardown - ActiveRecord::ConnectionAdapters::MysqlAdapter.class_eval do + ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter.class_eval do remove_method :execute alias_method :execute, :execute_without_stub end @@ -99,7 +99,7 @@ class ActiveSchemaTest < ActiveRecord::TestCase private def with_real_execute #we need to actually modify some data, so we make execute point to the original method - ActiveRecord::ConnectionAdapters::MysqlAdapter.class_eval do + ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter.class_eval do alias_method :execute_with_stub, :execute remove_method :execute alias_method :execute, :execute_without_stub @@ -107,7 +107,7 @@ class ActiveSchemaTest < ActiveRecord::TestCase yield ensure #before finishing, we restore the alias to the mock-up method - ActiveRecord::ConnectionAdapters::MysqlAdapter.class_eval do + ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter.class_eval do remove_method :execute alias_method :execute, :execute_with_stub end diff --git a/activerecord/test/cases/column_definition_test.rb b/activerecord/test/cases/column_definition_test.rb index d1dddd4c2c..14884e42af 100644 --- a/activerecord/test/cases/column_definition_test.rb +++ b/activerecord/test/cases/column_definition_test.rb @@ -58,68 +58,68 @@ module ActiveRecord if current_adapter?(:MysqlAdapter) def test_should_set_default_for_mysql_binary_data_types - binary_column = MysqlColumn.new("title", "a", "binary(1)") + binary_column = MysqlAdapter::Column.new("title", "a", "binary(1)") assert_equal "a", binary_column.default - varbinary_column = MysqlColumn.new("title", "a", "varbinary(1)") + varbinary_column = MysqlAdapter::Column.new("title", "a", "varbinary(1)") assert_equal "a", varbinary_column.default end def test_should_not_set_default_for_blob_and_text_data_types assert_raise ArgumentError do - MysqlColumn.new("title", "a", "blob") + MysqlAdapter::Column.new("title", "a", "blob") end assert_raise ArgumentError do - MysqlColumn.new("title", "Hello", "text") + MysqlAdapter::Column.new("title", "Hello", "text") end - text_column = MysqlColumn.new("title", nil, "text") + text_column = MysqlAdapter::Column.new("title", nil, "text") assert_equal nil, text_column.default - not_null_text_column = MysqlColumn.new("title", nil, "text", false) + not_null_text_column = MysqlAdapter::Column.new("title", nil, "text", false) assert_equal "", not_null_text_column.default end def test_has_default_should_return_false_for_blog_and_test_data_types - blob_column = MysqlColumn.new("title", nil, "blob") + blob_column = MysqlAdapter::Column.new("title", nil, "blob") assert !blob_column.has_default? - text_column = MysqlColumn.new("title", nil, "text") + text_column = MysqlAdapter::Column.new("title", nil, "text") assert !text_column.has_default? end end if current_adapter?(:Mysql2Adapter) def test_should_set_default_for_mysql_binary_data_types - binary_column = Mysql2Column.new("title", "a", "binary(1)") + binary_column = Mysql2Adapter::Column.new("title", "a", "binary(1)") assert_equal "a", binary_column.default - varbinary_column = Mysql2Column.new("title", "a", "varbinary(1)") + varbinary_column = Mysql2Adapter::Column.new("title", "a", "varbinary(1)") assert_equal "a", varbinary_column.default end def test_should_not_set_default_for_blob_and_text_data_types assert_raise ArgumentError do - Mysql2Column.new("title", "a", "blob") + Mysql2Adapter::Column.new("title", "a", "blob") end assert_raise ArgumentError do - Mysql2Column.new("title", "Hello", "text") + Mysql2Adapter::Column.new("title", "Hello", "text") end - text_column = Mysql2Column.new("title", nil, "text") + text_column = Mysql2Adapter::Column.new("title", nil, "text") assert_equal nil, text_column.default - not_null_text_column = Mysql2Column.new("title", nil, "text", false) + not_null_text_column = Mysql2Adapter::Column.new("title", nil, "text", false) assert_equal "", not_null_text_column.default end def test_has_default_should_return_false_for_blog_and_test_data_types - blob_column = Mysql2Column.new("title", nil, "blob") + blob_column = Mysql2Adapter::Column.new("title", nil, "blob") assert !blob_column.has_default? - text_column = Mysql2Column.new("title", nil, "text") + text_column = Mysql2Adapter::Column.new("title", nil, "text") assert !text_column.has_default? end end From 4fcd847c8d9fb2b22e1c2e3c840c8d1c590b56b4 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Mon, 29 Aug 2011 12:25:15 +0100 Subject: [PATCH 330/345] Extract simplified_type into the abstract class --- .../abstract_mysql_adapter.rb | 19 ++++++++++++++++++- .../connection_adapters/mysql2_adapter.rb | 18 +++--------------- .../connection_adapters/mysql_adapter.rb | 10 +++------- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb index 72cf490d7e..548ca83353 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -3,7 +3,7 @@ require 'active_support/core_ext/object/blank' module ActiveRecord module ConnectionAdapters class AbstractMysqlAdapter < AbstractAdapter - class Column < ConnectionAdapters::Column + class Column < ConnectionAdapters::Column # :nodoc: def extract_default(default) if sql_type =~ /blob/i || type == :text if default.blank? @@ -23,8 +23,25 @@ module ActiveRecord super end + # Must return the relevant concrete adapter + def adapter + raise NotImplementedError + end + private + def simplified_type(field_type) + return :boolean if adapter.emulate_booleans && field_type.downcase.index("tinyint(1)") + + case field_type + when /enum/i, /set/i then :string + when /year/i then :integer + when /bit/i then :binary + else + super + end + end + def extract_limit(sql_type) case sql_type when /blob|text/i diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb index 00d9caa8ee..8b574518e5 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb @@ -21,22 +21,10 @@ module ActiveRecord module ConnectionAdapters class Mysql2Adapter < AbstractMysqlAdapter + class Column < AbstractMysqlAdapter::Column # :nodoc: - BOOL = "tinyint(1)" - - private - - # FIXME: Combine with the mysql version and move to abstract adapter - def simplified_type(field_type) - return :boolean if Mysql2Adapter.emulate_booleans && field_type.downcase.index(BOOL) - - case field_type - when /enum/i, /set/i then :string - when /year/i then :integer - when /bit/i then :binary - else - super - end + def adapter + Mysql2Adapter end end diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index d61875195a..182db65165 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -59,6 +59,7 @@ module ActiveRecord # * :sslcipher - Necessary to use MySQL with an SSL connection. # class MysqlAdapter < AbstractMysqlAdapter + class Column < AbstractMysqlAdapter::Column #:nodoc: def self.string_to_time(value) return super unless Mysql::Time === value @@ -82,13 +83,8 @@ module ActiveRecord new_date(v.year, v.month, v.day) end - private - - # FIXME: Combine with the mysql2 version and move to abstract adapter - def simplified_type(field_type) - return :boolean if MysqlAdapter.emulate_booleans && field_type.downcase.index("tinyint(1)") - return :string if field_type =~ /enum/i - super + def adapter + MysqlAdapter end end From fd22d040fef48778a519825dd2f0cf2fd73a8965 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Mon, 29 Aug 2011 12:43:17 +0100 Subject: [PATCH 331/345] Move the bulk alter table code into the abstract mysql adapter, hence it is supported for mysql2 as well now. --- activerecord/CHANGELOG | 2 + .../abstract_mysql_adapter.rb | 42 +++++++++++++++++ .../connection_adapters/mysql_adapter.rb | 47 ------------------- 3 files changed, 44 insertions(+), 47 deletions(-) diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index e8d4b9c04e..700e11ff94 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,5 +1,7 @@ *Rails 3.2.0 (unreleased)* +* Support bulk change_table in mysql2 adapter, as well as the mysql one. [Jon Leighton] + * If multiple parameters are sent representing a date, and some are blank, the resulting object is nil. In previous releases those values defaulted to 1. This only affects existing but blank parameters, missing ones still raise an error. diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb index 548ca83353..4b7c74e0b8 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -140,6 +140,10 @@ module ActiveRecord true end + def supports_bulk_alter? #:nodoc: + true + end + def native_database_types NATIVE_DATABASE_TYPES end @@ -401,6 +405,21 @@ module ActiveRecord super(table_name, options.reverse_merge(:options => "ENGINE=InnoDB")) end + def bulk_change_table(table_name, operations) #:nodoc: + sqls = operations.map do |command, args| + table, arguments = args.shift, args + method = :"#{command}_sql" + + if respond_to?(method) + send(method, table, *arguments) + else + raise "Unknown method called : #{method}(#{arguments.inspect})" + end + end.flatten.join(", ") + + execute("ALTER TABLE #{quote_table_name(table_name)} #{sqls}") + end + # Renames a table. # # Example: @@ -552,6 +571,29 @@ module ActiveRecord rename_column_sql end + def remove_column_sql(table_name, *column_names) + columns_for_remove(table_name, *column_names).map {|column_name| "DROP #{column_name}" } + end + alias :remove_columns_sql :remove_column + + def add_index_sql(table_name, column_name, options = {}) + index_name, index_type, index_columns = add_index_options(table_name, column_name, options) + "ADD #{index_type} INDEX #{index_name} (#{index_columns})" + end + + def remove_index_sql(table_name, options = {}) + index_name = index_name_for_remove(table_name, options) + "DROP INDEX #{index_name}" + end + + def add_timestamps_sql(table_name) + [add_column_sql(table_name, :created_at, :datetime), add_column_sql(table_name, :updated_at, :datetime)] + end + + def remove_timestamps_sql(table_name) + [remove_column_sql(table_name, :updated_at), remove_column_sql(table_name, :created_at)] + end + private def supports_views? diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index 182db65165..e9bdcc2104 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -97,11 +97,6 @@ module ActiveRecord connect end - # FIXME: Move to abstract adapter - def supports_bulk_alter? #:nodoc: - true - end - # Returns true, since this connection adapter supports prepared statement # caching. def supports_statement_cache? @@ -312,48 +307,6 @@ module ActiveRecord # Transactions aren't supported end - # SCHEMA STATEMENTS ======================================== - - def bulk_change_table(table_name, operations) #:nodoc: - sqls = operations.map do |command, args| - table, arguments = args.shift, args - method = :"#{command}_sql" - - if respond_to?(method) - send(method, table, *arguments) - else - raise "Unknown method called : #{method}(#{arguments.inspect})" - end - end.flatten.join(", ") - - execute("ALTER TABLE #{quote_table_name(table_name)} #{sqls}") - end - - protected - - def remove_column_sql(table_name, *column_names) - columns_for_remove(table_name, *column_names).map {|column_name| "DROP #{column_name}" } - end - alias :remove_columns_sql :remove_column - - def add_index_sql(table_name, column_name, options = {}) - index_name, index_type, index_columns = add_index_options(table_name, column_name, options) - "ADD #{index_type} INDEX #{index_name} (#{index_columns})" - end - - def remove_index_sql(table_name, options = {}) - index_name = index_name_for_remove(table_name, options) - "DROP INDEX #{index_name}" - end - - def add_timestamps_sql(table_name) - [add_column_sql(table_name, :created_at, :datetime), add_column_sql(table_name, :updated_at, :datetime)] - end - - def remove_timestamps_sql(table_name) - [remove_column_sql(table_name, :updated_at), remove_column_sql(table_name, :created_at)] - end - private def exec_stmt(sql, name, binds) From 735d985b0162976e7e900cf36d4cbb0d657fb5e9 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Mon, 29 Aug 2011 15:01:17 +0100 Subject: [PATCH 332/345] The join_nodes must be passed to the JoinDependency initializer and therefore counted by the alias tracker. This is because the association_joins are aliased on initialization and then the tables are cached, so it is no use to alias the join_nodes later. Fixes #2556. --- .../associations/alias_tracker.rb | 18 ++++++++++++------ .../active_record/relation/query_methods.rb | 9 ++------- .../has_many_through_associations_test.rb | 4 ++++ activerecord/test/models/toy.rb | 2 ++ 4 files changed, 20 insertions(+), 13 deletions(-) diff --git a/activerecord/lib/active_record/associations/alias_tracker.rb b/activerecord/lib/active_record/associations/alias_tracker.rb index 92ed844a2e..0248c7483c 100644 --- a/activerecord/lib/active_record/associations/alias_tracker.rb +++ b/activerecord/lib/active_record/associations/alias_tracker.rb @@ -53,12 +53,18 @@ module ActiveRecord # quoted_name should be downcased as some database adapters (Oracle) return quoted name in uppercase quoted_name = connection.quote_table_name(name).downcase - table_joins.map { |join| - # Table names + table aliases - join.left.downcase.scan( - /join(?:\s+\w+)?\s+(\S+\s+)?#{quoted_name}\son/ - ).size - }.sum + counts = table_joins.map do |join| + if join.is_a?(Arel::Nodes::StringJoin) + # Table names + table aliases + join.left.downcase.scan( + /join(?:\s+\w+)?\s+(\S+\s+)?#{quoted_name}\son/ + ).size + else + join.left.table_name == name ? 1 : 0 + end + end + + counts.sum end def truncate(name) diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 1654ae1eac..7eda9ad8e8 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -254,12 +254,12 @@ module ActiveRecord association_joins = buckets['association_join'] || [] stashed_association_joins = buckets['stashed_join'] || [] - join_nodes = buckets['join_node'] || [] + join_nodes = (buckets['join_node'] || []).uniq string_joins = (buckets['string_join'] || []).map { |x| x.strip }.uniq - join_list = custom_join_ast(manager, string_joins) + join_list = join_nodes + custom_join_ast(manager, string_joins) join_dependency = ActiveRecord::Associations::JoinDependency.new( @klass, @@ -267,10 +267,6 @@ module ActiveRecord join_list ) - join_nodes.each do |join| - join_dependency.alias_tracker.aliased_name_for(join.left.name.downcase) - end - join_dependency.graft(*stashed_association_joins) @implicit_readonly = true unless association_joins.empty? && stashed_association_joins.empty? @@ -280,7 +276,6 @@ module ActiveRecord association.join_to(manager) end - manager.join_sources.concat join_nodes.uniq manager.join_sources.concat join_list manager diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb index 5f2328ff95..b703c96ec1 100644 --- a/activerecord/test/cases/associations/has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb @@ -821,4 +821,8 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase assert person.posts.loaded?, 'person.posts should be loaded' assert_equal [], person.posts end + + def test_explicitly_joining_join_table + assert_equal owners(:blackbeard).toys, owners(:blackbeard).toys.with_pet + end end diff --git a/activerecord/test/models/toy.rb b/activerecord/test/models/toy.rb index 79a88db0da..6c45e99671 100644 --- a/activerecord/test/models/toy.rb +++ b/activerecord/test/models/toy.rb @@ -1,4 +1,6 @@ class Toy < ActiveRecord::Base set_primary_key :toy_id belongs_to :pet + + scope :with_pet, joins(:pet) end From c59c9bb8bc275a2be8695d4d431a0512d29353f1 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Mon, 29 Aug 2011 17:39:09 +0100 Subject: [PATCH 333/345] Move clear_timestamp_attributes into Timestamp module --- activerecord/lib/active_record/base.rb | 10 +--------- activerecord/lib/active_record/timestamp.rb | 14 +++++++++++++- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 03aea81d2c..374791deb1 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1849,7 +1849,7 @@ MSG ensure_proper_type populate_with_current_scope_attributes - clear_timestamp_attributes + super end # Returns +true+ if the record is read only. Records loaded through joins with piggy-back @@ -2113,14 +2113,6 @@ MSG send("#{att}=", value) if respond_to?("#{att}=") end end - - # Clear attributes and changed_attributes - def clear_timestamp_attributes - all_timestamp_attributes_in_model.each do |attribute_name| - self[attribute_name] = nil - changed_attributes.delete(attribute_name) - end - end end Base.class_eval do diff --git a/activerecord/lib/active_record/timestamp.rb b/activerecord/lib/active_record/timestamp.rb index 1511c71ffc..6b8c52861e 100644 --- a/activerecord/lib/active_record/timestamp.rb +++ b/activerecord/lib/active_record/timestamp.rb @@ -37,6 +37,11 @@ module ActiveRecord self.record_timestamps = true end + def initialize_dup(other) + clear_timestamp_attributes + super + end + private def create #:nodoc: @@ -95,6 +100,13 @@ module ActiveRecord def current_time_from_proper_timezone #:nodoc: self.class.default_timezone == :utc ? Time.now.utc : Time.now end + + # Clear attributes and changed_attributes + def clear_timestamp_attributes + all_timestamp_attributes_in_model.each do |attribute_name| + self[attribute_name] = nil + changed_attributes.delete(attribute_name) + end + end end end - From 92619e4f78e9417dbfa3e22acce25ff343f45f0b Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Mon, 29 Aug 2011 23:04:50 +0100 Subject: [PATCH 334/345] Fix test failures on 1.8.7, since Object#initialize_dup is not defined there (and this call to super is no essential, so easiest to simply remove) --- activerecord/lib/active_record/timestamp.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/activerecord/lib/active_record/timestamp.rb b/activerecord/lib/active_record/timestamp.rb index 6b8c52861e..cccac6ffd7 100644 --- a/activerecord/lib/active_record/timestamp.rb +++ b/activerecord/lib/active_record/timestamp.rb @@ -39,7 +39,6 @@ module ActiveRecord def initialize_dup(other) clear_timestamp_attributes - super end private From 5aa86f793f4df75f8a5780626269abc3511c61a0 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Mon, 29 Aug 2011 15:47:56 -0700 Subject: [PATCH 335/345] let SDoc add a link to the source code in GitHub for each method --- Rakefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Rakefile b/Rakefile index ae857036c5..f171949961 100755 --- a/Rakefile +++ b/Rakefile @@ -93,6 +93,7 @@ RDoc::Task.new do |rdoc| rdoc.options << '-f' << 'sdoc' rdoc.options << '-T' << 'rails' rdoc.options << '-c' << 'utf-8' + rdoc.options << '-g' # SDoc flag, link methods to GitHub rdoc.options << '-m' << RDOC_MAIN rdoc.rdoc_files.include('railties/CHANGELOG') From 725617a6475703270a9afd59f1cf91ac3297720a Mon Sep 17 00:00:00 2001 From: Daniel Schierbeck Date: Mon, 22 Aug 2011 19:21:35 +0200 Subject: [PATCH 336/345] Document the Sprockets compressors Add documentation to Sprockets::NullCompressor and Sprockets::LazyCompressor. Also, make LazyCompressor#compressor private, as it isn't part of the public API. --- actionpack/lib/sprockets/compressors.rb | 30 +++++++++++++++++++------ 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/actionpack/lib/sprockets/compressors.rb b/actionpack/lib/sprockets/compressors.rb index 6544953df4..351eff1085 100644 --- a/actionpack/lib/sprockets/compressors.rb +++ b/actionpack/lib/sprockets/compressors.rb @@ -1,21 +1,37 @@ module Sprockets - class NullCompressor + # An asset compressor which does nothing. + # + # This compressor simply returns the asset as-is, without any compression + # whatsoever. It is useful in development mode, when compression isn't + # needed but using the same asset pipeline as production is desired. + class NullCompressor #:nodoc: def compress(content) content end end - class LazyCompressor + # An asset compressor which only initializes the underlying compression + # engine when needed. + # + # This postpones the initialization of the compressor until + # #compress is called the first time. + class LazyCompressor #:nodoc: + # Initializes a new LazyCompressor. + # + # The block should return a compressor when called, i.e. an object + # which responds to #compress. def initialize(&block) @block = block end - def compressor - @compressor ||= @block.call || NullCompressor.new - end - def compress(content) compressor.compress(content) end + + private + + def compressor + @compressor ||= (@block.call || NullCompressor.new) + end end -end \ No newline at end of file +end From bd4bd3f50a7e3a8efd8f24612765a7f16e520748 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Tue, 30 Aug 2011 09:56:42 -0700 Subject: [PATCH 337/345] Merge pull request #2750 from rsim/fix_test_column_names_are_escaped_for_oracle Fix test column names are escaped for oracle --- activerecord/test/cases/base_test.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index bee183cc67..1e647b5970 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -81,7 +81,13 @@ class BasicsTest < ActiveRecord::TestCase } quoted = conn.quote_column_name "foo#{badchar}bar" - assert_equal("#{badchar}foo#{badchar * 2}bar#{badchar}", quoted) + if current_adapter?(:OracleAdapter) + # Oracle does not allow double quotes in table and column names at all + # therefore quoting removes them + assert_equal("#{badchar}foobar#{badchar}", quoted) + else + assert_equal("#{badchar}foo#{badchar * 2}bar#{badchar}", quoted) + end end def test_columns_should_obey_set_primary_key From 2350fecd2251584d770afc4bd1764b3fe526ff70 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Tue, 30 Aug 2011 13:48:16 -0700 Subject: [PATCH 338/345] adds the asset pipeline guide to the index --- railties/guides/source/asset_pipeline.textile | 2 +- railties/guides/source/index.html.erb | 4 ++++ railties/guides/source/layout.html.erb | 3 ++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/railties/guides/source/asset_pipeline.textile b/railties/guides/source/asset_pipeline.textile index 554246acb3..2695ba9ec1 100644 --- a/railties/guides/source/asset_pipeline.textile +++ b/railties/guides/source/asset_pipeline.textile @@ -1,6 +1,6 @@ h2. Asset Pipeline -This guide covers the ideology of the asset pipeline introduced in Rails 3.1. +This guide covers the asset pipeline introduced in Rails 3.1. By referring to this guide you will be able to: * Understand what the asset pipeline is and what it does diff --git a/railties/guides/source/index.html.erb b/railties/guides/source/index.html.erb index 684251962c..b7813086d7 100644 --- a/railties/guides/source/index.html.erb +++ b/railties/guides/source/index.html.erb @@ -131,6 +131,10 @@ Ruby on Rails Guides <%= guide("Caching with Rails", 'caching_with_rails.html', :work_in_progress => true) do %>

Various caching techniques provided by Rails.

<% end %> + +<%= guide('Asset Pipeline', 'asset_pipeline.html') do %> +

This guide documents the asset pipeline.

+<% end %>

Extending Rails

diff --git a/railties/guides/source/layout.html.erb b/railties/guides/source/layout.html.erb index 5dcac8e74c..5f8ee57517 100644 --- a/railties/guides/source/layout.html.erb +++ b/railties/guides/source/layout.html.erb @@ -5,7 +5,7 @@ -<%= yield(:page_title) || 'Ruby on Rails guides' %> +<%= yield(:page_title) || 'Ruby on Rails Guides' %> @@ -71,6 +71,7 @@
Configuring Rails Applications
Rails Command Line Tools and Rake Tasks
Caching with Rails
+
Asset Pipeline
Extending Rails
The Basics of Creating Rails Plugins
From 60d8e4ac28726d04d029b25cff82181a9b0ab5c3 Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Tue, 30 Aug 2011 20:37:16 +0300 Subject: [PATCH 339/345] Ensure correct ordering of results in test_update_all_with_joins_and_offset_and_order Last two asserts in this test assume that all_comments are ordered by posts.id and then by comments.id therefore additional ordering is added. Without it test was failing on Oracle which returned results in different order. --- activerecord/test/cases/relations_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index 615551a279..da96afd718 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -1018,7 +1018,7 @@ class RelationTest < ActiveRecord::TestCase end def test_update_all_with_joins_and_offset_and_order - all_comments = Comment.joins(:post).where('posts.id' => posts(:welcome).id).order('posts.id') + all_comments = Comment.joins(:post).where('posts.id' => posts(:welcome).id).order('posts.id', 'comments.id') count = all_comments.count comments = all_comments.offset(1) From e5f2b0d75f29cd7d9e11e8008d410caf48ab1078 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 30 Aug 2011 20:47:01 -0300 Subject: [PATCH 340/345] Revert "Merge pull request #2647 from dmathieu/no_rescue" This reverts commit 125b1b0b9180ec8f0135da185e77250d2b8a4bea. --- actionpack/lib/sprockets/helpers/rails_helper.rb | 8 ++++++-- actionpack/test/abstract_unit.rb | 6 +----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/actionpack/lib/sprockets/helpers/rails_helper.rb b/actionpack/lib/sprockets/helpers/rails_helper.rb index 7a2bf8bef6..062aa4dae5 100644 --- a/actionpack/lib/sprockets/helpers/rails_helper.rb +++ b/actionpack/lib/sprockets/helpers/rails_helper.rb @@ -58,8 +58,12 @@ module Sprockets private def debug_assets? - config = Rails.application.config.assets - config.allow_debugging && (config.debug || params[:debug_assets]) + begin + config = Rails.application.config.assets + config.allow_debugging && (config.debug || params[:debug_assets]) + rescue NoMethodError + false + end end # Override to specify an alternative prefix for asset path generation. diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index aa7a01f6c9..24d071df39 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -142,11 +142,7 @@ class RoutedRackApp end class BasicController - attr_accessor :request, :params - - def initialize - @params = {} - end + attr_accessor :request def config @config ||= ActiveSupport::InheritableOptions.new(ActionController::Base.config).tap do |config| From f4492b8656f7a1937a574d9a8ea1f065e10df36d Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 30 Aug 2011 22:49:03 -0300 Subject: [PATCH 341/345] Bump sprockets up --- actionpack/actionpack.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec index 59d5bbc5ed..65b364f872 100644 --- a/actionpack/actionpack.gemspec +++ b/actionpack/actionpack.gemspec @@ -24,7 +24,7 @@ Gem::Specification.new do |s| s.add_dependency('rack', '~> 1.3.2') s.add_dependency('rack-test', '~> 0.6.1') s.add_dependency('rack-mount', '~> 0.8.2') - s.add_dependency('sprockets', '~> 2.0.0.beta.15') + s.add_dependency('sprockets', '~> 2.0.0') s.add_dependency('erubis', '~> 2.7.0') s.add_development_dependency('tzinfo', '~> 0.3.29') From 331dad14bc0623a8b1f24be88f2933c20c346c74 Mon Sep 17 00:00:00 2001 From: Ray Baxter Date: Tue, 30 Aug 2011 22:32:09 -0700 Subject: [PATCH 342/345] don't need edgeapi now that we are on 3.1 --- railties/guides/source/3_1_release_notes.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/guides/source/3_1_release_notes.textile b/railties/guides/source/3_1_release_notes.textile index 087926f98d..156987efc4 100644 --- a/railties/guides/source/3_1_release_notes.textile +++ b/railties/guides/source/3_1_release_notes.textile @@ -170,7 +170,7 @@ class PostsController < ActionController::Base end -You can restrict it to some actions by using +:only+ or +:except+. Please read the docs at "ActionController::Streaming":http://edgeapi.rubyonrails.org/classes/ActionController/Streaming.html for more information. +You can restrict it to some actions by using +:only+ or +:except+. Please read the docs at "ActionController::Streaming":http://api.rubyonrails.org/classes/ActionController/Streaming.html for more information. * The redirect route method now also accepts a hash of options which will only change the parts of the url in question, or an object which responds to call, allowing for redirects to be reused. From 73263f6c81936b199f7410991a23ea380a58e005 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Wed, 31 Aug 2011 01:44:59 -0700 Subject: [PATCH 343/345] adds the release notes of 3.1 to the index --- railties/guides/source/index.html.erb | 4 ++++ railties/guides/source/layout.html.erb | 1 + 2 files changed, 5 insertions(+) diff --git a/railties/guides/source/index.html.erb b/railties/guides/source/index.html.erb index b7813086d7..214155c088 100644 --- a/railties/guides/source/index.html.erb +++ b/railties/guides/source/index.html.erb @@ -174,6 +174,10 @@ Ruby on Rails Guides

Release Notes

+<%= guide("Ruby on Rails 3.1 Release Notes", '3_1_release_notes.html') do %> +

Release notes for Rails 3.1.

+<% end %> + <%= guide("Ruby on Rails 3.0 Release Notes", '3_0_release_notes.html') do %>

Release notes for Rails 3.0.

<% end %> diff --git a/railties/guides/source/layout.html.erb b/railties/guides/source/layout.html.erb index 5f8ee57517..3ccbc3a477 100644 --- a/railties/guides/source/layout.html.erb +++ b/railties/guides/source/layout.html.erb @@ -84,6 +84,7 @@
Ruby on Rails Guides Guidelines
Release Notes
+
Ruby on Rails 3.1 Release Notes
Ruby on Rails 3.0 Release Notes
Ruby on Rails 2.3 Release Notes
Ruby on Rails 2.2 Release Notes
From d7be97ec31f5d972e01fb11b05ca4b36f581c779 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Wed, 31 Aug 2011 01:52:43 -0700 Subject: [PATCH 344/345] release notes: adds a couple of blank lines to get the markup right --- railties/guides/source/3_1_release_notes.textile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/railties/guides/source/3_1_release_notes.textile b/railties/guides/source/3_1_release_notes.textile index 087926f98d..9ca77d0657 100644 --- a/railties/guides/source/3_1_release_notes.textile +++ b/railties/guides/source/3_1_release_notes.textile @@ -346,6 +346,7 @@ has_many :things, :conditions => proc { "foo = #{bar}" } # after Inside the proc, +self+ is the object which is the owner of the association, unless you are eager loading the association, in which case +self+ is the class which the association is within. You can have any "normal" conditions inside the proc, so the following will work too: + has_many :things, :conditions => proc { ["foo = ?", bar] } @@ -353,6 +354,7 @@ has_many :things, :conditions => proc { ["foo = ?", bar] } * Previously +:insert_sql+ and +:delete_sql+ on +has_and_belongs_to_many+ association allowed you to call 'record' to get the record being inserted or deleted. This is now passed as an argument to the proc. * Added ActiveRecord::Base#has_secure_password (via ActiveModel::SecurePassword) to encapsulate dead-simple password usage with BCrypt encryption and salting. + # Schema: User(name:string, password_digest:string, password_salt:string) class User < ActiveRecord::Base From e746c4047cd34accd7f63aa5d09cbb35011c24e2 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Wed, 31 Aug 2011 02:04:36 -0700 Subject: [PATCH 345/345] syncs assets guide with what's in 3-1-stable --- railties/guides/source/asset_pipeline.textile | 38 +++++++++++++------ 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/railties/guides/source/asset_pipeline.textile b/railties/guides/source/asset_pipeline.textile index 2695ba9ec1..96b11dbf63 100644 --- a/railties/guides/source/asset_pipeline.textile +++ b/railties/guides/source/asset_pipeline.textile @@ -15,7 +15,7 @@ h3. What is the Asset Pipeline? The asset pipeline provides a framework to concatenate and minify or compress JavaScript and CSS assets. It also adds the ability to write these assets in other languages such as CoffeeScript, SCSS and ERB. -Prior to Rails 3.1 these features were added through third-party Ruby libraries such as Jammit and Sprockets. Rails 3.1 includes the +sprockets-rails+ gem, which depends on the +sprockets+ gem, by default. +Prior to Rails 3.1 these features were added through third-party Ruby libraries such as Jammit and Sprockets. Rails 3.1 is integrated with Sprockets throught ActionPack which depends on the +sprockets+ gem, by default. By having this as a core feature of Rails, all developers can benefit from the power of having their assets pre-processed, compressed and minified by one central library, Sprockets. This is part of Rails' "Fast by default" strategy as outlined by DHH in his 2011 keynote at Railsconf. @@ -27,6 +27,7 @@ config.assets.enabled = false It is recommended that you use the defaults for all new apps. + h4. Main Features The first feature of the pipeline is to concatenate assets. This is important in a production environment, as it reduces the number of requests that a browser must make to render a web page. While Rails already has a feature to concatenate these types of assets -- by placing +:cache => true+ at the end of tags such as +javascript_include_tag+ and +stylesheet_link_tag+ -- many people do not use it. @@ -74,11 +75,14 @@ The other problem is that when static assets are deployed with each new release Fingerprinting avoids all these problems by ensuring filenames are consistent based on their content. +Fingerprinting is enabled by default for production and disabled for all the others environments. You can enable or disable it in your configuration through the +config.assets.digest+ option. + More reading: * "Optimize caching":http://code.google.com/speed/page-speed/docs/caching.html * "Revving Filenames: don’t use querystring":http://www.stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring/ + h3. How to Use the Asset Pipeline In previous versions of Rails, all assets were located in subdirectories of +public+ such as +images+, +javascripts+ and +stylesheets+. With the asset pipeline, the preferred location for these assets is now the +app/assets+ directory. Files in this directory are served by the Sprockets middleware included in the sprockets gem. @@ -247,14 +251,7 @@ When the +debug_assets+ parameter is set, this line is expanded out into three s This allows the individual parts of an asset to be rendered and debugged separately. -Additionally if the +config.assets.debug+ is set to true you can debug your assets passing the +:debug+ option to the assets tags: - - -<%= javascript_include_tag :application, :debug => true %> - - - -NOTE. Assets debugging is turned on by default in development and test environments. You can set +config.assets.allow_debugging+ to false to turn it off. +NOTE. Assets debugging is turned on by default in development and test environments. h3. In Production @@ -271,7 +268,7 @@ The MD5 is generated from the contents of the compiled files, and is included in Sprockets also sets the +Cache-Control+ HTTP header to +max-age=31536000+. This signals all caches between your server and the client browser that this content (the file served) can be cached for 1 year. The effect of this is to reduce the number of requests for this asset from your server; the asset has a good chance of being in the local browser cache or some intermediate cache. -This behavior is controlled by the setting of +config.action_controller.perform_caching+ setting in Rails (which is +true+ for production, +false+ for everything else). This value is propagated to Sprockets during initialization for use when action_controller is not available. +This behavior is controlled by the setting of +config.assets.digest+ setting in Rails (which is +true+ for production, +false+ for everything else). h4. Precompiling Assets @@ -307,6 +304,20 @@ If you have other manifests or individual stylesheets and JavaScript files to in config.assets.precompile += ['admin.js', 'admin.css', 'swfObject.js'] +The rake task also generates a +manifest.yml+ that contains a list with all your assets and their fingerprints, using this manifest file the assets helpers avoid hitting to Sprockets to recalculate MD5 hashes for files. Manifest file typically look like this: + + +--- +rails.png: rails-bd9ad5a560b5a3a7be0808c5cd76a798.png +jquery-ui.min.js: jquery-ui-7e33882a28fc84ad0e0e47e46cbf901c.min.js +jquery.min.js: jquery-8a50feed8d29566738ad005e19fe1c2d.min.js +application.js: application-3fdab497b8fb70d20cfc5495239dfc29.js +application.css: application-8af74128f904600e41a6e39241464e03.css + + +The manifest file is generated by default in same folder of your precompiled assets, you can change the location of the file setting the +config.assets.manifest+ option with the full path of the folder where you want save it. + + Precompiled assets exist on the filesystem and are served directly by your webserver. They do not have far-future headers by default, so to get the benefit of fingerprinting you'll have to update your server configuration to add them. For Apache: @@ -325,12 +336,16 @@ For Apache: -TODO: NGINX instructions +TODO: nginx instructions When files are precompiled, Sprockets also creates a "Gzip":http://en.wikipedia.org/wiki/Gzip (.gz) version of your assets. This avoids the server having to do this for any requests; it can simply read the compressed files from disc. You must configure your server to use gzip compression and serve the compressed assets that will be stored in the public/assets folder. The following configuration options can be used: TODO: Apache instructions +TODO: nginx instructions + +By default Rails assumes that you have your files precompiled in the production environment, if you want use live compiling (compile your assets during runtime) in production you must set the +config.assets.compile+ to true. You can use this option to fallback to Sprockets when you are using precompiled assets but there are any missing precompiled files. If +config.assets.compile+ option is set to false and there are missing precompiled files you will get an "AssetNoPrecompiledError" indicating the name of the missing file. + h3. Customizing the Pipeline @@ -378,6 +393,7 @@ To enable this, pass a +new+ Object to the config option in +application.rb+: config.assets.css_compressor = Transformer.new + h4. Changing the _assets_ Path The public path that Sprockets uses by default is +/assets+.