diff options
-rw-r--r-- | activerecord/CHANGELOG.md | 10 | ||||
-rw-r--r-- | activerecord/lib/active_record/associations/association_scope.rb | 16 | ||||
-rw-r--r-- | activerecord/lib/active_record/associations/join_dependency/join_association.rb | 25 | ||||
-rw-r--r-- | activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb | 10 | ||||
-rw-r--r-- | activerecord/lib/active_record/reflection.rb | 83 | ||||
-rw-r--r-- | activerecord/test/cases/migration/references_statements_test.rb | 7 | ||||
-rw-r--r-- | guides/source/association_basics.md | 2 | ||||
-rw-r--r-- | guides/source/configuring.md | 10 | ||||
-rw-r--r-- | guides/source/testing.md | 16 | ||||
-rw-r--r-- | railties/lib/rails/generators/erb.rb | 4 |
10 files changed, 115 insertions, 68 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 55773f2172..8d054a144a 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,13 @@ +* Don't share options between reference id and type columns + + When using a polymorphic reference column in a migration, sharing options + between the two columns doesn't make sense since they are different types. + The `reference_id` column is usually an integer and the `reference_type` + column a string so options like `unsigned: true` will result in an invalid + table definition. + + *Ryuta Kamizono* + * Use `max_identifier_length` for `index_name_length` in PostgreSQL adapter. *Ryuta Kamizono* diff --git a/activerecord/lib/active_record/associations/association_scope.rb b/activerecord/lib/active_record/associations/association_scope.rb index badde9973f..120d75416c 100644 --- a/activerecord/lib/active_record/associations/association_scope.rb +++ b/activerecord/lib/active_record/associations/association_scope.rb @@ -25,7 +25,7 @@ module ActiveRecord chain_head, chain_tail = get_chain(reflection, association, alias_tracker) scope.extending! Array(reflection.options[:extend]) - add_constraints(scope, owner, klass, reflection, chain_head, chain_tail) + add_constraints(scope, owner, reflection, chain_head, chain_tail) end def join_type @@ -60,8 +60,8 @@ module ActiveRecord table.create_join(table, table.create_on(constraint), join_type) end - def last_chain_scope(scope, table, reflection, owner, association_klass) - join_keys = reflection.join_keys(association_klass) + def last_chain_scope(scope, table, reflection, owner) + join_keys = reflection.join_keys key = join_keys.key foreign_key = join_keys.foreign_key @@ -80,8 +80,8 @@ module ActiveRecord value_transformation.call(value) end - def next_chain_scope(scope, table, reflection, association_klass, foreign_table, next_reflection) - join_keys = reflection.join_keys(association_klass) + def next_chain_scope(scope, table, reflection, foreign_table, next_reflection) + join_keys = reflection.join_keys key = join_keys.key foreign_key = join_keys.foreign_key @@ -120,10 +120,10 @@ module ActiveRecord [runtime_reflection, previous_reflection] end - def add_constraints(scope, owner, association_klass, refl, chain_head, chain_tail) + def add_constraints(scope, owner, refl, chain_head, chain_tail) owner_reflection = chain_tail table = owner_reflection.alias_name - scope = last_chain_scope(scope, table, owner_reflection, owner, association_klass) + scope = last_chain_scope(scope, table, owner_reflection, owner) reflection = chain_head while reflection @@ -132,7 +132,7 @@ module ActiveRecord unless reflection == chain_tail foreign_table = next_reflection.alias_name - scope = next_chain_scope(scope, table, reflection, association_klass, foreign_table, next_reflection) + scope = next_chain_scope(scope, table, reflection, foreign_table, next_reflection) end # Exclude the scope of the association itself, because that diff --git a/activerecord/lib/active_record/associations/join_dependency/join_association.rb b/activerecord/lib/active_record/associations/join_dependency/join_association.rb index 935777d485..97cfec0302 100644 --- a/activerecord/lib/active_record/associations/join_dependency/join_association.rb +++ b/activerecord/lib/active_record/associations/join_dependency/join_association.rb @@ -34,35 +34,16 @@ module ActiveRecord table = tables.shift klass = reflection.klass - join_keys = reflection.join_keys(klass) + join_keys = reflection.join_keys key = join_keys.key foreign_key = join_keys.foreign_key constraint = build_constraint(klass, table, key, foreign_table, foreign_key) predicate_builder = PredicateBuilder.new(TableMetadata.new(klass, table)) - scope_chain_items = reflection.scopes.map do |item| - if item.is_a?(Relation) - item - else - ActiveRecord::Relation.create(klass, table, predicate_builder) - .instance_exec(&item) - end - end + scope_chain_items = reflection.join_scopes(table, predicate_builder) + klass_scope = reflection.klass_join_scope(table, predicate_builder) - klass_scope = - if klass.current_scope - klass.current_scope.clone.tap { |scope| - scope.joins_values = [] - } - else - relation = ActiveRecord::Relation.create( - klass, - table, - predicate_builder, - ) - klass.send(:build_default_scope, relation) - end scope_chain_items.concat [klass_scope].compact rel = scope_chain_items.inject(scope_chain_items.shift) do |left, right| diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index 5eb7787226..4682afc188 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -116,16 +116,12 @@ module ActiveRecord private - def as_options(value, default = {}) - if value.is_a?(Hash) - value - else - default - end + def as_options(value) + value.is_a?(Hash) ? value : {} end def polymorphic_options - as_options(polymorphic, options) + as_options(polymorphic) end def index_options diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index 61a2279292..24ca8b0be4 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -172,8 +172,8 @@ module ActiveRecord JoinKeys = Struct.new(:key, :foreign_key) # :nodoc: - def join_keys(association_klass) - JoinKeys.new(foreign_key, active_record_primary_key) + def join_keys + get_join_keys klass end # Returns a list of scopes that should be applied for this Reflection @@ -187,6 +187,30 @@ module ActiveRecord end deprecate :scope_chain + def join_scopes(table, predicate_builder) # :nodoc: + if scope + [ActiveRecord::Relation.create(klass, table, predicate_builder) + .instance_exec(&scope)] + else + [] + end + end + + def klass_join_scope(table, predicate_builder) # :nodoc: + if klass.current_scope + klass.current_scope.clone.tap { |scope| + scope.joins_values = [] + } + else + relation = ActiveRecord::Relation.create( + klass, + table, + predicate_builder, + ) + klass.send(:build_default_scope, relation) + end + end + def constraints chain.map(&:scopes).flatten end @@ -260,6 +284,20 @@ module ActiveRecord def chain collect_join_chain end + + def get_join_keys(association_klass) + JoinKeys.new(join_pk(association_klass), join_fk) + end + + private + + def join_pk(_) + foreign_key + end + + def join_fk + active_record_primary_key + end end # Base class for AggregateReflection and AssociationReflection. Objects of @@ -687,11 +725,6 @@ module ActiveRecord end end - def join_keys(association_klass) - key = polymorphic? ? association_primary_key(association_klass) : association_primary_key - JoinKeys.new(key, foreign_key) - end - def join_id_for(owner) # :nodoc: owner[foreign_key] end @@ -701,6 +734,14 @@ module ActiveRecord def calculate_constructable(macro, options) !polymorphic? end + + def join_fk + foreign_key + end + + def join_pk(klass) + polymorphic? ? association_primary_key(klass) : association_primary_key + end end class HasAndBelongsToManyReflection < AssociationReflection # :nodoc: @@ -720,7 +761,7 @@ module ActiveRecord class ThroughReflection < AbstractReflection #:nodoc: attr_reader :delegate_reflection delegate :foreign_key, :foreign_type, :association_foreign_key, - :active_record_primary_key, :type, to: :source_reflection + :active_record_primary_key, :type, :get_join_keys, to: :source_reflection def initialize(delegate_reflection) @delegate_reflection = delegate_reflection @@ -806,6 +847,10 @@ module ActiveRecord source_reflection.scopes + super end + def join_scopes(table, predicate_builder) # :nodoc: + source_reflection.join_scopes(table, predicate_builder) + super + end + def source_type_scope through_reflection.klass.where(foreign_type => options[:source_type]) end @@ -816,10 +861,6 @@ module ActiveRecord through_reflection.has_scope? end - def join_keys(association_klass) - source_reflection.join_keys(association_klass) - end - # A through association is nested if there would be more than one join table def nested? source_reflection.through_reflection? || through_reflection.through_reflection? @@ -954,6 +995,7 @@ module ActiveRecord end private + def actual_source_reflection # FIXME: this is a horrible name source_reflection.send(:actual_source_reflection) end @@ -990,6 +1032,15 @@ module ActiveRecord end end + def join_scopes(table, predicate_builder) # :nodoc: + scopes = @previous_reflection.join_scopes(table, predicate_builder) + super + if @previous_reflection.options[:source_type] + scopes + [@previous_reflection.source_type_scope] + else + scopes + end + end + def klass @reflection.klass end @@ -1006,10 +1057,6 @@ module ActiveRecord @reflection.plural_name end - def join_keys(association_klass) - @reflection.join_keys(association_klass) - end - def type @reflection.type end @@ -1023,6 +1070,10 @@ module ActiveRecord source_type = @previous_reflection.options[:source_type] lambda { |object| where(type => source_type) } end + + def get_join_keys(association_klass) + @reflection.get_join_keys(association_klass) + end end class RuntimeReflection < PolymorphicReflection # :nodoc: diff --git a/activerecord/test/cases/migration/references_statements_test.rb b/activerecord/test/cases/migration/references_statements_test.rb index df15d7cb45..06c44c8c52 100644 --- a/activerecord/test/cases/migration/references_statements_test.rb +++ b/activerecord/test/cases/migration/references_statements_test.rb @@ -50,6 +50,13 @@ module ActiveRecord assert column_exists?(table_name, :taggable_type, :string, default: "Photo") end + def test_does_not_share_options_with_reference_type_column + add_reference table_name, :taggable, type: :integer, limit: 2, polymorphic: true + assert column_exists?(table_name, :taggable_id, :integer, limit: 2) + assert column_exists?(table_name, :taggable_type, :string) + assert_not column_exists?(table_name, :taggable_type, :string, limit: 2) + end + def test_creates_named_index add_reference table_name, :tag, index: { name: "index_taggings_on_tag_id" } assert index_exists?(table_name, :tag_id, name: "index_taggings_on_tag_id") diff --git a/guides/source/association_basics.md b/guides/source/association_basics.md index 6e68935f9b..73c9c10c1f 100644 --- a/guides/source/association_basics.md +++ b/guides/source/association_basics.md @@ -154,7 +154,7 @@ case, the column definition might look like this: ```ruby create_table :accounts do |t| - t.belongs_to :supplier, index: true, unique: true, foreign_key: true + t.belongs_to :supplier, index: { unique: true }, foreign_key: true # ... end ``` diff --git a/guides/source/configuring.md b/guides/source/configuring.md index de921e2705..a4f3882124 100644 --- a/guides/source/configuring.md +++ b/guides/source/configuring.md @@ -350,9 +350,9 @@ All these configuration options are delegated to the `I18n` library. `config/environments/production.rb` which is generated by Rails. The default value is `true` if this configuration is not set. -* `config.active_record.dump_schemas` controls which database schemas will be dumped when calling db:structure:dump. - The options are `:schema_search_path` (the default) which dumps any schemas listed in schema_search_path, - `:all` which always dumps all schemas regardless of the schema_search_path, +* `config.active_record.dump_schemas` controls which database schemas will be dumped when calling `db:structure:dump`. + The options are `:schema_search_path` (the default) which dumps any schemas listed in `schema_search_path`, + `:all` which always dumps all schemas regardless of the `schema_search_path`, or a string of comma separated schemas. * `config.active_record.belongs_to_required_by_default` is a boolean value and @@ -362,10 +362,10 @@ All these configuration options are delegated to the `I18n` library. * `config.active_record.warn_on_records_fetched_greater_than` allows setting a warning threshold for query result size. If the number of records returned by a query exceeds the threshold, a warning is logged. This can be used to - identify queries which might be causing memory bloat. + identify queries which might be causing a memory bloat. * `config.active_record.index_nested_attribute_errors` allows errors for nested - has_many relationships to be displayed with an index as well as the error. + `has_many` relationships to be displayed with an index as well as the error. Defaults to `false`. * `config.active_record.use_schema_cache_dump` enables users to get schema cache information diff --git a/guides/source/testing.md b/guides/source/testing.md index 4231500729..f7640d097f 100644 --- a/guides/source/testing.md +++ b/guides/source/testing.md @@ -610,9 +610,9 @@ For creating Rails system tests, you use the `test/system` directory in your application. Rails provides a generator to create a system test skeleton for you. ```bash -$ bin/rails generate system_test users_create_test +$ bin/rails generate system_test users_create invoke test_unit - create test/system/users_create_test.rb + create test/system/users_creates_test.rb ``` Here's what a freshly-generated system test looks like: @@ -620,10 +620,12 @@ Here's what a freshly-generated system test looks like: ```ruby require "application_system_test_case" -class UsersCreateTest < ApplicationSystemTestCase - visit users_url - - assert_selector "h1", text: "Users" +class UsersCreatesTest < ApplicationSystemTestCase + # test "visiting the index" do + # visit users_creates_url + # + # assert_selector "h1", text: "UsersCreate" + # end end ``` @@ -1436,7 +1438,7 @@ second batch of assertions, we ensure that the email does indeed contain what we expect. The helper `read_fixture` is used to read in the content from this file. NOTE: `email.body.to_s` is present when there's only one (HTML or text) part present. -If the mailer provides both, you can test your fixture against specific parts +If the mailer provides both, you can test your fixture against specific parts with `email.text_part.body.to_s` or `email.html_part.body.to_s`. Here's the content of the `invite` fixture: diff --git a/railties/lib/rails/generators/erb.rb b/railties/lib/rails/generators/erb.rb index d5e326d6ee..97d9ab29d4 100644 --- a/railties/lib/rails/generators/erb.rb +++ b/railties/lib/rails/generators/erb.rb @@ -17,8 +17,8 @@ module Erb # :nodoc: :erb end - def filename_with_extensions(name, format = self.format) - [name, format, handler].compact.join(".") + def filename_with_extensions(name, file_format = format) + [name, file_format, handler].compact.join(".") end end end |