aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--actionpack/CHANGELOG.md13
-rw-r--r--actionpack/actionpack.gemspec2
-rw-r--r--actionpack/lib/action_controller/metal/request_forgery_protection.rb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/cookies.rb13
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb6
-rw-r--r--actionpack/test/controller/request_forgery_protection_test.rb35
-rw-r--r--actionpack/test/dispatch/routing_test.rb61
-rw-r--r--activerecord/CHANGELOG.md17
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/quoting.rb10
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_adapter.rb8
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb9
-rw-r--r--activerecord/lib/active_record/relation/predicate_builder.rb7
-rw-r--r--activerecord/lib/active_record/schema_dumper.rb13
-rw-r--r--activerecord/test/cases/adapters/postgresql/hstore_test.rb14
-rw-r--r--activerecord/test/cases/quoting_test.rb14
-rw-r--r--activerecord/test/cases/relation/where_test.rb25
-rw-r--r--activerecord/test/cases/relation_scoping_test.rb6
-rw-r--r--activerecord/test/cases/schema_dumper_test.rb16
-rw-r--r--activerecord/test/schema/schema.rb2
-rw-r--r--activesupport/CHANGELOG.md16
-rw-r--r--activesupport/lib/active_support/gzip.rb4
-rw-r--r--activesupport/lib/active_support/i18n.rb1
-rw-r--r--activesupport/lib/active_support/time_with_zone.rb2
-rw-r--r--activesupport/test/core_ext/time_with_zone_test.rb2
-rw-r--r--activesupport/test/gzip_test.rb18
-rw-r--r--guides/source/4_0_release_notes.md2
-rw-r--r--guides/source/getting_started.md4
-rw-r--r--guides/source/routing.md13
-rw-r--r--guides/source/upgrading_ruby_on_rails.md10
-rw-r--r--railties/CHANGELOG.md4
-rw-r--r--railties/lib/rails/commands/application.rb8
-rw-r--r--railties/lib/rails/generators/app_base.rb7
-rw-r--r--railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb2
-rw-r--r--railties/lib/rails/ruby_version_check.rb4
-rw-r--r--railties/lib/rails/test_unit/testing.rake12
-rw-r--r--railties/test/generators/scaffold_controller_generator_test.rb1
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|