Fix naughty trailing whitespace
This commit is contained in:
parent
d010fb13ef
commit
9a1a32ac2b
@ -210,9 +210,9 @@ def preload_has_one_or_has_many_association(records, reflection, preload_options
|
|||||||
return if records.first.send("loaded_#{reflection.name}?")
|
return if records.first.send("loaded_#{reflection.name}?")
|
||||||
records.each {|record| record.send("set_#{reflection.name}_target", nil)}
|
records.each {|record| record.send("set_#{reflection.name}_target", nil)}
|
||||||
end
|
end
|
||||||
|
|
||||||
options = reflection.options
|
options = reflection.options
|
||||||
|
|
||||||
if options[:through]
|
if options[:through]
|
||||||
records_with_through_records = preload_through_records(records, reflection, options[:through])
|
records_with_through_records = preload_through_records(records, reflection, options[:through])
|
||||||
all_through_records = records_with_through_records.map(&:last).flatten
|
all_through_records = records_with_through_records.map(&:last).flatten
|
||||||
@ -220,10 +220,10 @@ def preload_has_one_or_has_many_association(records, reflection, preload_options
|
|||||||
unless all_through_records.empty?
|
unless all_through_records.empty?
|
||||||
source = reflection.source_reflection.name
|
source = reflection.source_reflection.name
|
||||||
all_through_records.first.class.preload_associations(all_through_records, source, options)
|
all_through_records.first.class.preload_associations(all_through_records, source, options)
|
||||||
|
|
||||||
records_with_through_records.each do |record, through_records|
|
records_with_through_records.each do |record, through_records|
|
||||||
source_records = through_records.map(&source).flatten.compact
|
source_records = through_records.map(&source).flatten.compact
|
||||||
|
|
||||||
case reflection.macro
|
case reflection.macro
|
||||||
when :has_many, :has_and_belongs_to_many
|
when :has_many, :has_and_belongs_to_many
|
||||||
add_preloaded_records_to_collection([record], reflection.name, source_records)
|
add_preloaded_records_to_collection([record], reflection.name, source_records)
|
||||||
@ -235,7 +235,7 @@ def preload_has_one_or_has_many_association(records, reflection, preload_options
|
|||||||
else
|
else
|
||||||
id_to_record_map, ids = construct_id_map(records, reflection.options[:primary_key])
|
id_to_record_map, ids = construct_id_map(records, reflection.options[:primary_key])
|
||||||
associated_records = find_associated_records(ids, reflection, preload_options)
|
associated_records = find_associated_records(ids, reflection, preload_options)
|
||||||
|
|
||||||
if reflection.macro == :has_many
|
if reflection.macro == :has_many
|
||||||
set_association_collection_records(
|
set_association_collection_records(
|
||||||
id_to_record_map, reflection.name,
|
id_to_record_map, reflection.name,
|
||||||
@ -249,7 +249,7 @@ def preload_has_one_or_has_many_association(records, reflection, preload_options
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
alias_method :preload_has_one_association, :preload_has_one_or_has_many_association
|
alias_method :preload_has_one_association, :preload_has_one_or_has_many_association
|
||||||
alias_method :preload_has_many_association, :preload_has_one_or_has_many_association
|
alias_method :preload_has_many_association, :preload_has_one_or_has_many_association
|
||||||
|
|
||||||
@ -259,12 +259,12 @@ def preload_through_records(records, reflection, through_association)
|
|||||||
# record. This is so that we can preload the source association for each record,
|
# record. This is so that we can preload the source association for each record,
|
||||||
# and always be able to access the preloaded association regardless of where we
|
# and always be able to access the preloaded association regardless of where we
|
||||||
# refer to the record.
|
# refer to the record.
|
||||||
#
|
#
|
||||||
# Suffices to say, if AR had an identity map built in then this would be unnecessary.
|
# Suffices to say, if AR had an identity map built in then this would be unnecessary.
|
||||||
identity_map = {}
|
identity_map = {}
|
||||||
|
|
||||||
options = {}
|
options = {}
|
||||||
|
|
||||||
if reflection.options[:source_type]
|
if reflection.options[:source_type]
|
||||||
interface = reflection.source_reflection.options[:foreign_type]
|
interface = reflection.source_reflection.options[:foreign_type]
|
||||||
options[:conditions] = ["#{connection.quote_column_name interface} = ?", reflection.options[:source_type]]
|
options[:conditions] = ["#{connection.quote_column_name interface} = ?", reflection.options[:source_type]]
|
||||||
@ -272,20 +272,20 @@ def preload_through_records(records, reflection, through_association)
|
|||||||
else
|
else
|
||||||
if reflection.options[:conditions]
|
if reflection.options[:conditions]
|
||||||
options[:include] = reflection.options[:include] ||
|
options[:include] = reflection.options[:include] ||
|
||||||
reflection.options[:source]
|
reflection.options[:source]
|
||||||
options[:conditions] = reflection.options[:conditions]
|
options[:conditions] = reflection.options[:conditions]
|
||||||
end
|
end
|
||||||
|
|
||||||
options[:order] = reflection.options[:order]
|
options[:order] = reflection.options[:order]
|
||||||
end
|
end
|
||||||
|
|
||||||
records.first.class.preload_associations(records, through_association, options)
|
records.first.class.preload_associations(records, through_association, options)
|
||||||
|
|
||||||
records.map do |record|
|
records.map do |record|
|
||||||
if reflection.options[:source_type]
|
if reflection.options[:source_type]
|
||||||
# Dont cache the association - we would only be caching a subset
|
# Dont cache the association - we would only be caching a subset
|
||||||
proxy = record.send(through_association)
|
proxy = record.send(through_association)
|
||||||
|
|
||||||
if proxy.respond_to?(:target)
|
if proxy.respond_to?(:target)
|
||||||
through_records = proxy.target
|
through_records = proxy.target
|
||||||
proxy.reset
|
proxy.reset
|
||||||
@ -295,11 +295,11 @@ def preload_through_records(records, reflection, through_association)
|
|||||||
else
|
else
|
||||||
through_records = record.send(through_association)
|
through_records = record.send(through_association)
|
||||||
end
|
end
|
||||||
|
|
||||||
through_records = Array.wrap(through_records).map do |through_record|
|
through_records = Array.wrap(through_records).map do |through_record|
|
||||||
identity_map[through_record] ||= through_record
|
identity_map[through_record] ||= through_record
|
||||||
end
|
end
|
||||||
|
|
||||||
[record, through_records]
|
[record, through_records]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -56,7 +56,7 @@ def initialize(owner, reflection)
|
|||||||
super("Cannot dissociate new records through '#{owner.class.name}##{reflection.name}' on '#{reflection.source_reflection.class_name rescue nil}##{reflection.source_reflection.name rescue nil}'. Both records must have an id in order to delete the has_many :through record associating them.")
|
super("Cannot dissociate new records through '#{owner.class.name}##{reflection.name}' on '#{reflection.source_reflection.class_name rescue nil}##{reflection.source_reflection.name rescue nil}'. Both records must have an id in order to delete the has_many :through record associating them.")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class HasManyThroughNestedAssociationsAreReadonly < ActiveRecordError #:nodoc
|
class HasManyThroughNestedAssociationsAreReadonly < ActiveRecordError #:nodoc
|
||||||
def initialize(owner, reflection)
|
def initialize(owner, reflection)
|
||||||
super("Cannot modify association '#{owner.class.name}##{reflection.name}' because it goes through more than one other association.")
|
super("Cannot modify association '#{owner.class.name}##{reflection.name}' because it goes through more than one other association.")
|
||||||
@ -487,7 +487,7 @@ def association_instance_set(name, association)
|
|||||||
# @group.avatars.delete(@group.avatars.last) # so would this
|
# @group.avatars.delete(@group.avatars.last) # so would this
|
||||||
#
|
#
|
||||||
# === Nested Associations
|
# === Nested Associations
|
||||||
#
|
#
|
||||||
# You can actually specify *any* association with the <tt>:through</tt> option, including an
|
# You can actually specify *any* association with the <tt>:through</tt> option, including an
|
||||||
# association which has a <tt>:through</tt> option itself. For example:
|
# association which has a <tt>:through</tt> option itself. For example:
|
||||||
#
|
#
|
||||||
@ -496,15 +496,15 @@ def association_instance_set(name, association)
|
|||||||
# has_many :comments, :through => :posts
|
# has_many :comments, :through => :posts
|
||||||
# has_many :commenters, :through => :comments
|
# has_many :commenters, :through => :comments
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
# class Post < ActiveRecord::Base
|
# class Post < ActiveRecord::Base
|
||||||
# has_many :comments
|
# has_many :comments
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
# class Comment < ActiveRecord::Base
|
# class Comment < ActiveRecord::Base
|
||||||
# belongs_to :commenter
|
# belongs_to :commenter
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
# @author = Author.first
|
# @author = Author.first
|
||||||
# @author.commenters # => People who commented on posts written by the author
|
# @author.commenters # => People who commented on posts written by the author
|
||||||
#
|
#
|
||||||
@ -514,19 +514,19 @@ def association_instance_set(name, association)
|
|||||||
# has_many :posts
|
# has_many :posts
|
||||||
# has_many :commenters, :through => :posts
|
# has_many :commenters, :through => :posts
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
# class Post < ActiveRecord::Base
|
# class Post < ActiveRecord::Base
|
||||||
# has_many :comments
|
# has_many :comments
|
||||||
# has_many :commenters, :through => :comments
|
# has_many :commenters, :through => :comments
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
# class Comment < ActiveRecord::Base
|
# class Comment < ActiveRecord::Base
|
||||||
# belongs_to :commenter
|
# belongs_to :commenter
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
# When using nested association, you will not be able to modify the association because there
|
# When using nested association, you will not be able to modify the association because there
|
||||||
# is not enough information to know what modification to make. For example, if you tried to
|
# is not enough information to know what modification to make. For example, if you tried to
|
||||||
# add a <tt>Commenter</tt> in the example above, there would be no way to tell how to set up the
|
# add a <tt>Commenter</tt> in the example above, there would be no way to tell how to set up the
|
||||||
# intermediate <tt>Post</tt> and <tt>Comment</tt> objects.
|
# intermediate <tt>Post</tt> and <tt>Comment</tt> objects.
|
||||||
#
|
#
|
||||||
# === Polymorphic Associations
|
# === Polymorphic Associations
|
||||||
@ -2183,9 +2183,9 @@ class JoinAssociation < JoinPart # :nodoc:
|
|||||||
|
|
||||||
# What type of join will be generated, either Arel::InnerJoin (default) or Arel::OuterJoin
|
# What type of join will be generated, either Arel::InnerJoin (default) or Arel::OuterJoin
|
||||||
attr_accessor :join_type
|
attr_accessor :join_type
|
||||||
|
|
||||||
attr_reader :aliased_prefix
|
attr_reader :aliased_prefix
|
||||||
|
|
||||||
delegate :options, :through_reflection, :source_reflection, :through_reflection_chain, :to => :reflection
|
delegate :options, :through_reflection, :source_reflection, :through_reflection_chain, :to => :reflection
|
||||||
delegate :table, :table_name, :to => :parent, :prefix => true
|
delegate :table, :table_name, :to => :parent, :prefix => true
|
||||||
delegate :alias_tracker, :to => :join_dependency
|
delegate :alias_tracker, :to => :join_dependency
|
||||||
@ -2198,13 +2198,13 @@ def initialize(reflection, join_dependency, parent = nil)
|
|||||||
end
|
end
|
||||||
|
|
||||||
super(reflection.klass)
|
super(reflection.klass)
|
||||||
|
|
||||||
@reflection = reflection
|
@reflection = reflection
|
||||||
@join_dependency = join_dependency
|
@join_dependency = join_dependency
|
||||||
@parent = parent
|
@parent = parent
|
||||||
@join_type = Arel::InnerJoin
|
@join_type = Arel::InnerJoin
|
||||||
@aliased_prefix = "t#{ join_dependency.join_parts.size }"
|
@aliased_prefix = "t#{ join_dependency.join_parts.size }"
|
||||||
|
|
||||||
setup_tables
|
setup_tables
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -2221,17 +2221,17 @@ def find_parent_in(other_join_dependency)
|
|||||||
end
|
end
|
||||||
|
|
||||||
def join_to(relation)
|
def join_to(relation)
|
||||||
# The chain starts with the target table, but we want to end with it here (makes
|
# The chain starts with the target table, but we want to end with it here (makes
|
||||||
# more sense in this context)
|
# more sense in this context)
|
||||||
chain = through_reflection_chain.reverse
|
chain = through_reflection_chain.reverse
|
||||||
|
|
||||||
foreign_table = parent_table
|
foreign_table = parent_table
|
||||||
index = 0
|
index = 0
|
||||||
|
|
||||||
chain.each do |reflection|
|
chain.each do |reflection|
|
||||||
table = @tables[index]
|
table = @tables[index]
|
||||||
conditions = []
|
conditions = []
|
||||||
|
|
||||||
if reflection.source_reflection.nil?
|
if reflection.source_reflection.nil?
|
||||||
case reflection.macro
|
case reflection.macro
|
||||||
when :belongs_to
|
when :belongs_to
|
||||||
@ -2240,25 +2240,25 @@ def join_to(relation)
|
|||||||
when :has_many, :has_one
|
when :has_many, :has_one
|
||||||
key = reflection.primary_key_name
|
key = reflection.primary_key_name
|
||||||
foreign_key = reflection.active_record_primary_key
|
foreign_key = reflection.active_record_primary_key
|
||||||
|
|
||||||
conditions << polymorphic_conditions(reflection, table)
|
conditions << polymorphic_conditions(reflection, table)
|
||||||
when :has_and_belongs_to_many
|
when :has_and_belongs_to_many
|
||||||
# For habtm, we need to deal with the join table at the same time as the
|
# For habtm, we need to deal with the join table at the same time as the
|
||||||
# target table (because unlike a :through association, there is no reflection
|
# target table (because unlike a :through association, there is no reflection
|
||||||
# to represent the join table)
|
# to represent the join table)
|
||||||
table, join_table = table
|
table, join_table = table
|
||||||
|
|
||||||
join_key = reflection.primary_key_name
|
join_key = reflection.primary_key_name
|
||||||
join_foreign_key = reflection.active_record.primary_key
|
join_foreign_key = reflection.active_record.primary_key
|
||||||
|
|
||||||
relation = relation.join(join_table, join_type).on(
|
relation = relation.join(join_table, join_type).on(
|
||||||
join_table[join_key].
|
join_table[join_key].
|
||||||
eq(foreign_table[join_foreign_key])
|
eq(foreign_table[join_foreign_key])
|
||||||
)
|
)
|
||||||
|
|
||||||
# We've done the first join now, so update the foreign_table for the second
|
# We've done the first join now, so update the foreign_table for the second
|
||||||
foreign_table = join_table
|
foreign_table = join_table
|
||||||
|
|
||||||
key = reflection.klass.primary_key
|
key = reflection.klass.primary_key
|
||||||
foreign_key = reflection.association_foreign_key
|
foreign_key = reflection.association_foreign_key
|
||||||
end
|
end
|
||||||
@ -2267,41 +2267,41 @@ def join_to(relation)
|
|||||||
when :belongs_to
|
when :belongs_to
|
||||||
key = reflection.association_primary_key
|
key = reflection.association_primary_key
|
||||||
foreign_key = reflection.primary_key_name
|
foreign_key = reflection.primary_key_name
|
||||||
|
|
||||||
conditions << source_type_conditions(reflection, foreign_table)
|
conditions << source_type_conditions(reflection, foreign_table)
|
||||||
when :has_many, :has_one
|
when :has_many, :has_one
|
||||||
key = reflection.primary_key_name
|
key = reflection.primary_key_name
|
||||||
foreign_key = reflection.source_reflection.active_record_primary_key
|
foreign_key = reflection.source_reflection.active_record_primary_key
|
||||||
when :has_and_belongs_to_many
|
when :has_and_belongs_to_many
|
||||||
table, join_table = table
|
table, join_table = table
|
||||||
|
|
||||||
join_key = reflection.primary_key_name
|
join_key = reflection.primary_key_name
|
||||||
join_foreign_key = reflection.klass.primary_key
|
join_foreign_key = reflection.klass.primary_key
|
||||||
|
|
||||||
relation = relation.join(join_table, join_type).on(
|
relation = relation.join(join_table, join_type).on(
|
||||||
join_table[join_key].
|
join_table[join_key].
|
||||||
eq(foreign_table[join_foreign_key])
|
eq(foreign_table[join_foreign_key])
|
||||||
)
|
)
|
||||||
|
|
||||||
foreign_table = join_table
|
foreign_table = join_table
|
||||||
|
|
||||||
key = reflection.klass.primary_key
|
key = reflection.klass.primary_key
|
||||||
foreign_key = reflection.association_foreign_key
|
foreign_key = reflection.association_foreign_key
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
conditions << table[key].eq(foreign_table[foreign_key])
|
conditions << table[key].eq(foreign_table[foreign_key])
|
||||||
|
|
||||||
conditions << reflection_conditions(index, table)
|
conditions << reflection_conditions(index, table)
|
||||||
conditions << sti_conditions(reflection, table)
|
conditions << sti_conditions(reflection, table)
|
||||||
|
|
||||||
relation = relation.join(table, join_type).on(*conditions.flatten.compact)
|
relation = relation.join(table, join_type).on(*conditions.flatten.compact)
|
||||||
|
|
||||||
# The current table in this iteration becomes the foreign table in the next
|
# The current table in this iteration becomes the foreign table in the next
|
||||||
foreign_table = table
|
foreign_table = table
|
||||||
index += 1
|
index += 1
|
||||||
end
|
end
|
||||||
|
|
||||||
relation
|
relation
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -2317,11 +2317,11 @@ def table
|
|||||||
@tables.last
|
@tables.last
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def aliased_table_name
|
def aliased_table_name
|
||||||
table.table_alias || table.name
|
table.table_alias || table.name
|
||||||
end
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def table_alias_for(reflection, join = false)
|
def table_alias_for(reflection, join = false)
|
||||||
@ -2336,7 +2336,7 @@ def interpolate_sql(sql)
|
|||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
# Generate aliases and Arel::Table instances for each of the tables which we will
|
# Generate aliases and Arel::Table instances for each of the tables which we will
|
||||||
# later generate joins for. We must do this in advance in order to correctly allocate
|
# later generate joins for. We must do this in advance in order to correctly allocate
|
||||||
# the proper alias.
|
# the proper alias.
|
||||||
@ -2346,44 +2346,44 @@ def setup_tables
|
|||||||
reflection.table_name,
|
reflection.table_name,
|
||||||
table_alias_for(reflection, reflection != self.reflection)
|
table_alias_for(reflection, reflection != self.reflection)
|
||||||
)
|
)
|
||||||
|
|
||||||
table = Arel::Table.new(
|
table = Arel::Table.new(
|
||||||
reflection.table_name, :engine => arel_engine,
|
reflection.table_name, :engine => arel_engine,
|
||||||
:as => aliased_table_name, :columns => reflection.klass.columns
|
:as => aliased_table_name, :columns => reflection.klass.columns
|
||||||
)
|
)
|
||||||
|
|
||||||
# For habtm, we have two Arel::Table instances related to a single reflection, so
|
# For habtm, we have two Arel::Table instances related to a single reflection, so
|
||||||
# we just store them as a pair in the array.
|
# we just store them as a pair in the array.
|
||||||
if reflection.macro == :has_and_belongs_to_many ||
|
if reflection.macro == :has_and_belongs_to_many ||
|
||||||
(reflection.source_reflection &&
|
(reflection.source_reflection &&
|
||||||
reflection.source_reflection.macro == :has_and_belongs_to_many)
|
reflection.source_reflection.macro == :has_and_belongs_to_many)
|
||||||
|
|
||||||
join_table_name = (reflection.source_reflection || reflection).options[:join_table]
|
join_table_name = (reflection.source_reflection || reflection).options[:join_table]
|
||||||
|
|
||||||
aliased_join_table_name = alias_tracker.aliased_name_for(
|
aliased_join_table_name = alias_tracker.aliased_name_for(
|
||||||
join_table_name,
|
join_table_name,
|
||||||
table_alias_for(reflection, true)
|
table_alias_for(reflection, true)
|
||||||
)
|
)
|
||||||
|
|
||||||
join_table = Arel::Table.new(
|
join_table = Arel::Table.new(
|
||||||
join_table_name, :engine => arel_engine,
|
join_table_name, :engine => arel_engine,
|
||||||
:as => aliased_join_table_name
|
:as => aliased_join_table_name
|
||||||
)
|
)
|
||||||
|
|
||||||
[table, join_table]
|
[table, join_table]
|
||||||
else
|
else
|
||||||
table
|
table
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# The joins are generated from the through_reflection_chain in reverse order, so
|
# The joins are generated from the through_reflection_chain in reverse order, so
|
||||||
# reverse the tables too (but it's important to generate the aliases in the 'forward'
|
# reverse the tables too (but it's important to generate the aliases in the 'forward'
|
||||||
# order, which is why we only do the reversal now.
|
# order, which is why we only do the reversal now.
|
||||||
@tables.reverse!
|
@tables.reverse!
|
||||||
|
|
||||||
@tables
|
@tables
|
||||||
end
|
end
|
||||||
|
|
||||||
def reflection_conditions(index, table)
|
def reflection_conditions(index, table)
|
||||||
@reflection.through_conditions.reverse[index].map do |condition|
|
@reflection.through_conditions.reverse[index].map do |condition|
|
||||||
Arel.sql(interpolate_sql(sanitize_sql(
|
Arel.sql(interpolate_sql(sanitize_sql(
|
||||||
@ -2392,28 +2392,28 @@ def reflection_conditions(index, table)
|
|||||||
)))
|
)))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def sti_conditions(reflection, table)
|
def sti_conditions(reflection, table)
|
||||||
unless reflection.klass.descends_from_active_record?
|
unless reflection.klass.descends_from_active_record?
|
||||||
sti_column = table[reflection.klass.inheritance_column]
|
sti_column = table[reflection.klass.inheritance_column]
|
||||||
|
|
||||||
condition = sti_column.eq(reflection.klass.sti_name)
|
condition = sti_column.eq(reflection.klass.sti_name)
|
||||||
|
|
||||||
reflection.klass.descendants.each do |subclass|
|
reflection.klass.descendants.each do |subclass|
|
||||||
condition = condition.or(sti_column.eq(subclass.sti_name))
|
condition = condition.or(sti_column.eq(subclass.sti_name))
|
||||||
end
|
end
|
||||||
|
|
||||||
condition
|
condition
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def source_type_conditions(reflection, foreign_table)
|
def source_type_conditions(reflection, foreign_table)
|
||||||
if reflection.options[:source_type]
|
if reflection.options[:source_type]
|
||||||
foreign_table[reflection.source_reflection.options[:foreign_type]].
|
foreign_table[reflection.source_reflection.options[:foreign_type]].
|
||||||
eq(reflection.options[:source_type])
|
eq(reflection.options[:source_type])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def polymorphic_conditions(reflection, table)
|
def polymorphic_conditions(reflection, table)
|
||||||
if reflection.options[:as]
|
if reflection.options[:as]
|
||||||
table["#{reflection.options[:as]}_type"].
|
table["#{reflection.options[:as]}_type"].
|
||||||
|
@ -11,10 +11,10 @@ def initialize(other_sql = nil)
|
|||||||
@aliases = Hash.new
|
@aliases = Hash.new
|
||||||
@other_sql = other_sql.to_s.downcase
|
@other_sql = other_sql.to_s.downcase
|
||||||
end
|
end
|
||||||
|
|
||||||
def aliased_name_for(table_name, aliased_name = nil)
|
def aliased_name_for(table_name, aliased_name = nil)
|
||||||
aliased_name ||= table_name
|
aliased_name ||= table_name
|
||||||
|
|
||||||
initialize_count_for(table_name) if @aliases[table_name].nil?
|
initialize_count_for(table_name) if @aliases[table_name].nil?
|
||||||
|
|
||||||
if @aliases[table_name].zero?
|
if @aliases[table_name].zero?
|
||||||
@ -24,12 +24,12 @@ def aliased_name_for(table_name, aliased_name = nil)
|
|||||||
else
|
else
|
||||||
# Otherwise, we need to use an alias
|
# Otherwise, we need to use an alias
|
||||||
aliased_name = connection.table_alias_for(aliased_name)
|
aliased_name = connection.table_alias_for(aliased_name)
|
||||||
|
|
||||||
initialize_count_for(aliased_name) if @aliases[aliased_name].nil?
|
initialize_count_for(aliased_name) if @aliases[aliased_name].nil?
|
||||||
|
|
||||||
# Update the count
|
# Update the count
|
||||||
@aliases[aliased_name] += 1
|
@aliases[aliased_name] += 1
|
||||||
|
|
||||||
if @aliases[aliased_name] > 1
|
if @aliases[aliased_name] > 1
|
||||||
"#{truncate(aliased_name)}_#{@aliases[aliased_name]}"
|
"#{truncate(aliased_name)}_#{@aliases[aliased_name]}"
|
||||||
else
|
else
|
||||||
@ -41,30 +41,30 @@ def aliased_name_for(table_name, aliased_name = nil)
|
|||||||
def pluralize(table_name)
|
def pluralize(table_name)
|
||||||
ActiveRecord::Base.pluralize_table_names ? table_name.to_s.pluralize : table_name
|
ActiveRecord::Base.pluralize_table_names ? table_name.to_s.pluralize : table_name
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def initialize_count_for(name)
|
def initialize_count_for(name)
|
||||||
@aliases[name] = 0
|
@aliases[name] = 0
|
||||||
|
|
||||||
unless @other_sql.blank?
|
unless @other_sql.blank?
|
||||||
# quoted_name should be downcased as some database adapters (Oracle) return quoted name in uppercase
|
# quoted_name should be downcased as some database adapters (Oracle) return quoted name in uppercase
|
||||||
quoted_name = connection.quote_table_name(name.downcase).downcase
|
quoted_name = connection.quote_table_name(name.downcase).downcase
|
||||||
|
|
||||||
# Table names
|
# Table names
|
||||||
@aliases[name] += @other_sql.scan(/join(?:\s+\w+)?\s+#{quoted_name}\son/).size
|
@aliases[name] += @other_sql.scan(/join(?:\s+\w+)?\s+#{quoted_name}\son/).size
|
||||||
|
|
||||||
# Table aliases
|
# Table aliases
|
||||||
@aliases[name] += @other_sql.scan(/join(?:\s+\w+)?\s+\S+\s+#{quoted_name}\son/).size
|
@aliases[name] += @other_sql.scan(/join(?:\s+\w+)?\s+\S+\s+#{quoted_name}\son/).size
|
||||||
end
|
end
|
||||||
|
|
||||||
@aliases[name]
|
@aliases[name]
|
||||||
end
|
end
|
||||||
|
|
||||||
def truncate(name)
|
def truncate(name)
|
||||||
name[0..connection.table_alias_length-3]
|
name[0..connection.table_alias_length-3]
|
||||||
end
|
end
|
||||||
|
|
||||||
def connection
|
def connection
|
||||||
ActiveRecord::Base.connection
|
ActiveRecord::Base.connection
|
||||||
end
|
end
|
||||||
|
@ -66,7 +66,7 @@ def construct_find_options!(options)
|
|||||||
|
|
||||||
def insert_record(record, force = true, validate = true)
|
def insert_record(record, force = true, validate = true)
|
||||||
ensure_not_nested
|
ensure_not_nested
|
||||||
|
|
||||||
if record.new_record?
|
if record.new_record?
|
||||||
if force
|
if force
|
||||||
record.save!
|
record.save!
|
||||||
@ -83,7 +83,7 @@ def insert_record(record, force = true, validate = true)
|
|||||||
# TODO - add dependent option support
|
# TODO - add dependent option support
|
||||||
def delete_records(records)
|
def delete_records(records)
|
||||||
ensure_not_nested
|
ensure_not_nested
|
||||||
|
|
||||||
klass = @reflection.through_reflection.klass
|
klass = @reflection.through_reflection.klass
|
||||||
records.each do |associate|
|
records.each do |associate|
|
||||||
klass.delete_all(construct_join_attributes(associate))
|
klass.delete_all(construct_join_attributes(associate))
|
||||||
|
@ -15,7 +15,7 @@ def replace(new_value)
|
|||||||
|
|
||||||
def create_through_record(new_value) #nodoc:
|
def create_through_record(new_value) #nodoc:
|
||||||
ensure_not_nested
|
ensure_not_nested
|
||||||
|
|
||||||
klass = @reflection.through_reflection.klass
|
klass = @reflection.through_reflection.klass
|
||||||
|
|
||||||
current_object = @owner.send(@reflection.through_reflection.name)
|
current_object = @owner.send(@reflection.through_reflection.name)
|
||||||
|
@ -18,7 +18,7 @@ def construct_find_scope
|
|||||||
:readonly => @reflection.options[:readonly]
|
:readonly => @reflection.options[:readonly]
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def construct_create_scope
|
def construct_create_scope
|
||||||
@reflection.nested? ? {} : construct_owner_attributes(@reflection)
|
@reflection.nested? ? {} : construct_owner_attributes(@reflection)
|
||||||
end
|
end
|
||||||
@ -26,18 +26,18 @@ def construct_create_scope
|
|||||||
# Build SQL conditions from attributes, qualified by table name.
|
# Build SQL conditions from attributes, qualified by table name.
|
||||||
def construct_conditions
|
def construct_conditions
|
||||||
reflection = @reflection.through_reflection_chain.last
|
reflection = @reflection.through_reflection_chain.last
|
||||||
|
|
||||||
if reflection.macro == :has_and_belongs_to_many
|
if reflection.macro == :has_and_belongs_to_many
|
||||||
table_alias = table_aliases[reflection].first
|
table_alias = table_aliases[reflection].first
|
||||||
else
|
else
|
||||||
table_alias = table_aliases[reflection]
|
table_alias = table_aliases[reflection]
|
||||||
end
|
end
|
||||||
|
|
||||||
parts = construct_quoted_owner_attributes(reflection).map do |attr, value|
|
parts = construct_quoted_owner_attributes(reflection).map do |attr, value|
|
||||||
"#{table_alias}.#{attr} = #{value}"
|
"#{table_alias}.#{attr} = #{value}"
|
||||||
end
|
end
|
||||||
parts += reflection_conditions(0)
|
parts += reflection_conditions(0)
|
||||||
|
|
||||||
"(" + parts.join(') AND (') + ")"
|
"(" + parts.join(') AND (') + ")"
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -59,18 +59,18 @@ def construct_select(custom_select = nil)
|
|||||||
distinct = "DISTINCT " if @reflection.options[:uniq]
|
distinct = "DISTINCT " if @reflection.options[:uniq]
|
||||||
selected = custom_select || @reflection.options[:select] || "#{distinct}#{@reflection.quoted_table_name}.*"
|
selected = custom_select || @reflection.options[:select] || "#{distinct}#{@reflection.quoted_table_name}.*"
|
||||||
end
|
end
|
||||||
|
|
||||||
def construct_joins(custom_joins = nil)
|
def construct_joins(custom_joins = nil)
|
||||||
"#{construct_through_joins} #{@reflection.options[:joins]} #{custom_joins}"
|
"#{construct_through_joins} #{@reflection.options[:joins]} #{custom_joins}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def construct_through_joins
|
def construct_through_joins
|
||||||
joins, right_index = [], 1
|
joins, right_index = [], 1
|
||||||
|
|
||||||
# Iterate over each pair in the through reflection chain, joining them together
|
# Iterate over each pair in the through reflection chain, joining them together
|
||||||
@reflection.through_reflection_chain.each_cons(2) do |left, right|
|
@reflection.through_reflection_chain.each_cons(2) do |left, right|
|
||||||
right_table_and_alias = table_name_and_alias(right.quoted_table_name, table_aliases[right])
|
right_table_and_alias = table_name_and_alias(right.quoted_table_name, table_aliases[right])
|
||||||
|
|
||||||
if left.source_reflection.nil?
|
if left.source_reflection.nil?
|
||||||
case left.macro
|
case left.macro
|
||||||
when :belongs_to
|
when :belongs_to
|
||||||
@ -113,7 +113,7 @@ def construct_through_joins
|
|||||||
else
|
else
|
||||||
right_table = table_aliases[right]
|
right_table = table_aliases[right]
|
||||||
end
|
end
|
||||||
|
|
||||||
joins << inner_join_sql(
|
joins << inner_join_sql(
|
||||||
right_table_and_alias,
|
right_table_and_alias,
|
||||||
table_aliases[left], left.primary_key_name,
|
table_aliases[left], left.primary_key_name,
|
||||||
@ -121,7 +121,7 @@ def construct_through_joins
|
|||||||
polymorphic_conditions(left, left.source_reflection),
|
polymorphic_conditions(left, left.source_reflection),
|
||||||
reflection_conditions(right_index)
|
reflection_conditions(right_index)
|
||||||
)
|
)
|
||||||
|
|
||||||
if right.macro == :has_and_belongs_to_many
|
if right.macro == :has_and_belongs_to_many
|
||||||
joins << inner_join_sql(
|
joins << inner_join_sql(
|
||||||
table_name_and_alias(
|
table_name_and_alias(
|
||||||
@ -134,7 +134,7 @@ def construct_through_joins
|
|||||||
end
|
end
|
||||||
when :has_and_belongs_to_many
|
when :has_and_belongs_to_many
|
||||||
join_table, left_table = table_aliases[left]
|
join_table, left_table = table_aliases[left]
|
||||||
|
|
||||||
joins << inner_join_sql(
|
joins << inner_join_sql(
|
||||||
table_name_and_alias(
|
table_name_and_alias(
|
||||||
quote_table_name(left.source_reflection.options[:join_table]),
|
quote_table_name(left.source_reflection.options[:join_table]),
|
||||||
@ -143,7 +143,7 @@ def construct_through_joins
|
|||||||
left_table, left.klass.primary_key,
|
left_table, left.klass.primary_key,
|
||||||
join_table, left.association_foreign_key
|
join_table, left.association_foreign_key
|
||||||
)
|
)
|
||||||
|
|
||||||
joins << inner_join_sql(
|
joins << inner_join_sql(
|
||||||
right_table_and_alias,
|
right_table_and_alias,
|
||||||
join_table, left.primary_key_name,
|
join_table, left.primary_key_name,
|
||||||
@ -152,10 +152,10 @@ def construct_through_joins
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
right_index += 1
|
right_index += 1
|
||||||
end
|
end
|
||||||
|
|
||||||
joins.join(" ")
|
joins.join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -170,77 +170,77 @@ def table_aliases
|
|||||||
reflection.table_name,
|
reflection.table_name,
|
||||||
table_alias_for(reflection, reflection != @reflection)
|
table_alias_for(reflection, reflection != @reflection)
|
||||||
))
|
))
|
||||||
|
|
||||||
if reflection.macro == :has_and_belongs_to_many ||
|
if reflection.macro == :has_and_belongs_to_many ||
|
||||||
(reflection.source_reflection &&
|
(reflection.source_reflection &&
|
||||||
reflection.source_reflection.macro == :has_and_belongs_to_many)
|
reflection.source_reflection.macro == :has_and_belongs_to_many)
|
||||||
|
|
||||||
join_table_alias = quote_table_name(alias_tracker.aliased_name_for(
|
join_table_alias = quote_table_name(alias_tracker.aliased_name_for(
|
||||||
(reflection.source_reflection || reflection).options[:join_table],
|
(reflection.source_reflection || reflection).options[:join_table],
|
||||||
table_alias_for(reflection, true)
|
table_alias_for(reflection, true)
|
||||||
))
|
))
|
||||||
|
|
||||||
aliases[reflection] = [join_table_alias, table_alias]
|
aliases[reflection] = [join_table_alias, table_alias]
|
||||||
else
|
else
|
||||||
aliases[reflection] = table_alias
|
aliases[reflection] = table_alias
|
||||||
end
|
end
|
||||||
|
|
||||||
aliases
|
aliases
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def table_alias_for(reflection, join = false)
|
def table_alias_for(reflection, join = false)
|
||||||
name = alias_tracker.pluralize(reflection.name)
|
name = alias_tracker.pluralize(reflection.name)
|
||||||
name << "_#{@reflection.name}"
|
name << "_#{@reflection.name}"
|
||||||
name << "_join" if join
|
name << "_join" if join
|
||||||
name
|
name
|
||||||
end
|
end
|
||||||
|
|
||||||
def quote_table_name(table_name)
|
def quote_table_name(table_name)
|
||||||
@reflection.klass.connection.quote_table_name(table_name)
|
@reflection.klass.connection.quote_table_name(table_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
def table_name_and_alias(table_name, table_alias)
|
def table_name_and_alias(table_name, table_alias)
|
||||||
"#{table_name} #{table_alias if table_alias != table_name}".strip
|
"#{table_name} #{table_alias if table_alias != table_name}".strip
|
||||||
end
|
end
|
||||||
|
|
||||||
def inner_join_sql(table, on_left_table, on_left_key, on_right_table, on_right_key, *conditions)
|
def inner_join_sql(table, on_left_table, on_left_key, on_right_table, on_right_key, *conditions)
|
||||||
conditions << "#{on_left_table}.#{on_left_key} = #{on_right_table}.#{on_right_key}"
|
conditions << "#{on_left_table}.#{on_left_key} = #{on_right_table}.#{on_right_key}"
|
||||||
conditions = conditions.flatten.compact
|
conditions = conditions.flatten.compact
|
||||||
conditions = conditions.map { |sql| "(#{sql})" } * ' AND '
|
conditions = conditions.map { |sql| "(#{sql})" } * ' AND '
|
||||||
|
|
||||||
"INNER JOIN #{table} ON #{conditions}"
|
"INNER JOIN #{table} ON #{conditions}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def reflection_conditions(index)
|
def reflection_conditions(index)
|
||||||
reflection = @reflection.through_reflection_chain[index]
|
reflection = @reflection.through_reflection_chain[index]
|
||||||
reflection_conditions = @reflection.through_conditions[index]
|
reflection_conditions = @reflection.through_conditions[index]
|
||||||
|
|
||||||
conditions = []
|
conditions = []
|
||||||
|
|
||||||
if reflection.options[:as].nil? && # reflection.klass is a Module if :as is used
|
if reflection.options[:as].nil? && # reflection.klass is a Module if :as is used
|
||||||
reflection.klass.finder_needs_type_condition?
|
reflection.klass.finder_needs_type_condition?
|
||||||
conditions << reflection.klass.send(:type_condition).to_sql
|
conditions << reflection.klass.send(:type_condition).to_sql
|
||||||
end
|
end
|
||||||
|
|
||||||
reflection_conditions.each do |condition|
|
reflection_conditions.each do |condition|
|
||||||
sanitized_condition = reflection.klass.send(:sanitize_sql, condition)
|
sanitized_condition = reflection.klass.send(:sanitize_sql, condition)
|
||||||
interpolated_condition = interpolate_sql(sanitized_condition)
|
interpolated_condition = interpolate_sql(sanitized_condition)
|
||||||
|
|
||||||
if condition.is_a?(Hash)
|
if condition.is_a?(Hash)
|
||||||
interpolated_condition.gsub!(
|
interpolated_condition.gsub!(
|
||||||
@reflection.quoted_table_name,
|
@reflection.quoted_table_name,
|
||||||
reflection.quoted_table_name
|
reflection.quoted_table_name
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
conditions << interpolated_condition
|
conditions << interpolated_condition
|
||||||
end
|
end
|
||||||
|
|
||||||
conditions
|
conditions
|
||||||
end
|
end
|
||||||
|
|
||||||
def polymorphic_conditions(reflection, polymorphic_reflection)
|
def polymorphic_conditions(reflection, polymorphic_reflection)
|
||||||
if polymorphic_reflection.options[:as]
|
if polymorphic_reflection.options[:as]
|
||||||
"%s.%s = %s" % [
|
"%s.%s = %s" % [
|
||||||
@ -249,7 +249,7 @@ def polymorphic_conditions(reflection, polymorphic_reflection)
|
|||||||
]
|
]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def source_type_conditions(reflection)
|
def source_type_conditions(reflection)
|
||||||
if reflection.options[:source_type]
|
if reflection.options[:source_type]
|
||||||
"%s.%s = %s" % [
|
"%s.%s = %s" % [
|
||||||
@ -289,7 +289,7 @@ def construct_join_attributes(associate)
|
|||||||
|
|
||||||
join_attributes
|
join_attributes
|
||||||
end
|
end
|
||||||
|
|
||||||
def ensure_not_nested
|
def ensure_not_nested
|
||||||
if @reflection.nested?
|
if @reflection.nested?
|
||||||
raise HasManyThroughNestedAssociationsAreReadonly.new(@owner, @reflection)
|
raise HasManyThroughNestedAssociationsAreReadonly.new(@owner, @reflection)
|
||||||
|
@ -209,11 +209,11 @@ def primary_key_column
|
|||||||
def association_foreign_key
|
def association_foreign_key
|
||||||
@association_foreign_key ||= @options[:association_foreign_key] || class_name.foreign_key
|
@association_foreign_key ||= @options[:association_foreign_key] || class_name.foreign_key
|
||||||
end
|
end
|
||||||
|
|
||||||
def association_primary_key
|
def association_primary_key
|
||||||
@association_primary_key ||= @options[:primary_key] || klass.primary_key
|
@association_primary_key ||= @options[:primary_key] || klass.primary_key
|
||||||
end
|
end
|
||||||
|
|
||||||
def active_record_primary_key
|
def active_record_primary_key
|
||||||
@active_record_primary_key ||= @options[:primary_key] || active_record.primary_key
|
@active_record_primary_key ||= @options[:primary_key] || active_record.primary_key
|
||||||
end
|
end
|
||||||
@ -249,11 +249,11 @@ def check_validity_of_inverse!
|
|||||||
def through_reflection
|
def through_reflection
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
def through_reflection_chain
|
def through_reflection_chain
|
||||||
[self]
|
[self]
|
||||||
end
|
end
|
||||||
|
|
||||||
def through_conditions
|
def through_conditions
|
||||||
[Array.wrap(options[:conditions])]
|
[Array.wrap(options[:conditions])]
|
||||||
end
|
end
|
||||||
@ -340,7 +340,7 @@ def derive_primary_key_name
|
|||||||
# in the Active Record class.
|
# in the Active Record class.
|
||||||
class ThroughReflection < AssociationReflection #:nodoc:
|
class ThroughReflection < AssociationReflection #:nodoc:
|
||||||
delegate :primary_key_name, :association_foreign_key, :to => :source_reflection
|
delegate :primary_key_name, :association_foreign_key, :to => :source_reflection
|
||||||
|
|
||||||
# Gets the source of the through reflection. It checks both a singularized
|
# Gets the source of the through reflection. It checks both a singularized
|
||||||
# and pluralized form for <tt>:belongs_to</tt> or <tt>:has_many</tt>.
|
# and pluralized form for <tt>:belongs_to</tt> or <tt>:has_many</tt>.
|
||||||
#
|
#
|
||||||
@ -367,14 +367,14 @@ def source_reflection
|
|||||||
def through_reflection
|
def through_reflection
|
||||||
@through_reflection ||= active_record.reflect_on_association(options[:through])
|
@through_reflection ||= active_record.reflect_on_association(options[:through])
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns an array of AssociationReflection objects which are involved in this through
|
# Returns an array of AssociationReflection objects which are involved in this through
|
||||||
# association. Each item in the array corresponds to a table which will be part of the
|
# association. Each item in the array corresponds to a table which will be part of the
|
||||||
# query for this association.
|
# query for this association.
|
||||||
#
|
#
|
||||||
# If the source reflection is itself a ThroughReflection, then we don't include self in
|
# If the source reflection is itself a ThroughReflection, then we don't include self in
|
||||||
# the chain, but just defer to the source reflection.
|
# the chain, but just defer to the source reflection.
|
||||||
#
|
#
|
||||||
# The chain is built by recursively calling through_reflection_chain on the source
|
# The chain is built by recursively calling through_reflection_chain on the source
|
||||||
# reflection and the through reflection. The base case for the recursion is a normal
|
# reflection and the through reflection. The base case for the recursion is a normal
|
||||||
# association, which just returns [self] for its through_reflection_chain.
|
# association, which just returns [self] for its through_reflection_chain.
|
||||||
@ -389,31 +389,31 @@ def through_reflection_chain
|
|||||||
# to this reflection directly, and so start the chain here
|
# to this reflection directly, and so start the chain here
|
||||||
chain = [self]
|
chain = [self]
|
||||||
end
|
end
|
||||||
|
|
||||||
# Recursively build the rest of the chain
|
# Recursively build the rest of the chain
|
||||||
chain += through_reflection.through_reflection_chain
|
chain += through_reflection.through_reflection_chain
|
||||||
|
|
||||||
# Finally return the completed chain
|
# Finally return the completed chain
|
||||||
chain
|
chain
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Consider the following example:
|
# Consider the following example:
|
||||||
#
|
#
|
||||||
# class Person
|
# class Person
|
||||||
# has_many :articles
|
# has_many :articles
|
||||||
# has_many :comment_tags, :through => :articles
|
# has_many :comment_tags, :through => :articles
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
# class Article
|
# class Article
|
||||||
# has_many :comments
|
# has_many :comments
|
||||||
# has_many :comment_tags, :through => :comments, :source => :tags
|
# has_many :comment_tags, :through => :comments, :source => :tags
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
# class Comment
|
# class Comment
|
||||||
# has_many :tags
|
# has_many :tags
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
# There may be conditions on Person.comment_tags, Article.comment_tags and/or Comment.tags,
|
# There may be conditions on Person.comment_tags, Article.comment_tags and/or Comment.tags,
|
||||||
# but only Comment.tags will be represented in the through_reflection_chain. So this method
|
# but only Comment.tags will be represented in the through_reflection_chain. So this method
|
||||||
# creates an array of conditions corresponding to the through_reflection_chain. Each item in
|
# creates an array of conditions corresponding to the through_reflection_chain. Each item in
|
||||||
@ -429,24 +429,24 @@ def through_conditions
|
|||||||
else
|
else
|
||||||
conditions = [Array.wrap(source_reflection.options[:conditions])]
|
conditions = [Array.wrap(source_reflection.options[:conditions])]
|
||||||
end
|
end
|
||||||
|
|
||||||
# Add to it the conditions from this reflection if necessary.
|
# Add to it the conditions from this reflection if necessary.
|
||||||
conditions.first << options[:conditions] if options[:conditions]
|
conditions.first << options[:conditions] if options[:conditions]
|
||||||
|
|
||||||
# Recursively fill out the rest of the array from the through reflection
|
# Recursively fill out the rest of the array from the through reflection
|
||||||
conditions += through_reflection.through_conditions
|
conditions += through_reflection.through_conditions
|
||||||
|
|
||||||
# And return
|
# And return
|
||||||
conditions
|
conditions
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# A through association is nested iff there would be more than one join table
|
# A through association is nested iff there would be more than one join table
|
||||||
def nested?
|
def nested?
|
||||||
through_reflection_chain.length > 2 ||
|
through_reflection_chain.length > 2 ||
|
||||||
through_reflection.macro == :has_and_belongs_to_many
|
through_reflection.macro == :has_and_belongs_to_many
|
||||||
end
|
end
|
||||||
|
|
||||||
# We want to use the klass from this reflection, rather than just delegate straight to
|
# We want to use the klass from this reflection, rather than just delegate straight to
|
||||||
# the source_reflection, because the source_reflection may be polymorphic. We still
|
# the source_reflection, because the source_reflection may be polymorphic. We still
|
||||||
# need to respect the source_reflection's :primary_key option, though.
|
# need to respect the source_reflection's :primary_key option, though.
|
||||||
@ -458,7 +458,7 @@ def association_primary_key
|
|||||||
while source_reflection.source_reflection
|
while source_reflection.source_reflection
|
||||||
source_reflection = source_reflection.source_reflection
|
source_reflection = source_reflection.source_reflection
|
||||||
end
|
end
|
||||||
|
|
||||||
source_reflection.options[:primary_key] || klass.primary_key
|
source_reflection.options[:primary_key] || klass.primary_key
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -456,19 +456,19 @@ def test_include_method_in_association_through_should_return_true_for_instance_a
|
|||||||
|
|
||||||
def test_has_many_through_polymorphic_with_primary_key_option
|
def test_has_many_through_polymorphic_with_primary_key_option
|
||||||
assert_equal [categories(:general)], authors(:david).essay_categories
|
assert_equal [categories(:general)], authors(:david).essay_categories
|
||||||
|
|
||||||
authors = Author.joins(:essay_categories).where('categories.id' => categories(:general).id)
|
authors = Author.joins(:essay_categories).where('categories.id' => categories(:general).id)
|
||||||
assert_equal authors(:david), authors.first
|
assert_equal authors(:david), authors.first
|
||||||
|
|
||||||
assert_equal [owners(:blackbeard)], authors(:david).essay_owners
|
assert_equal [owners(:blackbeard)], authors(:david).essay_owners
|
||||||
|
|
||||||
authors = Author.joins(:essay_owners).where("owners.name = 'blackbeard'")
|
authors = Author.joins(:essay_owners).where("owners.name = 'blackbeard'")
|
||||||
assert_equal authors(:david), authors.first
|
assert_equal authors(:david), authors.first
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_has_many_through_with_primary_key_option
|
def test_has_many_through_with_primary_key_option
|
||||||
assert_equal [categories(:general)], authors(:david).essay_categories_2
|
assert_equal [categories(:general)], authors(:david).essay_categories_2
|
||||||
|
|
||||||
authors = Author.joins(:essay_categories_2).where('categories.id' => categories(:general).id)
|
authors = Author.joins(:essay_categories_2).where('categories.id' => categories(:general).id)
|
||||||
assert_equal authors(:david), authors.first
|
assert_equal authors(:david), authors.first
|
||||||
end
|
end
|
||||||
|
@ -217,22 +217,22 @@ def test_value_is_properly_quoted
|
|||||||
minivan.dashboard
|
minivan.dashboard
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_has_one_through_polymorphic_with_primary_key_option
|
def test_has_one_through_polymorphic_with_primary_key_option
|
||||||
assert_equal categories(:general), authors(:david).essay_category
|
assert_equal categories(:general), authors(:david).essay_category
|
||||||
|
|
||||||
authors = Author.joins(:essay_category).where('categories.id' => categories(:general).id)
|
authors = Author.joins(:essay_category).where('categories.id' => categories(:general).id)
|
||||||
assert_equal authors(:david), authors.first
|
assert_equal authors(:david), authors.first
|
||||||
|
|
||||||
assert_equal owners(:blackbeard), authors(:david).essay_owner
|
assert_equal owners(:blackbeard), authors(:david).essay_owner
|
||||||
|
|
||||||
authors = Author.joins(:essay_owner).where("owners.name = 'blackbeard'")
|
authors = Author.joins(:essay_owner).where("owners.name = 'blackbeard'")
|
||||||
assert_equal authors(:david), authors.first
|
assert_equal authors(:david), authors.first
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_has_one_through_with_primary_key_option
|
def test_has_one_through_with_primary_key_option
|
||||||
assert_equal categories(:general), authors(:david).essay_category_2
|
assert_equal categories(:general), authors(:david).essay_category_2
|
||||||
|
|
||||||
authors = Author.joins(:essay_category_2).where('categories.id' => categories(:general).id)
|
authors = Author.joins(:essay_category_2).where('categories.id' => categories(:general).id)
|
||||||
assert_equal authors(:david), authors.first
|
assert_equal authors(:david), authors.first
|
||||||
end
|
end
|
||||||
|
@ -30,18 +30,18 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase
|
|||||||
:categorizations, :memberships, :essays
|
:categorizations, :memberships, :essays
|
||||||
|
|
||||||
# Through associations can either use the has_many or has_one macros.
|
# Through associations can either use the has_many or has_one macros.
|
||||||
#
|
#
|
||||||
# has_many
|
# has_many
|
||||||
# - Source reflection can be has_many, has_one, belongs_to or has_and_belongs_to_many
|
# - Source reflection can be has_many, has_one, belongs_to or has_and_belongs_to_many
|
||||||
# - Through reflection can be has_many, has_one, belongs_to or has_and_belongs_to_many
|
# - Through reflection can be has_many, has_one, belongs_to or has_and_belongs_to_many
|
||||||
#
|
#
|
||||||
# has_one
|
# has_one
|
||||||
# - Source reflection can be has_one or belongs_to
|
# - Source reflection can be has_one or belongs_to
|
||||||
# - Through reflection can be has_one or belongs_to
|
# - Through reflection can be has_one or belongs_to
|
||||||
#
|
#
|
||||||
# Additionally, the source reflection and/or through reflection may be subject to
|
# Additionally, the source reflection and/or through reflection may be subject to
|
||||||
# polymorphism and/or STI.
|
# polymorphism and/or STI.
|
||||||
#
|
#
|
||||||
# When testing these, we need to make sure it works via loading the association directly, or
|
# When testing these, we need to make sure it works via loading the association directly, or
|
||||||
# joining the association, or including the association. We also need to ensure that associations
|
# joining the association, or including the association. We also need to ensure that associations
|
||||||
# are readonly where relevant.
|
# are readonly where relevant.
|
||||||
@ -51,18 +51,18 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase
|
|||||||
# Through: has_many
|
# Through: has_many
|
||||||
def test_has_many_through_has_many_with_has_many_through_source_reflection
|
def test_has_many_through_has_many_with_has_many_through_source_reflection
|
||||||
general = tags(:general)
|
general = tags(:general)
|
||||||
|
|
||||||
assert_equal [general, general], authors(:david).tags
|
assert_equal [general, general], authors(:david).tags
|
||||||
|
|
||||||
assert_includes_and_joins_equal(
|
assert_includes_and_joins_equal(
|
||||||
Author.where('tags.id' => tags(:general).id),
|
Author.where('tags.id' => tags(:general).id),
|
||||||
[authors(:david)], :tags
|
[authors(:david)], :tags
|
||||||
)
|
)
|
||||||
|
|
||||||
# This ensures that the polymorphism of taggings is being observed correctly
|
# This ensures that the polymorphism of taggings is being observed correctly
|
||||||
authors = Author.joins(:tags).where('taggings.taggable_type' => 'FakeModel')
|
authors = Author.joins(:tags).where('taggings.taggable_type' => 'FakeModel')
|
||||||
assert authors.empty?
|
assert authors.empty?
|
||||||
|
|
||||||
authors = assert_queries(5) { Author.includes(:tags).to_a }
|
authors = assert_queries(5) { Author.includes(:tags).to_a }
|
||||||
assert_no_queries do
|
assert_no_queries do
|
||||||
assert_equal [general, general], authors.first.tags
|
assert_equal [general, general], authors.first.tags
|
||||||
@ -74,236 +74,236 @@ def test_has_many_through_has_many_with_has_many_through_source_reflection
|
|||||||
# Through: has_many through
|
# Through: has_many through
|
||||||
def test_has_many_through_has_many_through_with_has_many_source_reflection
|
def test_has_many_through_has_many_through_with_has_many_source_reflection
|
||||||
luke, david = subscribers(:first), subscribers(:second)
|
luke, david = subscribers(:first), subscribers(:second)
|
||||||
|
|
||||||
author = authors(:david)
|
author = authors(:david)
|
||||||
assert_equal [luke, david, david], author.subscribers.order('subscribers.nick')
|
assert_equal [luke, david, david], author.subscribers.order('subscribers.nick')
|
||||||
|
|
||||||
# All authors with subscribers where one of the subscribers' nick is 'alterself'
|
# All authors with subscribers where one of the subscribers' nick is 'alterself'
|
||||||
assert_includes_and_joins_equal(
|
assert_includes_and_joins_equal(
|
||||||
Author.where('subscribers.nick' => 'alterself'),
|
Author.where('subscribers.nick' => 'alterself'),
|
||||||
[authors(:david)], :subscribers
|
[authors(:david)], :subscribers
|
||||||
)
|
)
|
||||||
|
|
||||||
authors = assert_queries(4) { Author.includes(:subscribers).to_a }
|
authors = assert_queries(4) { Author.includes(:subscribers).to_a }
|
||||||
assert_no_queries do
|
assert_no_queries do
|
||||||
assert_equal [luke, david, david], authors.first.subscribers.sort_by(&:nick)
|
assert_equal [luke, david, david], authors.first.subscribers.sort_by(&:nick)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# has_many through
|
# has_many through
|
||||||
# Source: has_one through
|
# Source: has_one through
|
||||||
# Through: has_one
|
# Through: has_one
|
||||||
def test_has_many_through_has_one_with_has_one_through_source_reflection
|
def test_has_many_through_has_one_with_has_one_through_source_reflection
|
||||||
founding = member_types(:founding)
|
founding = member_types(:founding)
|
||||||
|
|
||||||
assert_equal [founding], members(:groucho).nested_member_types
|
assert_equal [founding], members(:groucho).nested_member_types
|
||||||
|
|
||||||
assert_includes_and_joins_equal(
|
assert_includes_and_joins_equal(
|
||||||
Member.where('member_types.id' => founding.id),
|
Member.where('member_types.id' => founding.id),
|
||||||
[members(:groucho)], :nested_member_types
|
[members(:groucho)], :nested_member_types
|
||||||
)
|
)
|
||||||
|
|
||||||
members = assert_queries(4) { Member.includes(:nested_member_types).to_a }
|
members = assert_queries(4) { Member.includes(:nested_member_types).to_a }
|
||||||
assert_no_queries do
|
assert_no_queries do
|
||||||
assert_equal [founding], members.first.nested_member_types
|
assert_equal [founding], members.first.nested_member_types
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# has_many through
|
# has_many through
|
||||||
# Source: has_one
|
# Source: has_one
|
||||||
# Through: has_one through
|
# Through: has_one through
|
||||||
def test_has_many_through_has_one_through_with_has_one_source_reflection
|
def test_has_many_through_has_one_through_with_has_one_source_reflection
|
||||||
mustache = sponsors(:moustache_club_sponsor_for_groucho)
|
mustache = sponsors(:moustache_club_sponsor_for_groucho)
|
||||||
|
|
||||||
assert_equal [mustache], members(:groucho).nested_sponsors
|
assert_equal [mustache], members(:groucho).nested_sponsors
|
||||||
|
|
||||||
assert_includes_and_joins_equal(
|
assert_includes_and_joins_equal(
|
||||||
Member.where('sponsors.id' => mustache.id),
|
Member.where('sponsors.id' => mustache.id),
|
||||||
[members(:groucho)], :nested_sponsors
|
[members(:groucho)], :nested_sponsors
|
||||||
)
|
)
|
||||||
|
|
||||||
members = assert_queries(4) { Member.includes(:nested_sponsors).to_a }
|
members = assert_queries(4) { Member.includes(:nested_sponsors).to_a }
|
||||||
assert_no_queries do
|
assert_no_queries do
|
||||||
assert_equal [mustache], members.first.nested_sponsors
|
assert_equal [mustache], members.first.nested_sponsors
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# has_many through
|
# has_many through
|
||||||
# Source: has_many through
|
# Source: has_many through
|
||||||
# Through: has_one
|
# Through: has_one
|
||||||
def test_has_many_through_has_one_with_has_many_through_source_reflection
|
def test_has_many_through_has_one_with_has_many_through_source_reflection
|
||||||
groucho_details, other_details = member_details(:groucho), member_details(:some_other_guy)
|
groucho_details, other_details = member_details(:groucho), member_details(:some_other_guy)
|
||||||
|
|
||||||
assert_equal [groucho_details, other_details],
|
assert_equal [groucho_details, other_details],
|
||||||
members(:groucho).organization_member_details.order('member_details.id')
|
members(:groucho).organization_member_details.order('member_details.id')
|
||||||
|
|
||||||
assert_includes_and_joins_equal(
|
assert_includes_and_joins_equal(
|
||||||
Member.where('member_details.id' => member_details(:groucho).id).order('member_details.id'),
|
Member.where('member_details.id' => member_details(:groucho).id).order('member_details.id'),
|
||||||
[members(:groucho), members(:some_other_guy)], :organization_member_details
|
[members(:groucho), members(:some_other_guy)], :organization_member_details
|
||||||
)
|
)
|
||||||
|
|
||||||
members = Member.joins(:organization_member_details).
|
members = Member.joins(:organization_member_details).
|
||||||
where('member_details.id' => 9)
|
where('member_details.id' => 9)
|
||||||
assert members.empty?
|
assert members.empty?
|
||||||
|
|
||||||
members = assert_queries(4) { Member.includes(:organization_member_details).to_a.sort_by(&:id) }
|
members = assert_queries(4) { Member.includes(:organization_member_details).to_a.sort_by(&:id) }
|
||||||
assert_no_queries do
|
assert_no_queries do
|
||||||
assert_equal [groucho_details, other_details], members.first.organization_member_details.sort_by(&:id)
|
assert_equal [groucho_details, other_details], members.first.organization_member_details.sort_by(&:id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# has_many through
|
# has_many through
|
||||||
# Source: has_many
|
# Source: has_many
|
||||||
# Through: has_one through
|
# Through: has_one through
|
||||||
def test_has_many_through_has_one_through_with_has_many_source_reflection
|
def test_has_many_through_has_one_through_with_has_many_source_reflection
|
||||||
groucho_details, other_details = member_details(:groucho), member_details(:some_other_guy)
|
groucho_details, other_details = member_details(:groucho), member_details(:some_other_guy)
|
||||||
|
|
||||||
assert_equal [groucho_details, other_details],
|
assert_equal [groucho_details, other_details],
|
||||||
members(:groucho).organization_member_details_2.order('member_details.id')
|
members(:groucho).organization_member_details_2.order('member_details.id')
|
||||||
|
|
||||||
assert_includes_and_joins_equal(
|
assert_includes_and_joins_equal(
|
||||||
Member.where('member_details.id' => groucho_details.id).order('member_details.id'),
|
Member.where('member_details.id' => groucho_details.id).order('member_details.id'),
|
||||||
[members(:groucho), members(:some_other_guy)], :organization_member_details_2
|
[members(:groucho), members(:some_other_guy)], :organization_member_details_2
|
||||||
)
|
)
|
||||||
|
|
||||||
members = Member.joins(:organization_member_details_2).
|
members = Member.joins(:organization_member_details_2).
|
||||||
where('member_details.id' => 9)
|
where('member_details.id' => 9)
|
||||||
assert members.empty?
|
assert members.empty?
|
||||||
|
|
||||||
members = assert_queries(4) { Member.includes(:organization_member_details_2).to_a.sort_by(&:id) }
|
members = assert_queries(4) { Member.includes(:organization_member_details_2).to_a.sort_by(&:id) }
|
||||||
assert_no_queries do
|
assert_no_queries do
|
||||||
assert_equal [groucho_details, other_details], members.first.organization_member_details_2.sort_by(&:id)
|
assert_equal [groucho_details, other_details], members.first.organization_member_details_2.sort_by(&:id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# has_many through
|
# has_many through
|
||||||
# Source: has_and_belongs_to_many
|
# Source: has_and_belongs_to_many
|
||||||
# Through: has_many
|
# Through: has_many
|
||||||
def test_has_many_through_has_many_with_has_and_belongs_to_many_source_reflection
|
def test_has_many_through_has_many_with_has_and_belongs_to_many_source_reflection
|
||||||
general, cooking = categories(:general), categories(:cooking)
|
general, cooking = categories(:general), categories(:cooking)
|
||||||
|
|
||||||
assert_equal [general, cooking], authors(:bob).post_categories.order('categories.id')
|
assert_equal [general, cooking], authors(:bob).post_categories.order('categories.id')
|
||||||
|
|
||||||
assert_includes_and_joins_equal(
|
assert_includes_and_joins_equal(
|
||||||
Author.where('categories.id' => cooking.id),
|
Author.where('categories.id' => cooking.id),
|
||||||
[authors(:bob)], :post_categories
|
[authors(:bob)], :post_categories
|
||||||
)
|
)
|
||||||
|
|
||||||
authors = assert_queries(3) { Author.includes(:post_categories).to_a.sort_by(&:id) }
|
authors = assert_queries(3) { Author.includes(:post_categories).to_a.sort_by(&:id) }
|
||||||
assert_no_queries do
|
assert_no_queries do
|
||||||
assert_equal [general, cooking], authors[2].post_categories.sort_by(&:id)
|
assert_equal [general, cooking], authors[2].post_categories.sort_by(&:id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# has_many through
|
# has_many through
|
||||||
# Source: has_many
|
# Source: has_many
|
||||||
# Through: has_and_belongs_to_many
|
# Through: has_and_belongs_to_many
|
||||||
def test_has_many_through_has_and_belongs_to_many_with_has_many_source_reflection
|
def test_has_many_through_has_and_belongs_to_many_with_has_many_source_reflection
|
||||||
greetings, more = comments(:greetings), comments(:more_greetings)
|
greetings, more = comments(:greetings), comments(:more_greetings)
|
||||||
|
|
||||||
assert_equal [greetings, more], categories(:technology).post_comments.order('comments.id')
|
assert_equal [greetings, more], categories(:technology).post_comments.order('comments.id')
|
||||||
|
|
||||||
assert_includes_and_joins_equal(
|
assert_includes_and_joins_equal(
|
||||||
Category.where('comments.id' => more.id).order('comments.id'),
|
Category.where('comments.id' => more.id).order('comments.id'),
|
||||||
[categories(:general), categories(:technology)], :post_comments
|
[categories(:general), categories(:technology)], :post_comments
|
||||||
)
|
)
|
||||||
|
|
||||||
categories = assert_queries(3) { Category.includes(:post_comments).to_a.sort_by(&:id) }
|
categories = assert_queries(3) { Category.includes(:post_comments).to_a.sort_by(&:id) }
|
||||||
assert_no_queries do
|
assert_no_queries do
|
||||||
assert_equal [greetings, more], categories[1].post_comments.sort_by(&:id)
|
assert_equal [greetings, more], categories[1].post_comments.sort_by(&:id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# has_many through
|
# has_many through
|
||||||
# Source: has_many through a habtm
|
# Source: has_many through a habtm
|
||||||
# Through: has_many through
|
# Through: has_many through
|
||||||
def test_has_many_through_has_many_with_has_many_through_habtm_source_reflection
|
def test_has_many_through_has_many_with_has_many_through_habtm_source_reflection
|
||||||
greetings, more = comments(:greetings), comments(:more_greetings)
|
greetings, more = comments(:greetings), comments(:more_greetings)
|
||||||
|
|
||||||
assert_equal [greetings, more], authors(:bob).category_post_comments.order('comments.id')
|
assert_equal [greetings, more], authors(:bob).category_post_comments.order('comments.id')
|
||||||
|
|
||||||
assert_includes_and_joins_equal(
|
assert_includes_and_joins_equal(
|
||||||
Author.where('comments.id' => comments(:does_it_hurt).id).order('comments.id'),
|
Author.where('comments.id' => comments(:does_it_hurt).id).order('comments.id'),
|
||||||
[authors(:david), authors(:mary)], :category_post_comments
|
[authors(:david), authors(:mary)], :category_post_comments
|
||||||
)
|
)
|
||||||
|
|
||||||
authors = assert_queries(5) { Author.includes(:category_post_comments).to_a.sort_by(&:id) }
|
authors = assert_queries(5) { Author.includes(:category_post_comments).to_a.sort_by(&:id) }
|
||||||
assert_no_queries do
|
assert_no_queries do
|
||||||
assert_equal [greetings, more], authors[2].category_post_comments.sort_by(&:id)
|
assert_equal [greetings, more], authors[2].category_post_comments.sort_by(&:id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# has_many through
|
# has_many through
|
||||||
# Source: belongs_to
|
# Source: belongs_to
|
||||||
# Through: has_many through
|
# Through: has_many through
|
||||||
def test_has_many_through_has_many_through_with_belongs_to_source_reflection
|
def test_has_many_through_has_many_through_with_belongs_to_source_reflection
|
||||||
general = tags(:general)
|
general = tags(:general)
|
||||||
|
|
||||||
assert_equal [general, general], authors(:david).tagging_tags
|
assert_equal [general, general], authors(:david).tagging_tags
|
||||||
|
|
||||||
assert_includes_and_joins_equal(
|
assert_includes_and_joins_equal(
|
||||||
Author.where('tags.id' => tags(:general).id),
|
Author.where('tags.id' => tags(:general).id),
|
||||||
[authors(:david)], :tagging_tags
|
[authors(:david)], :tagging_tags
|
||||||
)
|
)
|
||||||
|
|
||||||
authors = assert_queries(5) { Author.includes(:tagging_tags).to_a }
|
authors = assert_queries(5) { Author.includes(:tagging_tags).to_a }
|
||||||
assert_no_queries do
|
assert_no_queries do
|
||||||
assert_equal [general, general], authors.first.tagging_tags
|
assert_equal [general, general], authors.first.tagging_tags
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# has_many through
|
# has_many through
|
||||||
# Source: has_many through
|
# Source: has_many through
|
||||||
# Through: belongs_to
|
# Through: belongs_to
|
||||||
def test_has_many_through_belongs_to_with_has_many_through_source_reflection
|
def test_has_many_through_belongs_to_with_has_many_through_source_reflection
|
||||||
welcome_general, thinking_general = taggings(:welcome_general), taggings(:thinking_general)
|
welcome_general, thinking_general = taggings(:welcome_general), taggings(:thinking_general)
|
||||||
|
|
||||||
assert_equal [welcome_general, thinking_general],
|
assert_equal [welcome_general, thinking_general],
|
||||||
categorizations(:david_welcome_general).post_taggings.order('taggings.id')
|
categorizations(:david_welcome_general).post_taggings.order('taggings.id')
|
||||||
|
|
||||||
assert_includes_and_joins_equal(
|
assert_includes_and_joins_equal(
|
||||||
Categorization.where('taggings.id' => welcome_general.id).order('taggings.id'),
|
Categorization.where('taggings.id' => welcome_general.id).order('taggings.id'),
|
||||||
[categorizations(:david_welcome_general)], :post_taggings
|
[categorizations(:david_welcome_general)], :post_taggings
|
||||||
)
|
)
|
||||||
|
|
||||||
categorizations = assert_queries(4) { Categorization.includes(:post_taggings).to_a.sort_by(&:id) }
|
categorizations = assert_queries(4) { Categorization.includes(:post_taggings).to_a.sort_by(&:id) }
|
||||||
assert_no_queries do
|
assert_no_queries do
|
||||||
assert_equal [welcome_general, thinking_general], categorizations.first.post_taggings.sort_by(&:id)
|
assert_equal [welcome_general, thinking_general], categorizations.first.post_taggings.sort_by(&:id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# has_one through
|
# has_one through
|
||||||
# Source: has_one through
|
# Source: has_one through
|
||||||
# Through: has_one
|
# Through: has_one
|
||||||
def test_has_one_through_has_one_with_has_one_through_source_reflection
|
def test_has_one_through_has_one_with_has_one_through_source_reflection
|
||||||
founding = member_types(:founding)
|
founding = member_types(:founding)
|
||||||
|
|
||||||
assert_equal founding, members(:groucho).nested_member_type
|
assert_equal founding, members(:groucho).nested_member_type
|
||||||
|
|
||||||
assert_includes_and_joins_equal(
|
assert_includes_and_joins_equal(
|
||||||
Member.where('member_types.id' => founding.id),
|
Member.where('member_types.id' => founding.id),
|
||||||
[members(:groucho)], :nested_member_type
|
[members(:groucho)], :nested_member_type
|
||||||
)
|
)
|
||||||
|
|
||||||
members = assert_queries(4) { Member.includes(:nested_member_type).to_a.sort_by(&:id) }
|
members = assert_queries(4) { Member.includes(:nested_member_type).to_a.sort_by(&:id) }
|
||||||
assert_no_queries do
|
assert_no_queries do
|
||||||
assert_equal founding, members.first.nested_member_type
|
assert_equal founding, members.first.nested_member_type
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# has_one through
|
# has_one through
|
||||||
# Source: belongs_to
|
# Source: belongs_to
|
||||||
# Through: has_one through
|
# Through: has_one through
|
||||||
def test_has_one_through_has_one_through_with_belongs_to_source_reflection
|
def test_has_one_through_has_one_through_with_belongs_to_source_reflection
|
||||||
general = categories(:general)
|
general = categories(:general)
|
||||||
|
|
||||||
assert_equal general, members(:groucho).club_category
|
assert_equal general, members(:groucho).club_category
|
||||||
|
|
||||||
assert_includes_and_joins_equal(
|
assert_includes_and_joins_equal(
|
||||||
Member.where('categories.id' => categories(:technology).id),
|
Member.where('categories.id' => categories(:technology).id),
|
||||||
[members(:blarpy_winkup)], :club_category
|
[members(:blarpy_winkup)], :club_category
|
||||||
)
|
)
|
||||||
|
|
||||||
members = assert_queries(4) { Member.includes(:club_category).to_a.sort_by(&:id) }
|
members = assert_queries(4) { Member.includes(:club_category).to_a.sort_by(&:id) }
|
||||||
assert_no_queries do
|
assert_no_queries do
|
||||||
assert_equal general, members.first.club_category
|
assert_equal general, members.first.club_category
|
||||||
@ -320,34 +320,34 @@ def test_distinct_has_many_through_a_has_many_through_association_on_through_ref
|
|||||||
assert_equal [subscribers(:first), subscribers(:second)],
|
assert_equal [subscribers(:first), subscribers(:second)],
|
||||||
author.distinct_subscribers.order('subscribers.nick')
|
author.distinct_subscribers.order('subscribers.nick')
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_nested_has_many_through_with_a_table_referenced_multiple_times
|
def test_nested_has_many_through_with_a_table_referenced_multiple_times
|
||||||
author = authors(:bob)
|
author = authors(:bob)
|
||||||
assert_equal [posts(:misc_by_bob), posts(:misc_by_mary), posts(:other_by_bob), posts(:other_by_mary)],
|
assert_equal [posts(:misc_by_bob), posts(:misc_by_mary), posts(:other_by_bob), posts(:other_by_mary)],
|
||||||
author.similar_posts.sort_by(&:id)
|
author.similar_posts.sort_by(&:id)
|
||||||
|
|
||||||
# Mary and Bob both have posts in misc, but they are the only ones.
|
# Mary and Bob both have posts in misc, but they are the only ones.
|
||||||
authors = Author.joins(:similar_posts).where('posts.id' => posts(:misc_by_bob).id)
|
authors = Author.joins(:similar_posts).where('posts.id' => posts(:misc_by_bob).id)
|
||||||
assert_equal [authors(:mary), authors(:bob)], authors.uniq.sort_by(&:id)
|
assert_equal [authors(:mary), authors(:bob)], authors.uniq.sort_by(&:id)
|
||||||
|
|
||||||
# Check the polymorphism of taggings is being observed correctly (in both joins)
|
# Check the polymorphism of taggings is being observed correctly (in both joins)
|
||||||
authors = Author.joins(:similar_posts).where('taggings.taggable_type' => 'FakeModel')
|
authors = Author.joins(:similar_posts).where('taggings.taggable_type' => 'FakeModel')
|
||||||
assert authors.empty?
|
assert authors.empty?
|
||||||
authors = Author.joins(:similar_posts).where('taggings_authors_join.taggable_type' => 'FakeModel')
|
authors = Author.joins(:similar_posts).where('taggings_authors_join.taggable_type' => 'FakeModel')
|
||||||
assert authors.empty?
|
assert authors.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_has_many_through_with_foreign_key_option_on_through_reflection
|
def test_has_many_through_with_foreign_key_option_on_through_reflection
|
||||||
assert_equal [posts(:welcome), posts(:authorless)], people(:david).agents_posts.order('posts.id')
|
assert_equal [posts(:welcome), posts(:authorless)], people(:david).agents_posts.order('posts.id')
|
||||||
assert_equal [authors(:david)], references(:david_unicyclist).agents_posts_authors
|
assert_equal [authors(:david)], references(:david_unicyclist).agents_posts_authors
|
||||||
|
|
||||||
references = Reference.joins(:agents_posts_authors).where('authors.id' => authors(:david).id)
|
references = Reference.joins(:agents_posts_authors).where('authors.id' => authors(:david).id)
|
||||||
assert_equal [references(:david_unicyclist)], references
|
assert_equal [references(:david_unicyclist)], references
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_has_many_through_with_foreign_key_option_on_source_reflection
|
def test_has_many_through_with_foreign_key_option_on_source_reflection
|
||||||
assert_equal [people(:michael), people(:susan)], jobs(:unicyclist).agents.order('people.id')
|
assert_equal [people(:michael), people(:susan)], jobs(:unicyclist).agents.order('people.id')
|
||||||
|
|
||||||
jobs = Job.joins(:agents)
|
jobs = Job.joins(:agents)
|
||||||
assert_equal [jobs(:unicyclist), jobs(:unicyclist)], jobs
|
assert_equal [jobs(:unicyclist), jobs(:unicyclist)], jobs
|
||||||
end
|
end
|
||||||
@ -355,7 +355,7 @@ def test_has_many_through_with_foreign_key_option_on_source_reflection
|
|||||||
def test_has_many_through_with_sti_on_through_reflection
|
def test_has_many_through_with_sti_on_through_reflection
|
||||||
ratings = posts(:sti_comments).special_comments_ratings.sort_by(&:id)
|
ratings = posts(:sti_comments).special_comments_ratings.sort_by(&:id)
|
||||||
assert_equal [ratings(:special_comment_rating), ratings(:sub_special_comment_rating)], ratings
|
assert_equal [ratings(:special_comment_rating), ratings(:sub_special_comment_rating)], ratings
|
||||||
|
|
||||||
# Ensure STI is respected in the join
|
# Ensure STI is respected in the join
|
||||||
scope = Post.joins(:special_comments_ratings).where(:id => posts(:sti_comments).id)
|
scope = Post.joins(:special_comments_ratings).where(:id => posts(:sti_comments).id)
|
||||||
assert scope.where("comments.type" => "Comment").empty?
|
assert scope.where("comments.type" => "Comment").empty?
|
||||||
@ -366,101 +366,101 @@ def test_has_many_through_with_sti_on_through_reflection
|
|||||||
def test_nested_has_many_through_writers_should_raise_error
|
def test_nested_has_many_through_writers_should_raise_error
|
||||||
david = authors(:david)
|
david = authors(:david)
|
||||||
subscriber = subscribers(:first)
|
subscriber = subscribers(:first)
|
||||||
|
|
||||||
assert_raises(ActiveRecord::HasManyThroughNestedAssociationsAreReadonly) do
|
assert_raises(ActiveRecord::HasManyThroughNestedAssociationsAreReadonly) do
|
||||||
david.subscribers = [subscriber]
|
david.subscribers = [subscriber]
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_raises(ActiveRecord::HasManyThroughNestedAssociationsAreReadonly) do
|
assert_raises(ActiveRecord::HasManyThroughNestedAssociationsAreReadonly) do
|
||||||
david.subscriber_ids = [subscriber.id]
|
david.subscriber_ids = [subscriber.id]
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_raises(ActiveRecord::HasManyThroughNestedAssociationsAreReadonly) do
|
assert_raises(ActiveRecord::HasManyThroughNestedAssociationsAreReadonly) do
|
||||||
david.subscribers << subscriber
|
david.subscribers << subscriber
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_raises(ActiveRecord::HasManyThroughNestedAssociationsAreReadonly) do
|
assert_raises(ActiveRecord::HasManyThroughNestedAssociationsAreReadonly) do
|
||||||
david.subscribers.delete(subscriber)
|
david.subscribers.delete(subscriber)
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_raises(ActiveRecord::HasManyThroughNestedAssociationsAreReadonly) do
|
assert_raises(ActiveRecord::HasManyThroughNestedAssociationsAreReadonly) do
|
||||||
david.subscribers.clear
|
david.subscribers.clear
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_raises(ActiveRecord::HasManyThroughNestedAssociationsAreReadonly) do
|
assert_raises(ActiveRecord::HasManyThroughNestedAssociationsAreReadonly) do
|
||||||
david.subscribers.build
|
david.subscribers.build
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_raises(ActiveRecord::HasManyThroughNestedAssociationsAreReadonly) do
|
assert_raises(ActiveRecord::HasManyThroughNestedAssociationsAreReadonly) do
|
||||||
david.subscribers.create
|
david.subscribers.create
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_nested_has_one_through_writers_should_raise_error
|
def test_nested_has_one_through_writers_should_raise_error
|
||||||
groucho = members(:groucho)
|
groucho = members(:groucho)
|
||||||
founding = member_types(:founding)
|
founding = member_types(:founding)
|
||||||
|
|
||||||
assert_raises(ActiveRecord::HasManyThroughNestedAssociationsAreReadonly) do
|
assert_raises(ActiveRecord::HasManyThroughNestedAssociationsAreReadonly) do
|
||||||
groucho.nested_member_type = founding
|
groucho.nested_member_type = founding
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_nested_has_many_through_with_conditions_on_through_associations
|
def test_nested_has_many_through_with_conditions_on_through_associations
|
||||||
blue, bob = tags(:blue), authors(:bob)
|
blue, bob = tags(:blue), authors(:bob)
|
||||||
|
|
||||||
assert_equal [blue], bob.misc_post_first_blue_tags
|
assert_equal [blue], bob.misc_post_first_blue_tags
|
||||||
|
|
||||||
# Pointless condition to force single-query loading
|
# Pointless condition to force single-query loading
|
||||||
assert_includes_and_joins_equal(
|
assert_includes_and_joins_equal(
|
||||||
Author.where('tags.id = tags.id'),
|
Author.where('tags.id = tags.id'),
|
||||||
[bob], :misc_post_first_blue_tags
|
[bob], :misc_post_first_blue_tags
|
||||||
)
|
)
|
||||||
|
|
||||||
assert Author.where('tags.id' => 100).joins(:misc_post_first_blue_tags).empty?
|
assert Author.where('tags.id' => 100).joins(:misc_post_first_blue_tags).empty?
|
||||||
|
|
||||||
authors = assert_queries(3) { Author.includes(:misc_post_first_blue_tags).to_a.sort_by(&:id) }
|
authors = assert_queries(3) { Author.includes(:misc_post_first_blue_tags).to_a.sort_by(&:id) }
|
||||||
assert_no_queries do
|
assert_no_queries do
|
||||||
assert_equal [blue], authors[2].misc_post_first_blue_tags
|
assert_equal [blue], authors[2].misc_post_first_blue_tags
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_nested_has_many_through_with_conditions_on_source_associations
|
def test_nested_has_many_through_with_conditions_on_source_associations
|
||||||
blue, bob = tags(:blue), authors(:bob)
|
blue, bob = tags(:blue), authors(:bob)
|
||||||
|
|
||||||
assert_equal [blue], bob.misc_post_first_blue_tags_2
|
assert_equal [blue], bob.misc_post_first_blue_tags_2
|
||||||
|
|
||||||
# Pointless condition to force single-query loading
|
# Pointless condition to force single-query loading
|
||||||
assert_includes_and_joins_equal(
|
assert_includes_and_joins_equal(
|
||||||
Author.where('tags.id = tags.id'),
|
Author.where('tags.id = tags.id'),
|
||||||
[bob], :misc_post_first_blue_tags_2
|
[bob], :misc_post_first_blue_tags_2
|
||||||
)
|
)
|
||||||
|
|
||||||
authors = assert_queries(4) { Author.includes(:misc_post_first_blue_tags_2).to_a.sort_by(&:id) }
|
authors = assert_queries(4) { Author.includes(:misc_post_first_blue_tags_2).to_a.sort_by(&:id) }
|
||||||
assert_no_queries do
|
assert_no_queries do
|
||||||
assert_equal [blue], authors[2].misc_post_first_blue_tags_2
|
assert_equal [blue], authors[2].misc_post_first_blue_tags_2
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_nested_has_many_through_with_foreign_key_option_on_the_source_reflection_through_reflection
|
def test_nested_has_many_through_with_foreign_key_option_on_the_source_reflection_through_reflection
|
||||||
assert_equal [categories(:general)], organizations(:nsa).author_essay_categories
|
assert_equal [categories(:general)], organizations(:nsa).author_essay_categories
|
||||||
|
|
||||||
organizations = Organization.joins(:author_essay_categories).
|
organizations = Organization.joins(:author_essay_categories).
|
||||||
where('categories.id' => categories(:general).id)
|
where('categories.id' => categories(:general).id)
|
||||||
assert_equal [organizations(:nsa)], organizations
|
assert_equal [organizations(:nsa)], organizations
|
||||||
|
|
||||||
assert_equal categories(:general), organizations(:nsa).author_owned_essay_category
|
assert_equal categories(:general), organizations(:nsa).author_owned_essay_category
|
||||||
|
|
||||||
organizations = Organization.joins(:author_owned_essay_category).
|
organizations = Organization.joins(:author_owned_essay_category).
|
||||||
where('categories.id' => categories(:general).id)
|
where('categories.id' => categories(:general).id)
|
||||||
assert_equal [organizations(:nsa)], organizations
|
assert_equal [organizations(:nsa)], organizations
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def assert_includes_and_joins_equal(query, expected, association)
|
def assert_includes_and_joins_equal(query, expected, association)
|
||||||
actual = assert_queries(1) { query.joins(association).to_a.uniq }
|
actual = assert_queries(1) { query.joins(association).to_a.uniq }
|
||||||
assert_equal expected, actual
|
assert_equal expected, actual
|
||||||
|
|
||||||
actual = assert_queries(1) { query.includes(association).to_a.uniq }
|
actual = assert_queries(1) { query.includes(association).to_a.uniq }
|
||||||
assert_equal expected, actual
|
assert_equal expected, actual
|
||||||
end
|
end
|
||||||
|
@ -200,7 +200,7 @@ def test_reflection_should_not_raise_error_when_compared_to_other_object
|
|||||||
def test_has_many_through_reflection
|
def test_has_many_through_reflection
|
||||||
assert_kind_of ThroughReflection, Subscriber.reflect_on_association(:books)
|
assert_kind_of ThroughReflection, Subscriber.reflect_on_association(:books)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_through_reflection_chain
|
def test_through_reflection_chain
|
||||||
expected = [
|
expected = [
|
||||||
Author.reflect_on_association(:essay_categories),
|
Author.reflect_on_association(:essay_categories),
|
||||||
@ -208,10 +208,10 @@ def test_through_reflection_chain
|
|||||||
Organization.reflect_on_association(:authors)
|
Organization.reflect_on_association(:authors)
|
||||||
]
|
]
|
||||||
actual = Organization.reflect_on_association(:author_essay_categories).through_reflection_chain
|
actual = Organization.reflect_on_association(:author_essay_categories).through_reflection_chain
|
||||||
|
|
||||||
assert_equal expected, actual
|
assert_equal expected, actual
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_through_conditions
|
def test_through_conditions
|
||||||
expected = [
|
expected = [
|
||||||
["tags.name = 'Blue'"],
|
["tags.name = 'Blue'"],
|
||||||
@ -220,7 +220,7 @@ def test_through_conditions
|
|||||||
]
|
]
|
||||||
actual = Author.reflect_on_association(:misc_post_first_blue_tags).through_conditions
|
actual = Author.reflect_on_association(:misc_post_first_blue_tags).through_conditions
|
||||||
assert_equal expected, actual
|
assert_equal expected, actual
|
||||||
|
|
||||||
expected = [
|
expected = [
|
||||||
["tags.name = 'Blue'", "taggings.comment = 'first'", "posts.title LIKE 'misc post%'"],
|
["tags.name = 'Blue'", "taggings.comment = 'first'", "posts.title LIKE 'misc post%'"],
|
||||||
[],
|
[],
|
||||||
@ -229,27 +229,27 @@ def test_through_conditions
|
|||||||
actual = Author.reflect_on_association(:misc_post_first_blue_tags_2).through_conditions
|
actual = Author.reflect_on_association(:misc_post_first_blue_tags_2).through_conditions
|
||||||
assert_equal expected, actual
|
assert_equal expected, actual
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_nested?
|
def test_nested?
|
||||||
assert !Author.reflect_on_association(:comments).nested?
|
assert !Author.reflect_on_association(:comments).nested?
|
||||||
assert Author.reflect_on_association(:tags).nested?
|
assert Author.reflect_on_association(:tags).nested?
|
||||||
|
|
||||||
# Only goes :through once, but the through_reflection is a has_and_belongs_to_many, so this is
|
# Only goes :through once, but the through_reflection is a has_and_belongs_to_many, so this is
|
||||||
# a nested through association
|
# a nested through association
|
||||||
assert Category.reflect_on_association(:post_comments).nested?
|
assert Category.reflect_on_association(:post_comments).nested?
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_association_primary_key
|
def test_association_primary_key
|
||||||
# Normal association
|
# Normal association
|
||||||
assert_equal "id", Author.reflect_on_association(:posts).association_primary_key.to_s
|
assert_equal "id", Author.reflect_on_association(:posts).association_primary_key.to_s
|
||||||
assert_equal "name", Author.reflect_on_association(:essay).association_primary_key.to_s
|
assert_equal "name", Author.reflect_on_association(:essay).association_primary_key.to_s
|
||||||
|
|
||||||
# Through association (uses the :primary_key option from the source reflection)
|
# Through association (uses the :primary_key option from the source reflection)
|
||||||
assert_equal "nick", Author.reflect_on_association(:subscribers).association_primary_key.to_s
|
assert_equal "nick", Author.reflect_on_association(:subscribers).association_primary_key.to_s
|
||||||
assert_equal "name", Author.reflect_on_association(:essay_category).association_primary_key.to_s
|
assert_equal "name", Author.reflect_on_association(:essay_category).association_primary_key.to_s
|
||||||
assert_equal "custom_primary_key", Author.reflect_on_association(:tags_with_primary_key).association_primary_key.to_s # nested
|
assert_equal "custom_primary_key", Author.reflect_on_association(:tags_with_primary_key).association_primary_key.to_s # nested
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_active_record_primary_key
|
def test_active_record_primary_key
|
||||||
assert_equal "nick", Subscriber.reflect_on_association(:subscriptions).active_record_primary_key.to_s
|
assert_equal "nick", Subscriber.reflect_on_association(:subscriptions).active_record_primary_key.to_s
|
||||||
assert_equal "name", Author.reflect_on_association(:essay).active_record_primary_key.to_s
|
assert_equal "name", Author.reflect_on_association(:essay).active_record_primary_key.to_s
|
||||||
|
@ -96,7 +96,7 @@ def testing_proxy_target
|
|||||||
has_many :subscriptions, :through => :books
|
has_many :subscriptions, :through => :books
|
||||||
has_many :subscribers, :through => :subscriptions, :order => "subscribers.nick" # through has_many :through (on through reflection)
|
has_many :subscribers, :through => :subscriptions, :order => "subscribers.nick" # through has_many :through (on through reflection)
|
||||||
has_many :distinct_subscribers, :through => :subscriptions, :source => :subscriber, :select => "DISTINCT subscribers.*", :order => "subscribers.nick"
|
has_many :distinct_subscribers, :through => :subscriptions, :source => :subscriber, :select => "DISTINCT subscribers.*", :order => "subscribers.nick"
|
||||||
|
|
||||||
has_one :essay, :primary_key => :name, :as => :writer
|
has_one :essay, :primary_key => :name, :as => :writer
|
||||||
has_one :essay_category, :through => :essay, :source => :category
|
has_one :essay_category, :through => :essay, :source => :category
|
||||||
has_one :essay_owner, :through => :essay, :source => :owner
|
has_one :essay_owner, :through => :essay, :source => :owner
|
||||||
@ -107,7 +107,7 @@ def testing_proxy_target
|
|||||||
has_many :essays, :primary_key => :name, :as => :writer
|
has_many :essays, :primary_key => :name, :as => :writer
|
||||||
has_many :essay_categories, :through => :essays, :source => :category
|
has_many :essay_categories, :through => :essays, :source => :category
|
||||||
has_many :essay_owners, :through => :essays, :source => :owner
|
has_many :essay_owners, :through => :essays, :source => :owner
|
||||||
|
|
||||||
has_many :essays_2, :primary_key => :name, :class_name => 'Essay', :foreign_key => :author_id
|
has_many :essays_2, :primary_key => :name, :class_name => 'Essay', :foreign_key => :author_id
|
||||||
has_many :essay_categories_2, :through => :essays_2, :source => :category
|
has_many :essay_categories_2, :through => :essays_2, :source => :category
|
||||||
|
|
||||||
@ -119,7 +119,7 @@ def testing_proxy_target
|
|||||||
|
|
||||||
has_many :post_categories, :through => :posts, :source => :categories
|
has_many :post_categories, :through => :posts, :source => :categories
|
||||||
has_many :category_post_comments, :through => :categories, :source => :post_comments
|
has_many :category_post_comments, :through => :categories, :source => :post_comments
|
||||||
|
|
||||||
has_many :misc_posts, :class_name => 'Post', :conditions => "posts.title LIKE 'misc post%'"
|
has_many :misc_posts, :class_name => 'Post', :conditions => "posts.title LIKE 'misc post%'"
|
||||||
has_many :misc_post_first_blue_tags, :through => :misc_posts, :source => :first_blue_tags
|
has_many :misc_post_first_blue_tags, :through => :misc_posts, :source => :first_blue_tags
|
||||||
|
|
||||||
|
@ -2,6 +2,6 @@ class Categorization < ActiveRecord::Base
|
|||||||
belongs_to :post
|
belongs_to :post
|
||||||
belongs_to :category
|
belongs_to :category
|
||||||
belongs_to :author
|
belongs_to :author
|
||||||
|
|
||||||
has_many :post_taggings, :through => :author, :source => :taggings
|
has_many :post_taggings, :through => :author, :source => :taggings
|
||||||
end
|
end
|
||||||
|
@ -23,7 +23,7 @@ def self.what_are_you
|
|||||||
|
|
||||||
has_many :categorizations
|
has_many :categorizations
|
||||||
has_many :authors, :through => :categorizations, :select => 'authors.*, categorizations.post_id'
|
has_many :authors, :through => :categorizations, :select => 'authors.*, categorizations.post_id'
|
||||||
|
|
||||||
has_many :post_comments, :through => :posts, :source => :comments
|
has_many :post_comments, :through => :posts, :source => :comments
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -2,6 +2,6 @@ class Job < ActiveRecord::Base
|
|||||||
has_many :references
|
has_many :references
|
||||||
has_many :people, :through => :references
|
has_many :people, :through => :references
|
||||||
belongs_to :ideal_reference, :class_name => 'Reference'
|
belongs_to :ideal_reference, :class_name => 'Reference'
|
||||||
|
|
||||||
has_many :agents, :through => :people
|
has_many :agents, :through => :people
|
||||||
end
|
end
|
||||||
|
@ -9,15 +9,15 @@ class Member < ActiveRecord::Base
|
|||||||
has_one :member_detail
|
has_one :member_detail
|
||||||
has_one :organization, :through => :member_detail
|
has_one :organization, :through => :member_detail
|
||||||
belongs_to :member_type
|
belongs_to :member_type
|
||||||
|
|
||||||
has_many :nested_member_types, :through => :member_detail, :source => :member_type
|
has_many :nested_member_types, :through => :member_detail, :source => :member_type
|
||||||
has_one :nested_member_type, :through => :member_detail, :source => :member_type
|
has_one :nested_member_type, :through => :member_detail, :source => :member_type
|
||||||
|
|
||||||
has_many :nested_sponsors, :through => :sponsor_club, :source => :sponsor
|
has_many :nested_sponsors, :through => :sponsor_club, :source => :sponsor
|
||||||
has_one :nested_sponsor, :through => :sponsor_club, :source => :sponsor
|
has_one :nested_sponsor, :through => :sponsor_club, :source => :sponsor
|
||||||
|
|
||||||
has_many :organization_member_details, :through => :member_detail
|
has_many :organization_member_details, :through => :member_detail
|
||||||
has_many :organization_member_details_2, :through => :organization, :source => :member_details
|
has_many :organization_member_details_2, :through => :organization, :source => :member_details
|
||||||
|
|
||||||
has_one :club_category, :through => :club, :source => :category
|
has_one :club_category, :through => :club, :source => :category
|
||||||
end
|
end
|
||||||
|
@ -2,6 +2,6 @@ class MemberDetail < ActiveRecord::Base
|
|||||||
belongs_to :member
|
belongs_to :member
|
||||||
belongs_to :organization
|
belongs_to :organization
|
||||||
has_one :member_type, :through => :member
|
has_one :member_type, :through => :member
|
||||||
|
|
||||||
has_many :organization_member_details, :through => :organization, :source => :member_details
|
has_many :organization_member_details, :through => :organization, :source => :member_details
|
||||||
end
|
end
|
||||||
|
@ -4,7 +4,7 @@ class Organization < ActiveRecord::Base
|
|||||||
|
|
||||||
has_many :authors, :primary_key => :name
|
has_many :authors, :primary_key => :name
|
||||||
has_many :author_essay_categories, :through => :authors, :source => :essay_categories
|
has_many :author_essay_categories, :through => :authors, :source => :essay_categories
|
||||||
|
|
||||||
has_one :author, :primary_key => :name
|
has_one :author, :primary_key => :name
|
||||||
has_one :author_owned_essay_category, :through => :author, :source => :owned_essay_category
|
has_one :author_owned_essay_category, :through => :author, :source => :owned_essay_category
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ class Person < ActiveRecord::Base
|
|||||||
belongs_to :primary_contact, :class_name => 'Person'
|
belongs_to :primary_contact, :class_name => 'Person'
|
||||||
has_many :agents, :class_name => 'Person', :foreign_key => 'primary_contact_id'
|
has_many :agents, :class_name => 'Person', :foreign_key => 'primary_contact_id'
|
||||||
belongs_to :number1_fan, :class_name => 'Person'
|
belongs_to :number1_fan, :class_name => 'Person'
|
||||||
|
|
||||||
has_many :agents_posts, :through => :agents, :source => :posts
|
has_many :agents_posts, :through => :agents, :source => :posts
|
||||||
has_many :agents_posts_authors, :through => :agents_posts, :source => :author
|
has_many :agents_posts_authors, :through => :agents_posts, :source => :author
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ def find_most_recent
|
|||||||
has_one :very_special_comment_with_post, :class_name => "VerySpecialComment", :include => :post
|
has_one :very_special_comment_with_post, :class_name => "VerySpecialComment", :include => :post
|
||||||
has_many :special_comments
|
has_many :special_comments
|
||||||
has_many :nonexistant_comments, :class_name => 'Comment', :conditions => 'comments.id < 0'
|
has_many :nonexistant_comments, :class_name => 'Comment', :conditions => 'comments.id < 0'
|
||||||
|
|
||||||
has_many :special_comments_ratings, :through => :special_comments, :source => :ratings
|
has_many :special_comments_ratings, :through => :special_comments, :source => :ratings
|
||||||
|
|
||||||
has_and_belongs_to_many :categories
|
has_and_belongs_to_many :categories
|
||||||
@ -65,7 +65,7 @@ def add_joins_and_select
|
|||||||
has_many :super_tags, :through => :taggings
|
has_many :super_tags, :through => :taggings
|
||||||
has_many :tags_with_primary_key, :through => :taggings, :source => :tag_with_primary_key
|
has_many :tags_with_primary_key, :through => :taggings, :source => :tag_with_primary_key
|
||||||
has_one :tagging, :as => :taggable
|
has_one :tagging, :as => :taggable
|
||||||
|
|
||||||
has_many :first_taggings, :as => :taggable, :class_name => 'Tagging', :conditions => "taggings.comment = 'first'"
|
has_many :first_taggings, :as => :taggable, :class_name => 'Tagging', :conditions => "taggings.comment = 'first'"
|
||||||
has_many :first_blue_tags, :through => :first_taggings, :source => :tag, :conditions => "tags.name = 'Blue'"
|
has_many :first_blue_tags, :through => :first_taggings, :source => :tag, :conditions => "tags.name = 'Blue'"
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
class Reference < ActiveRecord::Base
|
class Reference < ActiveRecord::Base
|
||||||
belongs_to :person
|
belongs_to :person
|
||||||
belongs_to :job
|
belongs_to :job
|
||||||
|
|
||||||
has_many :agents_posts_authors, :through => :person
|
has_many :agents_posts_authors, :through => :person
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user