diff options
38 files changed, 332 insertions, 56 deletions
diff --git a/.gitignore b/.gitignore index 854fdbf450..a3a5304ecd 100644 --- a/.gitignore +++ b/.gitignore @@ -4,8 +4,7 @@ debug.log .Gemfile /.bundle -/.rbenv-version -/.rvmrc +/.ruby-version /Gemfile.lock /pkg /dist diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index fec35a36bd..d6a2687037 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,5 +1,18 @@ ## Rails 4.0.0 (unreleased) ## +* We don't support the `:controller` option for route definitions + with the ruby constant notation. This will now result in an + `ArgumentError`. + + Example: + # This raises an ArgumentError: + resources :posts, :controller => "Admin::Posts" + + # Use directory notation instead: + resources :posts, :controller => "admin/posts" + + *Yves Senn* + * `assert_template` can be used to verify the locals of partials, which live inside a directory. Fixes #8516. diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec index 70a1975ee9..008f17bceb 100644 --- a/actionpack/actionpack.gemspec +++ b/actionpack/actionpack.gemspec @@ -21,7 +21,7 @@ Gem::Specification.new do |s| s.add_dependency 'activesupport', version s.add_dependency 'builder', '~> 3.1.0' - s.add_dependency 'rack', '~> 1.5.0' + s.add_dependency 'rack', '~> 1.5.2' s.add_dependency 'rack-test', '~> 0.6.1' s.add_dependency 'erubis', '~> 2.7.0' diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb index 77b173979e..17379cf7ac 100644 --- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb +++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb @@ -126,7 +126,7 @@ module ActionController #:nodoc: host = request.host secure = request.ssl? - new(key_generator, host, secure) + new(key_generator, host, secure, options_for_env({})) end def write(*) diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb index 0f02d230d4..fff26bd1b2 100644 --- a/actionpack/lib/action_dispatch/middleware/cookies.rb +++ b/actionpack/lib/action_dispatch/middleware/cookies.rb @@ -1,5 +1,6 @@ require 'active_support/core_ext/hash/keys' require 'active_support/core_ext/module/attribute_accessors' +require 'active_support/key_generator' require 'active_support/message_verifier' module ActionDispatch @@ -110,13 +111,17 @@ module ActionDispatch # $& => example.local DOMAIN_REGEXP = /[^.]*\.([^.]*|..\...|...\...)$/ + def self.options_for_env(env) #:nodoc: + { signed_cookie_salt: env[SIGNED_COOKIE_SALT] || '', + encrypted_cookie_salt: env[ENCRYPTED_COOKIE_SALT] || '', + encrypted_signed_cookie_salt: env[ENCRYPTED_SIGNED_COOKIE_SALT] || '', + token_key: env[TOKEN_KEY] } + end + def self.build(request) env = request.env key_generator = env[GENERATOR_KEY] - options = { signed_cookie_salt: env[SIGNED_COOKIE_SALT], - encrypted_cookie_salt: env[ENCRYPTED_COOKIE_SALT], - encrypted_signed_cookie_salt: env[ENCRYPTED_SIGNED_COOKIE_SALT], - token_key: env[TOKEN_KEY] } + options = options_for_env env host = request.host secure = request.ssl? diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 82ef1d0333..0a41ed0fcf 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -246,6 +246,12 @@ module ActionDispatch raise ArgumentError, "missing :action" end + if controller.is_a?(String) && controller !~ /\A[a-z_0-9\/]*\z/ + message = "'#{controller}' is not a supported controller name. This can lead to potential routing problems." + message << " See http://guides.rubyonrails.org/routing.html#specifying-a-controller-to-use" + raise ArgumentError, message + end + hash = {} hash[:controller] = controller unless controller.blank? hash[:action] = action unless action.blank? diff --git a/actionpack/test/controller/request_forgery_protection_test.rb b/actionpack/test/controller/request_forgery_protection_test.rb index 7571192f97..c272e785c2 100644 --- a/actionpack/test/controller/request_forgery_protection_test.rb +++ b/actionpack/test/controller/request_forgery_protection_test.rb @@ -66,6 +66,19 @@ class RequestForgeryProtectionControllerUsingException < ActionController::Base protect_from_forgery :only => %w(index meta), :with => :exception end +class RequestForgeryProtectionControllerUsingNullSession < ActionController::Base + protect_from_forgery :with => :null_session + + def signed + cookies.signed[:foo] = 'bar' + render :nothing => true + end + + def encrypted + cookies.encrypted[:foo] = 'bar' + render :nothing => true + end +end class FreeCookieController < RequestForgeryProtectionControllerUsingResetSession self.allow_forgery_protection = false @@ -287,6 +300,28 @@ class RequestForgeryProtectionControllerUsingResetSessionTest < ActionController end end +class NullSessionDummyKeyGenerator + def generate_key(secret) + '03312270731a2ed0d11ed091c2338a06' + end +end + +class RequestForgeryProtectionControllerUsingNullSessionTest < ActionController::TestCase + def setup + @request.env[ActionDispatch::Cookies::GENERATOR_KEY] = NullSessionDummyKeyGenerator.new + end + + test 'should allow to set signed cookies' do + post :signed + assert_response :ok + end + + test 'should allow to set encrypted cookies' do + post :encrypted + assert_response :ok + end +end + class RequestForgeryProtectionControllerUsingExceptionTest < ActionController::TestCase include RequestForgeryProtectionTests def assert_blocked diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index 9f31ce8127..143733254b 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -1031,6 +1031,18 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest assert_equal 'users/home#index', @response.body end + def test_namespace_containing_numbers + draw do + namespace :v2 do + resources :subscriptions + end + end + + get '/v2/subscriptions' + assert_equal 'v2/subscriptions#index', @response.body + assert_equal '/v2/subscriptions', v2_subscriptions_path + end + def test_articles_with_id draw do controller :articles do @@ -2833,21 +2845,52 @@ class TestNamespaceWithControllerOption < ActionDispatch::IntegrationTest end end - DefaultScopeRoutes = ActionDispatch::Routing::RouteSet.new - DefaultScopeRoutes.draw do - namespace :admin do - resources :storage_files, :controller => "StorageFiles" - end + def draw(&block) + @app = ActionDispatch::Routing::RouteSet.new + @app.draw(&block) end - def app - DefaultScopeRoutes - end + def test_valid_controller_options_inside_namespace + draw do + namespace :admin do + resources :storage_files, :controller => "storage_files" + end + end - def test_controller_options get '/admin/storage_files' assert_equal "admin/storage_files#index", @response.body end + + def test_resources_with_valid_namespaced_controller_option + draw do + resources :storage_files, :controller => 'admin/storage_files' + end + + get 'storage_files' + assert_equal "admin/storage_files#index", @response.body + end + + def test_warn_with_ruby_constant_syntax_controller_option + e = assert_raise(ArgumentError) do + draw do + namespace :admin do + resources :storage_files, :controller => "StorageFiles" + end + end + end + + assert_match "'admin/StorageFiles' is not a supported controller name", e.message + end + + def test_warn_with_ruby_constant_syntax_namespaced_controller_option + e = assert_raise(ArgumentError) do + draw do + resources :storage_files, :controller => 'Admin::StorageFiles' + end + end + + assert_match "'Admin::StorageFiles' is not a supported controller name", e.message + end end class TestDefaultScope < ActionDispatch::IntegrationTest diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index f8931677ed..27ba1a8d95 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,5 +1,20 @@ ## Rails 4.0.0 (unreleased) ## +* Quote numeric values being compared to non-numeric columns. Otherwise, + in some database, the string column values will be coerced to a numeric + allowing 0, 0.0 or false to match any string starting with a non-digit. + + Example: + + App.where(apikey: 0) # => SELECT * FROM users WHERE apikey = '0' + + *Dylan Smith* + +* Schema dumper supports dumping the enabled database extensions to `schema.rb` + (currently only supported by postgresql). + + *Justin George* + * The `DATABASE_URL` environment variable now converts ints, floats, and the strings true and false to Ruby types. For example, SQLite requires that the timeout value is an integer, and PostgreSQL requires that the @@ -591,7 +606,7 @@ After: - #=> SELECT * FROM users WHERE 1 = 2; + #=> SELECT * FROM users WHERE 1=0; *Damien Mathieu* diff --git a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb index d18b9c991f..aec4654eee 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb @@ -25,13 +25,19 @@ module ActiveRecord when true, false if column && column.type == :integer value ? '1' : '0' + elsif column && [:text, :string, :binary].include?(column.type) + value ? "'1'" : "'0'" else value ? quoted_true : quoted_false end # BigDecimals need to be put in a non-normalized form and quoted. when nil then "NULL" - when BigDecimal then value.to_s('F') - when Numeric, ActiveSupport::Duration then value.to_s + when Numeric, ActiveSupport::Duration + value = BigDecimal === value ? value.to_s('F') : value.to_s + if column && ![:integer, :float, :decimal].include?(column.type) + value = "'#{value}'" + end + value when Date, Time then "'#{quoted_date(value)}'" when Symbol then "'#{quote_string(value.to_s)}'" when Class then "'#{value.to_s}'" diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index b2ad4e600d..26f601bf05 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -177,10 +177,16 @@ module ActiveRecord false end + # A list of extensions, to be filled in by databases that + # support them (at the moment, postgresql). + def extensions + [] + end + # QUOTING ================================================== # Returns a bind substitution value given a +column+ and list of current - # +binds+ + # +binds+. def substitute_at(column, index) Arel::Nodes::BindParam.new '?' end 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 52b0b3fe79..c3512adc5f 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -212,8 +212,6 @@ module ActiveRecord 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 diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 5ce2f1b04c..0818760b11 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -605,6 +605,15 @@ module ActiveRecord end end + def extensions + if supports_extensions? + res = exec_query "SELECT extname from pg_extension", "SCHEMA" + res.rows.map { |r| res.column_types['extname'].type_cast r.first } + else + super + end + end + # Returns the configured supported identifier length supported by PostgreSQL def table_alias_length @table_alias_length ||= query('SHOW max_identifier_length', 'SCHEMA')[0][0].to_i diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb index 537ebbef28..5cd015eba7 100644 --- a/activerecord/lib/active_record/relation/predicate_builder.rb +++ b/activerecord/lib/active_record/relation/predicate_builder.rb @@ -8,7 +8,7 @@ module ActiveRecord if value.is_a?(Hash) if value.empty? - queries << '1 = 2' + queries << '1=0' else table = Arel::Table.new(column, default_table.engine) association = klass.reflect_on_association(column.to_sym) @@ -98,6 +98,11 @@ module ActiveRecord when Class # FIXME: I think we need to deprecate this behavior attribute.eq(value.name) + when Integer, ActiveSupport::Duration + # Arel treats integers as literals, but they should be quoted when compared with strings + table = attribute.relation + column = table.engine.connection.schema_cache.columns_hash(table.name)[attribute.name.to_s] + attribute.eq(Arel::Nodes::SqlLiteral.new(table.engine.connection.quote(value, column))) else attribute.eq(value) end diff --git a/activerecord/lib/active_record/schema_dumper.rb b/activerecord/lib/active_record/schema_dumper.rb index 36bde44e7c..df090b972d 100644 --- a/activerecord/lib/active_record/schema_dumper.rb +++ b/activerecord/lib/active_record/schema_dumper.rb @@ -24,6 +24,7 @@ module ActiveRecord def dump(stream) header(stream) + extensions(stream) tables(stream) trailer(stream) stream @@ -66,6 +67,18 @@ HEADER stream.puts "end" end + def extensions(stream) + return unless @connection.supports_extensions? + extensions = @connection.extensions + if extensions.any? + stream.puts " # These are extensions that must be enabled in order to support this database" + extensions.each do |extension| + stream.puts " enable_extension #{extension.inspect}" + end + stream.puts + end + end + def tables(stream) @connection.tables.sort.each do |tbl| next if ['schema_migrations', ignore_tables].flatten.any? do |ignored| diff --git a/activerecord/test/cases/adapters/postgresql/hstore_test.rb b/activerecord/test/cases/adapters/postgresql/hstore_test.rb index 9498c829dc..6640f9b497 100644 --- a/activerecord/test/cases/adapters/postgresql/hstore_test.rb +++ b/activerecord/test/cases/adapters/postgresql/hstore_test.rb @@ -11,11 +11,18 @@ class PostgresqlHstoreTest < ActiveRecord::TestCase def setup @connection = ActiveRecord::Base.connection + + unless @connection.supports_extensions? + return skip "do not test on PG without hstore" + end + unless @connection.extension_enabled?('hstore') @connection.enable_extension 'hstore' - return skip "do not test on PG without hstore" + @connection.commit_db_transaction end + @connection.reconnect! + @connection.transaction do @connection.create_table('hstores') do |t| t.hstore 'tags', :default => '' @@ -28,6 +35,11 @@ class PostgresqlHstoreTest < ActiveRecord::TestCase @connection.execute 'drop table if exists hstores' end + def test_hstore_included_in_extensions + assert @connection.respond_to?(:extensions), "connection should have a list of extensions" + assert @connection.extensions.include?('hstore'), "extension list should include hstore" + end + def test_hstore_enabled assert @connection.extension_enabled?('hstore') end diff --git a/activerecord/test/cases/quoting_test.rb b/activerecord/test/cases/quoting_test.rb index 3dd11ae89d..0ad05223d4 100644 --- a/activerecord/test/cases/quoting_test.rb +++ b/activerecord/test/cases/quoting_test.rb @@ -122,35 +122,35 @@ module ActiveRecord def test_quote_float float = 1.2 assert_equal float.to_s, @quoter.quote(float, nil) - assert_equal float.to_s, @quoter.quote(float, Object.new) + assert_equal float.to_s, @quoter.quote(float, FakeColumn.new(:float)) end def test_quote_fixnum fixnum = 1 assert_equal fixnum.to_s, @quoter.quote(fixnum, nil) - assert_equal fixnum.to_s, @quoter.quote(fixnum, Object.new) + assert_equal fixnum.to_s, @quoter.quote(fixnum, FakeColumn.new(:integer)) end def test_quote_bignum bignum = 1 << 100 assert_equal bignum.to_s, @quoter.quote(bignum, nil) - assert_equal bignum.to_s, @quoter.quote(bignum, Object.new) + assert_equal bignum.to_s, @quoter.quote(bignum, FakeColumn.new(:integer)) end def test_quote_bigdecimal bigdec = BigDecimal.new((1 << 100).to_s) assert_equal bigdec.to_s('F'), @quoter.quote(bigdec, nil) - assert_equal bigdec.to_s('F'), @quoter.quote(bigdec, Object.new) + assert_equal bigdec.to_s('F'), @quoter.quote(bigdec, FakeColumn.new(:decimal)) end def test_dates_and_times @quoter.extend(Module.new { def quoted_date(value) 'lol' end }) assert_equal "'lol'", @quoter.quote(Date.today, nil) - assert_equal "'lol'", @quoter.quote(Date.today, Object.new) + assert_equal "'lol'", @quoter.quote(Date.today, FakeColumn.new(:date)) assert_equal "'lol'", @quoter.quote(Time.now, nil) - assert_equal "'lol'", @quoter.quote(Time.now, Object.new) + assert_equal "'lol'", @quoter.quote(Time.now, FakeColumn.new(:time)) assert_equal "'lol'", @quoter.quote(DateTime.now, nil) - assert_equal "'lol'", @quoter.quote(DateTime.now, Object.new) + assert_equal "'lol'", @quoter.quote(DateTime.now, FakeColumn.new(:datetime)) end def test_crazy_object diff --git a/activerecord/test/cases/relation/where_test.rb b/activerecord/test/cases/relation/where_test.rb index c43c7601a2..53cdf89b1f 100644 --- a/activerecord/test/cases/relation/where_test.rb +++ b/activerecord/test/cases/relation/where_test.rb @@ -108,5 +108,30 @@ module ActiveRecord assert_equal 4, Edge.where(blank).order("sink_id").to_a.size end end + + def test_where_with_integer_for_string_column + count = Post.where(:title => 0).count + assert_equal 0, count + end + + def test_where_with_float_for_string_column + count = Post.where(:title => 0.0).count + assert_equal 0, count + end + + def test_where_with_boolean_for_string_column + count = Post.where(:title => false).count + assert_equal 0, count + end + + def test_where_with_decimal_for_string_column + count = Post.where(:title => BigDecimal.new(0)).count + assert_equal 0, count + end + + def test_where_with_duration_for_string_column + count = Post.where(:title => 0.seconds).count + assert_equal 0, count + end end end diff --git a/activerecord/test/cases/relation_scoping_test.rb b/activerecord/test/cases/relation_scoping_test.rb index 7388324a0d..8e6c38706f 100644 --- a/activerecord/test/cases/relation_scoping_test.rb +++ b/activerecord/test/cases/relation_scoping_test.rb @@ -391,19 +391,19 @@ class DefaultScopingTest < ActiveRecord::TestCase def test_default_scope_with_inheritance wheres = InheritedPoorDeveloperCalledJamis.all.where_values_hash assert_equal "Jamis", wheres[:name] - assert_equal 50000, wheres[:salary] + assert_equal Arel.sql("50000"), wheres[:salary] end def test_default_scope_with_module_includes wheres = ModuleIncludedPoorDeveloperCalledJamis.all.where_values_hash assert_equal "Jamis", wheres[:name] - assert_equal 50000, wheres[:salary] + assert_equal Arel.sql("50000"), wheres[:salary] end def test_default_scope_with_multiple_calls wheres = MultiplePoorDeveloperCalledJamis.all.where_values_hash assert_equal "Jamis", wheres[:name] - assert_equal 50000, wheres[:salary] + assert_equal Arel.sql("50000"), wheres[:salary] end def test_scope_overwrites_default diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb index cae12e0e3a..bfecc0d1e9 100644 --- a/activerecord/test/cases/schema_dumper_test.rb +++ b/activerecord/test/cases/schema_dumper_test.rb @@ -1,6 +1,5 @@ require "cases/helper" - class SchemaDumperTest < ActiveRecord::TestCase def setup super @@ -231,6 +230,21 @@ class SchemaDumperTest < ActiveRecord::TestCase end if current_adapter?(:PostgreSQLAdapter) + def test_schema_dump_includes_extensions + connection = ActiveRecord::Base.connection + skip unless connection.supports_extensions? + + connection.stubs(:extensions).returns(['hstore']) + output = standard_dump + assert_match "# These are extensions that must be enabled", output + assert_match %r{enable_extension "hstore"}, output + + connection.stubs(:extensions).returns([]) + output = standard_dump + assert_no_match "# These are extensions that must be enabled", output + assert_no_match %r{enable_extension}, output + end + def test_schema_dump_includes_xml_shorthand_definition output = standard_dump if %r{create_table "postgresql_xml_data_type"} =~ output diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index cd9835259a..d789b6cb7a 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -540,6 +540,8 @@ ActiveRecord::Schema.define do create_table :price_estimates, :force => true do |t| t.string :estimate_of_type t.integer :estimate_of_id + t.string :thing_type + t.integer :thing_id t.integer :price end diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index a2e6c62c3e..5f7559b5a6 100644 --- a/activesupport/CHANGELOG.md +++ b/activesupport/CHANGELOG.md @@ -1,5 +1,17 @@ ## Rails 4.0.0 (unreleased) ## +* ActiveSupport::Gzip.compress allows two optional arguments for compression + level and strategy. + + *Beyond* + +* Modify `TimeWithZone#as_json` to include 3 decimal places of sub-second accuracy + by default, which is optional as per the ISO8601 spec, but extremely useful. Also + the default behaviour of Date#toJSON() in recent versions of Chrome, Safari and + Firefox. + + *James Harton* + * Improve `String#squish` to handle Unicode whitespace. *Antoine Lyset* * Standardise on `to_time` returning an instance of `Time` in the local system timezone @@ -14,8 +26,8 @@ *Yves Senn* -* Hash.from_xml raises when it encounters type="symbol" or type="yaml". - Use Hash.from_trusted_xml to parse this XML. +* `Hash.from_xml` raises when it encounters `type="symbol"` or `type="yaml"`. + Use `Hash.from_trusted_xml` to parse this XML. CVE-2013-0156 diff --git a/activesupport/lib/active_support/gzip.rb b/activesupport/lib/active_support/gzip.rb index 6ef33ab683..b837c879bb 100644 --- a/activesupport/lib/active_support/gzip.rb +++ b/activesupport/lib/active_support/gzip.rb @@ -25,9 +25,9 @@ module ActiveSupport end # Compresses a string using gzip. - def self.compress(source) + def self.compress(source, level=Zlib::DEFAULT_COMPRESSION, strategy=Zlib::DEFAULT_STRATEGY) output = Stream.new - gz = Zlib::GzipWriter.new(output) + gz = Zlib::GzipWriter.new(output, level, strategy) gz.write(source) gz.close output.string diff --git a/activesupport/lib/active_support/i18n.rb b/activesupport/lib/active_support/i18n.rb index 188653bd9b..8d8bf02927 100644 --- a/activesupport/lib/active_support/i18n.rb +++ b/activesupport/lib/active_support/i18n.rb @@ -1,4 +1,5 @@ begin + require 'active_support/core_ext/hash/deep_merge' require 'i18n' require 'active_support/lazy_load_hooks' rescue LoadError => e diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb index ff13efa990..0e6d12a186 100644 --- a/activesupport/lib/active_support/time_with_zone.rb +++ b/activesupport/lib/active_support/time_with_zone.rb @@ -154,7 +154,7 @@ module ActiveSupport # # => "2005/02/01 15:15:10 +0000" def as_json(options = nil) if ActiveSupport::JSON::Encoding.use_standard_json_time_format - xmlschema + xmlschema(3) else %(#{time.strftime("%Y/%m/%d %H:%M:%S")} #{formatted_offset(false)}) end diff --git a/activesupport/test/core_ext/time_with_zone_test.rb b/activesupport/test/core_ext/time_with_zone_test.rb index 18eca4cd8b..c2b3676aac 100644 --- a/activesupport/test/core_ext/time_with_zone_test.rb +++ b/activesupport/test/core_ext/time_with_zone_test.rb @@ -75,7 +75,7 @@ class TimeWithZoneTest < ActiveSupport::TestCase def test_to_json_with_use_standard_json_time_format_config_set_to_true old, ActiveSupport.use_standard_json_time_format = ActiveSupport.use_standard_json_time_format, true - assert_equal "\"1999-12-31T19:00:00-05:00\"", ActiveSupport::JSON.encode(@twz) + assert_equal "\"1999-12-31T19:00:00.000-05:00\"", ActiveSupport::JSON.encode(@twz) ensure ActiveSupport.use_standard_json_time_format = old end diff --git a/activesupport/test/gzip_test.rb b/activesupport/test/gzip_test.rb index 75a0505899..0e3cf3b429 100644 --- a/activesupport/test/gzip_test.rb +++ b/activesupport/test/gzip_test.rb @@ -4,6 +4,12 @@ require 'active_support/core_ext/object/blank' class GzipTest < ActiveSupport::TestCase def test_compress_should_decompress_to_the_same_value assert_equal "Hello World", ActiveSupport::Gzip.decompress(ActiveSupport::Gzip.compress("Hello World")) + assert_equal "Hello World", ActiveSupport::Gzip.decompress(ActiveSupport::Gzip.compress("Hello World", Zlib::NO_COMPRESSION)) + assert_equal "Hello World", ActiveSupport::Gzip.decompress(ActiveSupport::Gzip.compress("Hello World", Zlib::BEST_SPEED)) + assert_equal "Hello World", ActiveSupport::Gzip.decompress(ActiveSupport::Gzip.compress("Hello World", Zlib::BEST_COMPRESSION)) + assert_equal "Hello World", ActiveSupport::Gzip.decompress(ActiveSupport::Gzip.compress("Hello World", nil, Zlib::FILTERED)) + assert_equal "Hello World", ActiveSupport::Gzip.decompress(ActiveSupport::Gzip.compress("Hello World", nil, Zlib::HUFFMAN_ONLY)) + assert_equal "Hello World", ActiveSupport::Gzip.decompress(ActiveSupport::Gzip.compress("Hello World", nil, nil)) end def test_compress_should_return_a_binary_string @@ -12,4 +18,16 @@ class GzipTest < ActiveSupport::TestCase assert_equal Encoding.find('binary'), compressed.encoding assert !compressed.blank?, "a compressed blank string should not be blank" end + + def test_compress_should_return_gzipped_string_by_compression_level + source_string = "Hello World"*100 + + gzipped_by_speed = ActiveSupport::Gzip.compress(source_string, Zlib::BEST_SPEED) + assert_equal 1, Zlib::GzipReader.new(StringIO.new(gzipped_by_speed)).level + + gzipped_by_best_compression = ActiveSupport::Gzip.compress(source_string, Zlib::BEST_COMPRESSION) + assert_equal 9, Zlib::GzipReader.new(StringIO.new(gzipped_by_best_compression)).level + + assert_equal true, (gzipped_by_best_compression.bytesize < gzipped_by_speed.bytesize) + end end diff --git a/guides/source/4_0_release_notes.md b/guides/source/4_0_release_notes.md index a678dd9d90..9c157ec0b3 100644 --- a/guides/source/4_0_release_notes.md +++ b/guides/source/4_0_release_notes.md @@ -3,7 +3,7 @@ Ruby on Rails 4.0 Release Notes Highlights in Rails 4.0: -* Ruby 1.9.3 only +* Ruby 2.0 preferred; 1.9.3+ required * Strong Parameters * Turbolinks * Russian Doll Caching diff --git a/guides/source/getting_started.md b/guides/source/getting_started.md index c394f30c38..87f5e43157 100644 --- a/guides/source/getting_started.md +++ b/guides/source/getting_started.md @@ -21,7 +21,7 @@ application from scratch. It does not assume that you have any prior experience with Rails. However, to get the most out of it, you need to have some prerequisites installed: -* The [Ruby](http://www.ruby-lang.org/en/downloads) language version 1.9.3 or higher +* The [Ruby](http://www.ruby-lang.org/en/downloads) language version 1.9.3 or newer * The [RubyGems](http://rubygems.org/) packaging system * To learn more about RubyGems, please read the [RubyGems User Guide](http://docs.rubygems.org/read/book/1) * A working installation of the [SQLite3 Database](http://www.sqlite.org) @@ -84,7 +84,7 @@ current version of Ruby installed: ```bash $ ruby -v -ruby 1.9.3p327 +ruby 1.9.3p385 ``` To install Rails, use the `gem install` command provided by RubyGems: diff --git a/guides/source/routing.md b/guides/source/routing.md index 14f23d4020..4614169653 100644 --- a/guides/source/routing.md +++ b/guides/source/routing.md @@ -832,6 +832,19 @@ will recognize incoming paths beginning with `/photos` but route to the `Images` NOTE: Use `photos_path`, `new_photo_path`, etc. to generate paths for this resource. +For namespaced controllers you can use the directory notation. For example: + +```ruby +resources :user_permissions, controller: 'admin/user_permissions' +``` + +This will route to the `Admin::UserPermissions` controller. + +NOTE: Only the directory notation is supported. specifying the +controller with ruby constant notation (eg. `:controller => +'Admin::UserPermissions'`) can lead to routing problems and results in +a warning. + ### Specifying Constraints You can use the `:constraints` option to specify a required format on the implicit `id`. For example: diff --git a/guides/source/upgrading_ruby_on_rails.md b/guides/source/upgrading_ruby_on_rails.md index b4a59fe3da..568767d9de 100644 --- a/guides/source/upgrading_ruby_on_rails.md +++ b/guides/source/upgrading_ruby_on_rails.md @@ -16,11 +16,11 @@ The best way to be sure that your application still works after upgrading is to Rails generally stays close to the latest released Ruby version when it's released: -* Rails 3 and above 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.2.x will be the last branch to support Ruby 1.8.7. -* Rails 4 will support only Ruby 1.9.3. +* Rails 3 and above require Ruby 1.8.7 or higher. Support for all of the previous Ruby versions has been dropped officially. You should upgrade as early as possible. +* Rails 3.2.x is the last branch to support Ruby 1.8.7. +* Rails 4 prefers Ruby 2.0 and requires 1.9.3 or newer. -TIP: Ruby 1.8.7 p248 and p249 have marshaling bugs that crash Rails. Ruby Enterprise Edition has these fixed since the release of 1.8.7-2010.02. 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 to 1.9.2 or 1.9.3 for smooth sailing. +TIP: Ruby 1.8.7 p248 and p249 have marshaling bugs that crash Rails. Ruby Enterprise Edition has these fixed since the release of 1.8.7-2010.02. 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 straight to 1.9.3 for smooth sailing. Upgrading from Rails 3.2 to Rails 4.0 ------------------------------------- @@ -82,6 +82,8 @@ becomes get 'こんにちは', controller: 'welcome', action: 'index' ``` +* Rails 4.0 has removed ActionDispatch::BestStandardsSupport middleware, !DOCTYPE html already triggers standards mode per http://msdn.microsoft.com/en-us/library/jj676915(v=vs.85).aspx and ChromeFrame header has been moved to `config.action_dispatch.default_headers` + ### Active Support Rails 4.0 removes the `j` alias for `ERB::Util#json_escape` since `j` is already used for `ActionView::Helpers::JavaScriptHelper#escape_javascript`. diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index f86baee4c3..c2e47f1e09 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -1,5 +1,9 @@ ## Rails 4.0.0 (unreleased) ## +* Added notice message for destroy action in scaffold generator + + *Rahul P. Chaudhari* + * Add --rc option to support the load of a custom rc file during the generation of a new app. *Amparo Luna* diff --git a/railties/lib/rails/commands/application.rb b/railties/lib/rails/commands/application.rb index 7d84d3ae0e..2ff29418c6 100644 --- a/railties/lib/rails/commands/application.rb +++ b/railties/lib/rails/commands/application.rb @@ -10,8 +10,12 @@ if ARGV.first != "new" else ARGV.shift unless ARGV.delete("--no-rc") - customrc = ARGV.index('--rc') - railsrc = customrc ? ARGV.slice!(customrc, 2).last : File.join(File.expand_path("~"), '.railsrc') + customrc = ARGV.index{ |x| x.include?("--rc=") } + railsrc = if customrc + File.expand_path(ARGV.delete_at(customrc).gsub(/--rc=/, "")) + else + File.join(File.expand_path("~"), '.railsrc') + end if File.exist?(railsrc) extra_args_string = File.read(railsrc) extra_args = extra_args_string.split(/\n+/).map {|l| l.split}.flatten diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index 978ec3b5de..99d80b3245 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -20,10 +20,10 @@ module Rails def self.add_shared_options_for(name) class_option :builder, type: :string, aliases: '-b', - desc: "Path to a #{name} builder (can be a filesystem path or URL)" + desc: "Path to some #{name} builder (can be a filesystem path or URL)" class_option :template, type: :string, aliases: '-m', - desc: "Path to an #{name} template (can be a filesystem path or URL)" + desc: "Path to some #{name} template (can be a filesystem path or URL)" class_option :skip_gemfile, type: :boolean, default: false, desc: "Don't create a Gemfile" @@ -61,6 +61,9 @@ module Rails class_option :skip_test_unit, type: :boolean, aliases: '-T', default: false, desc: 'Skip Test::Unit files' + class_option :rc, type: :string, default: false, + desc: "Path to file containing extra configuration options for rails command" + class_option :no_rc, type: :boolean, default: false, desc: 'Skip loading of extra configuration options from .railsrc file' diff --git a/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb b/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb index e813437d75..72281a2fef 100644 --- a/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb +++ b/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb @@ -47,7 +47,7 @@ class <%= controller_class_name %>Controller < ApplicationController # DELETE <%= route_url %>/1 def destroy @<%= orm_instance.destroy %> - redirect_to <%= index_helper %>_url + redirect_to <%= index_helper %>_url, notice: <%= "'#{human_name} was successfully destroyed.'" %> end private diff --git a/railties/lib/rails/ruby_version_check.rb b/railties/lib/rails/ruby_version_check.rb index 4536fedaa3..3b7f358a5b 100644 --- a/railties/lib/rails/ruby_version_check.rb +++ b/railties/lib/rails/ruby_version_check.rb @@ -2,12 +2,12 @@ if RUBY_VERSION < '1.9.3' desc = defined?(RUBY_DESCRIPTION) ? RUBY_DESCRIPTION : "ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE})" abort <<-end_message - Rails 4 requires Ruby 1.9.3+. + Rails 4 prefers to run on Ruby 2.0. You're running #{desc} - Please upgrade to continue. + Please upgrade to Ruby 1.9.3 or newer to continue. end_message end diff --git a/railties/lib/rails/test_unit/testing.rake b/railties/lib/rails/test_unit/testing.rake index f0d46fd959..44485d9b14 100644 --- a/railties/lib/rails/test_unit/testing.rake +++ b/railties/lib/rails/test_unit/testing.rake @@ -71,6 +71,18 @@ namespace :test do end end + # Inspired by: http://ngauthier.com/2012/02/quick-tests-with-bash.html + desc "Run tests quickly by merging all types and not resetting db" + Rake::TestTask.new(:all) do |t| + t.libs << "test" + t.pattern = "test/**/*_test.rb" + end + + namespace :all do + desc "Run tests quickly, but also reset db" + task :db => %w[db:test:prepare test:all] + end + Rake::TestTask.new(recent: "test:prepare") do |t| since = TEST_CHANGES_SINCE touched = FileList['test/**/*_test.rb'].select { |path| File.mtime(path) > since } + diff --git a/railties/test/generators/scaffold_controller_generator_test.rb b/railties/test/generators/scaffold_controller_generator_test.rb index c34ce285e3..013cb78252 100644 --- a/railties/test/generators/scaffold_controller_generator_test.rb +++ b/railties/test/generators/scaffold_controller_generator_test.rb @@ -39,6 +39,7 @@ class ScaffoldControllerGeneratorTest < Rails::Generators::TestCase assert_instance_method :destroy, content do |m| assert_match(/@user\.destroy/, m) + assert_match(/User was successfully destroyed/, m) end assert_instance_method :set_user, content do |m| |