Skip to content

Commit

Permalink
Ambiguous reflections are on :through relationships are no longer sup…
Browse files Browse the repository at this point in the history
…ported.

For example, you need to change this:

  class Author < ActiveRecord::Base
    has_many :posts
    has_many :taggings, :through => :posts
  end

  class Post < ActiveRecord::Base
    has_one :tagging
    has_many :taggings
  end

  class Tagging < ActiveRecord::Base
  end

To this:

  class Author < ActiveRecord::Base
    has_many :posts
    has_many :taggings, :through => :posts, :source => :tagging
  end

  class Post < ActiveRecord::Base
    has_one :tagging
    has_many :taggings
  end

  class Tagging < ActiveRecord::Base
  end
  • Loading branch information
tenderlove committed Jun 13, 2013
1 parent 47e8bb1 commit b483a0d
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 3 deletions.
31 changes: 31 additions & 0 deletions activerecord/CHANGELOG.md
@@ -1,3 +1,34 @@
* Ambiguous reflections are on :through relationships are no longer supported.
For example, you need to change this:

class Author < ActiveRecord::Base
has_many :posts
has_many :taggings, :through => :posts
end

class Post < ActiveRecord::Base
has_one :tagging
has_many :taggings
end

class Tagging < ActiveRecord::Base
end

To this:

class Author < ActiveRecord::Base
has_many :posts
has_many :taggings, :through => :posts, :source => :tagging
end

class Post < ActiveRecord::Base
has_one :tagging
has_many :taggings
end

class Tagging < ActiveRecord::Base
end

* Remove column restrictions for `count`, let the database raise if the SQL is
invalid. The previous behavior was untested and surprising for the user.
Fixes #5554.
Expand Down
28 changes: 27 additions & 1 deletion activerecord/lib/active_record/reflection.rb
Expand Up @@ -499,6 +499,11 @@ class ThroughReflection < AssociationReflection #:nodoc:
delegate :foreign_key, :foreign_type, :association_foreign_key,
:active_record_primary_key, :type, :to => :source_reflection

def initialize(macro, name, scope, options, active_record)
super
@source_reflection = nil
end

# Returns the source of the through reflection. It checks both a singularized
# and pluralized form for <tt>:belongs_to</tt> or <tt>:has_many</tt>.
#
Expand All @@ -517,7 +522,28 @@ class ThroughReflection < AssociationReflection #:nodoc:
# # => <ActiveRecord::Reflection::AssociationReflection: @macro=:belongs_to, @name=:tag, @active_record=Tagging, @plural_name="tags">
#
def source_reflection
@source_reflection ||= source_reflection_names.collect { |name| through_reflection.klass.reflect_on_association(name) }.compact.first
return @source_reflection if @source_reflection

reflections = source_reflection_names.collect { |name|
through_reflection.klass.reflect_on_association(name)
}.compact

if reflections.length > 1
example_options = options.dup
example_options[:source] = source_reflection_names.first
ActiveSupport::Deprecation.warn <<-eowarn
Ambiguous source reflection for through association. Please specify a :source
directive on your declaration like:
class #{active_record.name} < ActiveRecord::Base
#{macro} :#{name}, #{example_options}
end
eowarn
@source_reflection = reflections.first
else
@source_reflection = reflections.first
end
end

# Returns the AssociationReflection object specified in the <tt>:through</tt> option
Expand Down
2 changes: 1 addition & 1 deletion activerecord/test/models/author.rb
Expand Up @@ -85,7 +85,7 @@ class Author < ActiveRecord::Base
has_many :author_favorites
has_many :favorite_authors, -> { order('name') }, :through => :author_favorites

has_many :taggings, :through => :posts
has_many :taggings, :through => :posts, :source => :taggings
has_many :taggings_2, :through => :posts, :source => :tagging
has_many :tags, :through => :posts
has_many :post_categories, :through => :posts, :source => :categories
Expand Down
2 changes: 1 addition & 1 deletion activerecord/test/models/company.rb
Expand Up @@ -141,7 +141,7 @@ class Client < Company
belongs_to :firm_with_primary_key_symbols, :class_name => "Firm", :primary_key => :name, :foreign_key => :firm_name
belongs_to :readonly_firm, -> { readonly }, :class_name => "Firm", :foreign_key => "firm_id"
belongs_to :bob_firm, -> { where :name => "Bob" }, :class_name => "Firm", :foreign_key => "client_of"
has_many :accounts, :through => :firm
has_many :accounts, :through => :firm, :source => :accounts
belongs_to :account

class RaisedOnSave < RuntimeError; end
Expand Down

1 comment on commit b483a0d

@rafaelfranca
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tenderlove when removing this deprecation should we raise an exception when reflections.length > 1?

Please sign in to comment.