diff options
23 files changed, 154 insertions, 21 deletions
diff --git a/.travis.yml b/.travis.yml index 985956363a..c213700687 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,9 +28,10 @@ matrix: env: "GEM=ar:mysql" - rvm: 2.0.0 env: "GEM=ar:mysql" + - rvm: ruby-head + env: "GEM=ar:mysql" - rvm: rbx-2 - rvm: jruby - - rvm: ruby-head fast_finish: true notifications: email: false diff --git a/actionview/lib/action_view/base.rb b/actionview/lib/action_view/base.rb index d1bade0d3d..3071a13655 100644 --- a/actionview/lib/action_view/base.rb +++ b/actionview/lib/action_view/base.rb @@ -33,7 +33,9 @@ module ActionView #:nodoc: # # If you absolutely must write from within a function use +concat+. # - # <%- and -%> suppress leading and trailing whitespace, including the trailing newline, and can be used interchangeably with <% and %>. + # When on a line that only contains whitespaces except for the tag, <% %> suppress leading and trailing whitespace, + # including the trailing newline. <% %> and <%- -%> are the same. + # Note however that <%= %> and <%= -%> are different: only the latter removes trailing whitespaces. # # === Using sub templates # diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index be6d65a721..78fb60332f 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,7 +1,16 @@ -* Don't autosave unchanged has_one through records +* Don't autosave unchanged has_one through records. *Alan Kennedy*, *Steve Parrington* +* Do not dump foreign keys for ignored tables. *Yves Senn* + +* PostgreSQL adapter correctly dumps foreign keys targeting tables + outside the schema search path. + + Fixes #16907. + + *Matthew Draper*, *Yves Senn* + * When a thread is killed, rollback the active transaction, instead of committing it during the stack unwind. Previously, we could commit half- completed work. This fix only works for Ruby 2.0+; on 1.9, we can't @@ -13,7 +22,7 @@ * A `NullRelation` should represent nothing. This fixes a bug where `Comment.where(post_id: Post.none)` returned a non-empty result. - Closes #15176. + Fixes #15176. *Matthew Draper*, *Yves Senn* diff --git a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb index f439bd1ffe..b7fe079ef5 100644 --- a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb +++ b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb @@ -2,6 +2,8 @@ module ActiveRecord module AttributeMethods module TimeZoneConversion class TimeZoneConverter < SimpleDelegator # :nodoc: + include Type::Decorator + def type_cast_from_database(value) convert_time_to_time_zone(super) end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb index 767b6b614a..fda5bbad5c 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb @@ -466,7 +466,7 @@ module ActiveRecord def foreign_keys(table_name) fk_info = select_all <<-SQL.strip_heredoc - SELECT t2.relname AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete + SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete FROM pg_constraint c JOIN pg_class t1 ON c.conrelid = t1.oid JOIN pg_class t2 ON c.confrelid = t2.oid @@ -488,6 +488,7 @@ module ActiveRecord options[:on_delete] = extract_foreign_key_action(row['on_delete']) options[:on_update] = extract_foreign_key_action(row['on_update']) + ForeignKeyDefinition.new(table_name, row['to_table'], options) end end diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb index 83859e474a..61f1a9aa27 100644 --- a/activerecord/lib/active_record/core.rb +++ b/activerecord/lib/active_record/core.rb @@ -124,6 +124,8 @@ module ActiveRecord def find(*ids) # We don't have cache keys for this stuff yet return super unless ids.length == 1 + # Allow symbols to super to maintain compatibility for deprecated finders until Rails 5 + return super if ids.first.kind_of?(Symbol) return super if block_given? || primary_key.nil? || default_scopes.any? || diff --git a/activerecord/lib/active_record/schema_dumper.rb b/activerecord/lib/active_record/schema_dumper.rb index 68d976c240..82c5ca291c 100644 --- a/activerecord/lib/active_record/schema_dumper.rb +++ b/activerecord/lib/active_record/schema_dumper.rb @@ -100,7 +100,7 @@ HEADER # dump foreign keys at the end to make sure all dependent tables exist. if @connection.supports_foreign_keys? sorted_tables.each do |tbl| - foreign_keys(tbl, stream) + foreign_keys(tbl, stream) unless ignored?(tbl) end end end diff --git a/activerecord/lib/active_record/type.rb b/activerecord/lib/active_record/type.rb index f1384e0bb2..e3d6c5957e 100644 --- a/activerecord/lib/active_record/type.rb +++ b/activerecord/lib/active_record/type.rb @@ -1,3 +1,4 @@ +require 'active_record/type/decorator' require 'active_record/type/mutable' require 'active_record/type/numeric' require 'active_record/type/time_value' diff --git a/activerecord/lib/active_record/type/decorator.rb b/activerecord/lib/active_record/type/decorator.rb new file mode 100644 index 0000000000..9fce38ea44 --- /dev/null +++ b/activerecord/lib/active_record/type/decorator.rb @@ -0,0 +1,14 @@ +module ActiveRecord + module Type + module Decorator # :nodoc: + def init_with(coder) + @subtype = coder['subtype'] + __setobj__(@subtype) + end + + def encode_with(coder) + coder['subtype'] = __getobj__ + end + end + end +end diff --git a/activerecord/lib/active_record/type/serialized.rb b/activerecord/lib/active_record/type/serialized.rb index 5b512433b0..17004b3593 100644 --- a/activerecord/lib/active_record/type/serialized.rb +++ b/activerecord/lib/active_record/type/serialized.rb @@ -2,6 +2,7 @@ module ActiveRecord module Type class Serialized < SimpleDelegator # :nodoc: include Mutable + include Decorator attr_reader :subtype, :coder @@ -36,14 +37,13 @@ module ActiveRecord end def init_with(coder) - @subtype = coder['subtype'] @coder = coder['coder'] - __setobj__(@subtype) + super end def encode_with(coder) - coder['subtype'] = @subtype coder['coder'] = @coder + super end private diff --git a/activerecord/test/cases/adapters/postgresql/schema_test.rb b/activerecord/test/cases/adapters/postgresql/schema_test.rb index 9e5fd17dc4..6f40b0d2de 100644 --- a/activerecord/test/cases/adapters/postgresql/schema_test.rb +++ b/activerecord/test/cases/adapters/postgresql/schema_test.rb @@ -1,4 +1,5 @@ require "cases/helper" +require 'support/schema_dumping_helper' class SchemaTest < ActiveRecord::TestCase self.use_transactional_fixtures = false @@ -426,3 +427,28 @@ class SchemaTest < ActiveRecord::TestCase assert_equal this_index_name, this_index.name end end + +class SchemaForeignKeyTest < ActiveRecord::TestCase + include SchemaDumpingHelper + + setup do + @connection = ActiveRecord::Base.connection + end + + def test_dump_foreign_key_targeting_different_schema + @connection.create_schema "my_schema" + @connection.create_table "my_schema.trains" do |t| + t.string :name + end + @connection.create_table "wagons" do |t| + t.integer :train_id + end + @connection.add_foreign_key "wagons", "my_schema.trains", column: "train_id" + output = dump_table_schema "wagons" + assert_match %r{\s+add_foreign_key "wagons", "my_schema.trains", column: "train_id"$}, output + ensure + @connection.execute "DROP TABLE IF EXISTS wagons" + @connection.execute "DROP TABLE IF EXISTS my_schema.trains" + @connection.execute "DROP SCHEMA IF EXISTS my_schema" + end +end diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb index b4917e727a..153f870e3d 100644 --- a/activerecord/test/cases/attribute_methods_test.rb +++ b/activerecord/test/cases/attribute_methods_test.rb @@ -681,6 +681,14 @@ class AttributeMethodsTest < ActiveRecord::TestCase end end + def test_yaml_dumping_record_with_time_zone_aware_attribute + in_time_zone "Pacific Time (US & Canada)" do + record = Topic.new(id: 1) + record.written_on = "Jan 01 00:00:00 2014" + assert_equal record, YAML.load(YAML.dump(record)) + end + end + def test_setting_time_zone_conversion_for_attributes_should_write_value_on_class_variable Topic.skip_time_zone_conversion_for_attributes = [:field_a] Minimalistic.skip_time_zone_conversion_for_attributes = [:field_b] diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb index d7ee56374d..93fb502410 100644 --- a/activerecord/test/cases/schema_dumper_test.rb +++ b/activerecord/test/cases/schema_dumper_test.rb @@ -371,6 +371,11 @@ class SchemaDumperTest < ActiveRecord::TestCase output = standard_dump assert_match(/^\s+add_foreign_key "fk_test_has_fk"[^\n]+\n\s+add_foreign_key "lessons_students"/, output) end + + def test_do_not_dump_foreign_keys_for_ignored_tables + output = dump_table_schema "authors" + assert_equal ["authors"], output.scan(/^\s*add_foreign_key "([^"]+)".+$/).flatten + end end class CreateDogMigration < ActiveRecord::Migration diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index bc8d11a297..8b671a8c27 100644 --- a/activesupport/CHANGELOG.md +++ b/activesupport/CHANGELOG.md @@ -1,3 +1,18 @@ +* Added method `#eql?` to `ActiveSupport::Duration`, in addition to `#==`. + + Currently, the following returns `false`, contrary to expectation: + + 1.minute.eql?(1.minute) + + Adding method `#eql?` will make this behave like expected. Method `#eql?` is + just a bit stricter than `#==`, as it checks whether the argument is also a duration. Their + parts may be different though. + + 1.minute.eql?(60.seconds) # => true + 1.minute.eql?(60) # => false + + *Joost Lubach* + * Time#change can now change nanoseconds (:nsec) as a higher-precision alternative to microseconds (:usec). diff --git a/activesupport/lib/active_support/duration.rb b/activesupport/lib/active_support/duration.rb index a54494bc65..e861a17426 100644 --- a/activesupport/lib/active_support/duration.rb +++ b/activesupport/lib/active_support/duration.rb @@ -57,8 +57,10 @@ module ActiveSupport @value.to_s end + # Returns +true+ if +other+ is also a Duration instance, which has the + # same parts as this one. def eql?(other) - other.is_a?(Duration) && self == other + Duration === other && other.value.eql?(value) end def self.===(other) #:nodoc: diff --git a/activesupport/test/core_ext/duration_test.rb b/activesupport/test/core_ext/duration_test.rb index 555bde6e04..881faf93f5 100644 --- a/activesupport/test/core_ext/duration_test.rb +++ b/activesupport/test/core_ext/duration_test.rb @@ -49,9 +49,13 @@ class DurationTest < ActiveSupport::TestCase "which behaves oddly for the sake of backward-compatibility." assert 1.minute.eql?(1.minute) + assert 1.minute.eql?(60.seconds) assert 2.days.eql?(48.hours) assert !1.second.eql?(1) assert !1.eql?(1.second) + assert 1.minute.eql?(180.seconds - 2.minutes) + assert !1.minute.eql?(60) + assert !1.minute.eql?('foo') end def test_inspect diff --git a/guides/source/3_0_release_notes.md b/guides/source/3_0_release_notes.md index 8122d6c235..46be2613ab 100644 --- a/guides/source/3_0_release_notes.md +++ b/guides/source/3_0_release_notes.md @@ -545,7 +545,7 @@ These are the main changes in Active Support: * `String#to_time` and `String#to_datetime` handle fractional seconds. * Added support to new callbacks for around filter object that respond to `:before` and `:after` used in before and after callbacks. * The `ActiveSupport::OrderedHash#to_a` method returns an ordered set of arrays. Matches Ruby 1.9's `Hash#to_a`. -* `MissingSourceFile` exists as a constant but it is now just equals to `LoadError`. +* `MissingSourceFile` exists as a constant but it is now just equal to `LoadError`. * Added `Class#class_attribute`, to be able to declare a class-level attribute whose value is inheritable and overwritable by subclasses. * Finally removed `DeprecatedCallbacks` in `ActiveRecord::Associations`. * `Object#metaclass` is now `Kernel#singleton_class` to match Ruby. diff --git a/guides/source/4_2_release_notes.md b/guides/source/4_2_release_notes.md index cb461feff8..5aed0c9358 100644 --- a/guides/source/4_2_release_notes.md +++ b/guides/source/4_2_release_notes.md @@ -52,11 +52,40 @@ deserialize it at run time. ### Adequate Record -Rails 4.2 comes with a performance improvement feature called Adequate Record -for Active Record. A lot of common queries are now up to twice as fast in Rails -4.2! +Adequate Record is a set of refactorings that make Active Record `find` and `find_by` methods and some association queries upto 2x faster. -TODO: add some technical details +It works by caching SQL query patterns while executing the Active Record calls. The cache helps skip parts of the computation involved in the transformation of the calls into SQL queries. More details in [Aaron Patterson's post](http://tenderlovemaking.com/2014/02/19/adequaterecord-pro-like-activerecord.html). + +Nothing special has to be done to activate this feature. Most `find` and `find_by` calls and association queries will use it automatically. Examples: + +```ruby +Post.find 1 # caches query pattern +Post.find 2 # uses the cached pattern + +Post.find_by_title 'first post' # caches query pattern +Post.find_by_title 'second post' # uses the cached pattern + +post.comments # caches query pattern +post.comments(true) # uses cached pattern +``` + +The caching is not used in the following scenarios: + +- The model has a default scope +- The model uses single table inheritence to inherit from another model +- `find` with a list of ids. eg: + + ```ruby + Post.find(1,2,3) + OR + Post.find [1,2] + ``` + +- `find_by` with sql fragments: + + ```ruby + Post.find_by "published_at < ?", 2.weeks.ago + ``` ### Web Console diff --git a/guides/source/maintenance_policy.md b/guides/source/maintenance_policy.md index 7f084dd54c..050a64ddf3 100644 --- a/guides/source/maintenance_policy.md +++ b/guides/source/maintenance_policy.md @@ -39,7 +39,10 @@ Only the latest release series will receive bug fixes. When enough bugs are fixed and its deemed worthy to release a new gem, this is the branch it happens from. -**Currently included series:** `4.2.Z`, `4.1.Z`. +In special situations, where someone from the Core Team agrees to support more series, +they are included in the list of supported series. + +**Currently included series:** `4.2.Z`, `4.1.Z` (Supported by Rafael França). Security Issues --------------- diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index 7d6521b2a8..646d84f304 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -1,3 +1,8 @@ +* Change the path of dummy app location in plugin's test_helper.rb for cases + you specify dummy_path option. + + *Yukio Mizuta* + * Fix a bug in the `gem` method for Rails templates when non-String options are used. 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 2cd8040f35..92ff0de030 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 @@ -16,7 +16,8 @@ Rails.application.configure do # Enable Rack::Cache to put a simple HTTP cache in front of your application # Add `rack-cache` to your Gemfile before enabling this. - # For large-scale production use, consider using a caching reverse proxy like NGINX, varnish or squid. + # For large-scale production use, consider using a caching reverse proxy like + # NGINX, varnish or squid. # config.action_dispatch.rack_cache = true # Disable Rails's static asset server (Apache or NGINX will already do this). @@ -38,7 +39,7 @@ Rails.application.configure do <%- end -%> # Specifies the header that your server uses for sending files. - # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # 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. @@ -57,7 +58,7 @@ Rails.application.configure do # config.cache_store = :mem_cache_store # Enable serving of images, stylesheets, and JavaScripts from an asset server. - # config.action_controller.asset_host = "http://assets.example.com" + # config.action_controller.asset_host = 'http://assets.example.com' # Ignore bad email addresses and do not raise email delivery errors. # Set this to true and configure the email server for immediate delivery to raise delivery errors. diff --git a/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb b/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb index 1e26a313cd..40c83d063a 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb +++ b/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb @@ -1,7 +1,7 @@ # Configure Rails Environment ENV["RAILS_ENV"] = "test" -require File.expand_path("../dummy/config/environment.rb", __FILE__) +require File.expand_path("../../<%= options[:dummy_path] -%>/config/environment.rb", __FILE__) require "rails/test_help" Rails.backtrace_cleaner.remove_silencers! diff --git a/railties/test/generators/plugin_generator_test.rb b/railties/test/generators/plugin_generator_test.rb index 985644e8af..645efa5daf 100644 --- a/railties/test/generators/plugin_generator_test.rb +++ b/railties/test/generators/plugin_generator_test.rb @@ -54,7 +54,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase run_generator assert_file "README.rdoc", /Bukkits/ assert_no_file "config/routes.rb" - assert_file "test/test_helper.rb" + assert_file "test/test_helper.rb", /require.+test\/dummy\/config\/environment/ assert_file "test/bukkits_test.rb", /assert_kind_of Module, Bukkits/ end @@ -270,6 +270,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase assert_file "spec/dummy" assert_file "spec/dummy/config/application.rb" assert_no_file "test/dummy" + assert_file "test/test_helper.rb", /require.+spec\/dummy\/config\/environment/ end def test_creating_dummy_application_with_different_name @@ -277,6 +278,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase assert_file "spec/fake" assert_file "spec/fake/config/application.rb" assert_no_file "test/dummy" + assert_file "test/test_helper.rb", /require.+spec\/fake\/config\/environment/ end def test_creating_dummy_without_tests_but_with_dummy_path @@ -284,6 +286,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase assert_file "spec/dummy" assert_file "spec/dummy/config/application.rb" assert_no_file "test" + assert_no_file "test/test_helper.rb" assert_file '.gitignore' do |contents| assert_match(/spec\/dummy/, contents) end |