composite_primary_keys 3.1.11 → 4.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. data/History.txt +6 -8
  2. data/lib/composite_primary_keys.rb +53 -36
  3. data/lib/composite_primary_keys/associations/association.rb +23 -0
  4. data/lib/composite_primary_keys/associations/association_scope.rb +67 -0
  5. data/lib/composite_primary_keys/associations/has_and_belongs_to_many_association.rb +31 -121
  6. data/lib/composite_primary_keys/associations/has_many_association.rb +27 -66
  7. data/lib/composite_primary_keys/associations/join_dependency/join_association.rb +22 -0
  8. data/lib/composite_primary_keys/associations/join_dependency/join_part.rb +39 -0
  9. data/lib/composite_primary_keys/associations/preloader/association.rb +61 -0
  10. data/lib/composite_primary_keys/associations/preloader/belongs_to.rb +13 -0
  11. data/lib/composite_primary_keys/associations/preloader/has_and_belongs_to_many.rb +46 -0
  12. data/lib/composite_primary_keys/attribute_methods/dirty.rb +30 -0
  13. data/lib/composite_primary_keys/attribute_methods/read.rb +88 -0
  14. data/lib/composite_primary_keys/attribute_methods/write.rb +33 -0
  15. data/lib/composite_primary_keys/base.rb +18 -70
  16. data/lib/composite_primary_keys/composite_predicates.rb +53 -0
  17. data/lib/composite_primary_keys/connection_adapters/abstract_adapter.rb +6 -4
  18. data/lib/composite_primary_keys/connection_adapters/postgresql_adapter.rb +19 -41
  19. data/lib/composite_primary_keys/fixtures.rb +19 -6
  20. data/lib/composite_primary_keys/persistence.rb +32 -13
  21. data/lib/composite_primary_keys/relation.rb +23 -16
  22. data/lib/composite_primary_keys/relation/calculations.rb +48 -0
  23. data/lib/composite_primary_keys/relation/finder_methods.rb +117 -0
  24. data/lib/composite_primary_keys/relation/query_methods.rb +24 -0
  25. data/lib/composite_primary_keys/validations/uniqueness.rb +19 -23
  26. data/lib/composite_primary_keys/version.rb +5 -5
  27. data/test/connections/native_mysql/connection.rb +1 -1
  28. data/test/fixtures/articles.yml +1 -0
  29. data/test/fixtures/products.yml +2 -4
  30. data/test/fixtures/readings.yml +1 -0
  31. data/test/fixtures/suburbs.yml +1 -4
  32. data/test/fixtures/users.yml +1 -0
  33. data/test/test_associations.rb +61 -63
  34. data/test/test_attributes.rb +16 -21
  35. data/test/test_create.rb +3 -3
  36. data/test/test_delete.rb +87 -84
  37. data/test/{test_clone.rb → test_dup.rb} +8 -5
  38. data/test/test_exists.rb +22 -10
  39. data/test/test_habtm.rb +0 -74
  40. data/test/test_ids.rb +2 -1
  41. data/test/test_miscellaneous.rb +2 -2
  42. data/test/test_polymorphic.rb +1 -1
  43. data/test/test_suite.rb +1 -1
  44. data/test/test_update.rb +3 -3
  45. metadata +76 -75
  46. data/lib/composite_primary_keys/association_preload.rb +0 -158
  47. data/lib/composite_primary_keys/associations.rb +0 -155
  48. data/lib/composite_primary_keys/associations/association_proxy.rb +0 -33
  49. data/lib/composite_primary_keys/associations/has_one_association.rb +0 -27
  50. data/lib/composite_primary_keys/associations/through_association_scope.rb +0 -103
  51. data/lib/composite_primary_keys/attribute_methods.rb +0 -84
  52. data/lib/composite_primary_keys/calculations.rb +0 -31
  53. data/lib/composite_primary_keys/connection_adapters/ibm_db_adapter.rb +0 -21
  54. data/lib/composite_primary_keys/connection_adapters/oracle_adapter.rb +0 -15
  55. data/lib/composite_primary_keys/connection_adapters/oracle_enhanced_adapter.rb +0 -17
  56. data/lib/composite_primary_keys/connection_adapters/sqlite3_adapter.rb +0 -15
  57. data/lib/composite_primary_keys/finder_methods.rb +0 -123
  58. data/lib/composite_primary_keys/primary_key.rb +0 -19
  59. data/lib/composite_primary_keys/query_methods.rb +0 -24
  60. data/lib/composite_primary_keys/read.rb +0 -25
  61. data/lib/composite_primary_keys/reflection.rb +0 -37
  62. data/lib/composite_primary_keys/write.rb +0 -18
@@ -1,158 +0,0 @@
1
- module CompositePrimaryKeys
2
- module ActiveRecord
3
- module AssociationPreload
4
- def self.append_features(base)
5
- super
6
- base.send(:extend, ClassMethods)
7
- end
8
-
9
- # Composite key versions of Association functions
10
- module ClassMethods
11
- def preload_has_and_belongs_to_many_association(records, reflection, preload_options={})
12
- table_name = reflection.klass.quoted_table_name
13
- id_to_record_map, ids = construct_id_map(records)
14
- records.each {|record| record.send(reflection.name).loaded}
15
- options = reflection.options
16
-
17
- if composite?
18
- where = (primary_key * ids.size).in_groups_of(primary_key.size).map do |keys|
19
- "(" + keys.map{|key| "t0.#{connection.quote_column_name(key)} = ?"}.join(" AND ") + ")"
20
- end.join(" OR ")
21
-
22
- conditions = [where, ids].flatten
23
- joins = "INNER JOIN #{connection.quote_table_name options[:join_table]} t0 ON #{full_composite_join_clause(reflection, reflection.klass.table_name, reflection.klass.primary_key, 't0', reflection.association_foreign_key)}"
24
- parent_primary_keys = reflection.cpk_primary_key.map{|k| "t0.#{connection.quote_column_name(k)}"}
25
- concat_arr = parent_primary_keys.zip(["'#{CompositePrimaryKeys::ID_SEP}'"] * (parent_primary_keys.size - 1)).flatten.compact
26
- parent_record_id = connection.concat(*concat_arr)
27
- else
28
- conditions = "t0.#{reflection.primary_key_name} #{in_or_equals_for_ids(ids)}"
29
- conditions << append_conditions(reflection, preload_options)
30
- conditions = [conditions, ids]
31
- joins = "INNER JOIN #{connection.quote_table_name options[:join_table]} t0 ON #{reflection.klass.quoted_table_name}.#{reflection.klass.primary_key} = t0.#{reflection.association_foreign_key}"
32
- parent_record_id = reflection.primary_key_name
33
- end
34
-
35
- associated_records = reflection.klass.unscoped.where(conditions).
36
- includes(options[:include]).
37
- joins(joins).
38
- select("#{options[:select] || table_name+'.*'}, #{parent_record_id} as the_parent_record_id").
39
- order(options[:order]).to_a
40
-
41
- set_association_collection_records(id_to_record_map, reflection.name, associated_records, 'the_parent_record_id')
42
- end
43
-
44
- def preload_belongs_to_association(records, reflection, preload_options={})
45
- return if records.first.send("loaded_#{reflection.name}?")
46
- options = reflection.options
47
-
48
- ids = Array.new
49
-
50
- if options[:polymorphic]
51
- # CPK
52
- #polymorph_type = options[:foreign_type]
53
- #klasses_and_ids = {}
54
-
55
- # Construct a mapping from klass to a list of ids to load and a mapping of those ids back to their parent_records
56
- #records.each do |record|
57
- # if klass = record.send(polymorph_type)
58
- # klass_id = record.send(primary_key_name)
59
- # if klass_id
60
- # id_map = klasses_and_ids[klass] ||= {}
61
- # id_list_for_klass_id = (id_map[klass_id.to_s] ||= [])
62
- # id_list_for_klass_id << record
63
- # end
64
- # end
65
- #end
66
- #klasses_and_ids = klasses_and_ids.to_a
67
- raise AssociationNotSupported, "Polymorphic joins not supported for composite keys"
68
- else
69
- # I need to keep the original ids for each record (as opposed to the stringified) so
70
- # that they get properly converted for each db so the id_map ends up looking like:
71
- #
72
- # { '1,2' => {:id => [1,2], :records => [...records...]}}
73
- id_map = {}
74
-
75
- records.each do |record|
76
- keys = record[reflection.cpk_primary_key]
77
- ids << keys
78
-
79
- mapped_records = (id_map[keys.to_s] ||= [])
80
- mapped_records << record
81
- end
82
-
83
- klasses_and_ids = [[reflection.klass.name, id_map]]
84
- end
85
-
86
- klasses_and_ids.each do |klass_and_id|
87
- klass_name, id_map = *klass_and_id
88
- next if id_map.empty?
89
- klass = klass_name.constantize
90
-
91
- table_name = klass.quoted_table_name
92
- primary_key = [reflection.options[:primary_key] || klass.primary_key].flatten
93
-
94
- # CPK
95
- conditions = id_map.map do |key, value|
96
- "(" +
97
- primary_key.map do |key|
98
- "#{table_name}.#{connection.quote_column_name(key)} = ?"
99
- end.join(' AND ') + ")"
100
- end.join(' OR ')
101
-
102
- conditions << append_conditions(reflection, preload_options)
103
-
104
- conditions = [conditions] + ids.uniq.flatten
105
-
106
- associated_records = klass.unscoped.where(conditions).apply_finder_options(options.slice(:include, :select, :joins, :order)).to_a
107
-
108
- set_association_single_records(id_map, reflection.name, associated_records, primary_key)
109
- end
110
- end
111
-
112
- def find_associated_records(ids, reflection, preload_options)
113
- options = reflection.options
114
- table_name = reflection.klass.quoted_table_name
115
-
116
- if interface = reflection.options[:as]
117
- conditions = "#{reflection.klass.quoted_table_name}.#{connection.quote_column_name "#{interface}_id"} #{in_or_equals_for_ids(ids)} and #{reflection.klass.quoted_table_name}.#{connection.quote_column_name "#{interface}_type"} = '#{self.base_class.sti_name}'"
118
- else
119
- foreign_key = reflection.cpk_primary_key
120
-
121
- where = (foreign_key * ids.size).in_groups_of(foreign_key.size).map do |keys|
122
- "(" + keys.map{|key| "#{reflection.klass.quoted_table_name}.#{connection.quote_column_name(key)} = ?"}.join(" AND ") + ")"
123
- end.join(" OR ")
124
-
125
- conditions = [where, ids].flatten
126
- end
127
-
128
- conditions[0] << append_conditions(reflection, preload_options)
129
-
130
- find_options = {
131
- :select => preload_options[:select] || options[:select] || "#{table_name}.*",
132
- :include => preload_options[:include] || options[:include],
133
- # CPK
134
- # :conditions => [conditions, ids],
135
- :conditions => conditions,
136
- :joins => options[:joins],
137
- :group => preload_options[:group] || options[:group],
138
- :order => preload_options[:order] || options[:order]
139
- }
140
-
141
- reflection.klass.unscoped.apply_finder_options(find_options).to_a
142
- end
143
-
144
- def full_composite_join_clause(reflection, table1, full_keys1, table2, full_keys2)
145
- connection = reflection.active_record.connection
146
- full_keys1 = full_keys1.split(CompositePrimaryKeys::ID_SEP) if full_keys1.is_a?(String)
147
- full_keys2 = full_keys2.split(CompositePrimaryKeys::ID_SEP) if full_keys2.is_a?(String)
148
- where_clause = [full_keys1, full_keys2].transpose.map do |key_pair|
149
- quoted1 = connection.quote_table_name(table1)
150
- quoted2 = connection.quote_table_name(table2)
151
- "#{quoted1}.#{connection.quote_column_name(key_pair.first)}=#{quoted2}.#{connection.quote_column_name(key_pair.last)}"
152
- end.join(" AND ")
153
- "(#{where_clause})"
154
- end
155
- end
156
- end
157
- end
158
- end
@@ -1,155 +0,0 @@
1
- module ActiveRecord
2
- module Associations
3
- module ClassMethods
4
- class JoinDependency
5
- class JoinBase
6
- def aliased_primary_key
7
- # CPK
8
- # "#{aliased_prefix}_r0"
9
-
10
- active_record.composite? ?
11
- primary_key.inject([]) {|aliased_keys, key| aliased_keys << "#{ aliased_prefix }_r#{aliased_keys.length}"} :
12
- "#{ aliased_prefix }_r0"
13
- end
14
-
15
- def record_id(row)
16
- # CPK
17
- # row[aliased_primary_key]
18
- active_record.composite? ?
19
- aliased_primary_key.map {|key| row[key]}.to_composite_keys :
20
- row[aliased_primary_key]
21
- end
22
-
23
- def column_names_with_alias
24
- unless defined?(@column_names_with_alias)
25
- @column_names_with_alias = []
26
- keys = active_record.composite? ? primary_key.map(&:to_s) : [primary_key]
27
- (keys + (column_names - keys)).each_with_index do |column_name, i|
28
- @column_names_with_alias << [column_name, "#{ aliased_prefix }_r#{ i }"]
29
- end
30
- end
31
- @column_names_with_alias
32
- end
33
- end
34
-
35
- class JoinAssociation
36
- # Ugly to include this twice, but I couldn't figure out how to make this
37
- # work via a module
38
- def composite_join_predicates(table1, keys1, table2, keys2)
39
- attributes1 = [keys1].flatten.map do |key|
40
- table1[key]
41
- end
42
-
43
- attributes2 = [keys2].flatten.map do |key|
44
- table2[key]
45
- end
46
-
47
- [attributes1, attributes2].transpose.map do |attribute1, attribute2|
48
- attribute1.eq(attribute2)
49
- end
50
- end
51
-
52
- def association_join
53
- return @join if @join
54
-
55
- aliased_table = Arel::Table.new(table_name, :as => @aliased_table_name,
56
- :engine => arel_engine,
57
- :columns => klass.columns)
58
-
59
- parent_table = Arel::Table.new(parent.table_name, :as => parent.aliased_table_name,
60
- :engine => arel_engine,
61
- :columns => parent.active_record.columns)
62
-
63
- @join = case reflection.macro
64
- when :has_and_belongs_to_many
65
- join_table = Arel::Table.new(options[:join_table], :as => aliased_join_table_name, :engine => arel_engine)
66
- fk = options[:foreign_key] || reflection.active_record.to_s.foreign_key
67
- klass_fk = options[:association_foreign_key] || klass.to_s.foreign_key
68
-
69
- [
70
- join_table[fk].eq(parent_table[reflection.active_record.primary_key]),
71
- aliased_table[klass.primary_key].eq(join_table[klass_fk])
72
- ]
73
- when :has_many, :has_one
74
- if reflection.options[:through]
75
- join_table = Arel::Table.new(through_reflection.klass.table_name, :as => aliased_join_table_name, :engine => arel_engine)
76
- jt_as_extra = jt_source_extra = jt_sti_extra = nil
77
- first_key = second_key = as_extra = nil
78
-
79
- if through_reflection.macro == :belongs_to
80
- jt_primary_key = through_reflection.primary_key_name
81
- jt_foreign_key = through_reflection.association_primary_key
82
- else
83
- jt_primary_key = through_reflection.active_record_primary_key
84
- jt_foreign_key = through_reflection.primary_key_name
85
-
86
- if through_reflection.options[:as] # has_many :through against a polymorphic join
87
- jt_as_extra = join_table[through_reflection.options[:as].to_s + '_type'].eq(parent.active_record.base_class.name)
88
- end
89
- end
90
-
91
- case source_reflection.macro
92
- when :has_many
93
- if source_reflection.options[:as]
94
- first_key = "#{source_reflection.options[:as]}_id"
95
- second_key = options[:foreign_key] || primary_key
96
- as_extra = aliased_table["#{source_reflection.options[:as]}_type"].eq(source_reflection.active_record.base_class.name)
97
- else
98
- first_key = through_reflection.klass.base_class.to_s.foreign_key
99
- second_key = options[:foreign_key] || primary_key
100
- end
101
-
102
- unless through_reflection.klass.descends_from_active_record?
103
- jt_sti_extra = join_table[through_reflection.active_record.inheritance_column].eq(through_reflection.klass.sti_name)
104
- end
105
- when :belongs_to
106
- first_key = primary_key
107
- if reflection.options[:source_type]
108
- second_key = source_reflection.association_foreign_key
109
- jt_source_extra = join_table[reflection.source_reflection.options[:foreign_type]].eq(reflection.options[:source_type])
110
- else
111
- second_key = source_reflection.primary_key_name
112
- end
113
- end
114
-
115
- [
116
- [parent_table[jt_primary_key].eq(join_table[jt_foreign_key]), jt_as_extra, jt_source_extra, jt_sti_extra].reject{|x| x.blank? },
117
- aliased_table[first_key].eq(join_table[second_key])
118
- ]
119
- elsif reflection.options[:as]
120
- id_rel = aliased_table["#{reflection.options[:as]}_id"].eq(parent_table[parent.primary_key])
121
- type_rel = aliased_table["#{reflection.options[:as]}_type"].eq(parent.active_record.base_class.name)
122
- [id_rel, type_rel]
123
- else
124
- foreign_key = options[:foreign_key] || reflection.active_record.name.foreign_key
125
- # CPK
126
- #[aliased_table[foreign_key].eq(parent_table[reflection.options[:primary_key] || parent.primary_key])]
127
- composite_join_predicates(aliased_table, foreign_key,
128
- parent_table, reflection.options[:primary_key] || parent.primary_key)
129
- end
130
- when :belongs_to
131
- #[aliased_table[options[:primary_key] || reflection.klass.primary_key].eq(parent_table[options[:foreign_key] || reflection.primary_key_name])]
132
- composite_join_predicates(aliased_table, options[:primary_key] || reflection.klass.primary_key, parent_table, options[:foreign_key] || reflection.primary_key_name)
133
- end
134
-
135
- unless klass.descends_from_active_record?
136
- sti_column = aliased_table[klass.inheritance_column]
137
- sti_condition = sti_column.eq(klass.sti_name)
138
- klass.descendants.each {|subclass| sti_condition = sti_condition.or(sti_column.eq(subclass.sti_name)) }
139
-
140
- @join << sti_condition
141
- end
142
-
143
- [through_reflection, reflection].each do |ref|
144
- if ref && ref.options[:conditions]
145
- @join << process_conditions(ref.options[:conditions], aliased_table_name)
146
- end
147
- end
148
-
149
- @join
150
- end
151
- end
152
- end
153
- end
154
- end
155
- end
@@ -1,33 +0,0 @@
1
- module ActiveRecord
2
- module Associations
3
- class AssociationProxy
4
- def full_columns_equals(table_name, keys, quoted_ids)
5
- quoted_table_name = @owner.connection.quote_table_name(table_name)
6
-
7
- keys = [keys].flatten
8
- ids = [quoted_ids].flatten
9
-
10
- [keys,ids].transpose.map do |key, id|
11
- "(#{quoted_table_name}.#{@owner.connection.quote_column_name(key)} = #{id})"
12
- end.join(' AND ')
13
- end
14
-
15
- def set_belongs_to_association_for(record)
16
- if @reflection.options[:as]
17
- record["#{@reflection.options[:as]}_id"] = @owner.id unless @owner.new_record?
18
- record["#{@reflection.options[:as]}_type"] = @owner.class.base_class.name.to_s
19
- else
20
- unless @owner.new_record?
21
- primary_keys = Array(@reflection.options[:primary_key] || :id)
22
- # CPK
23
- # record[@reflection.primary_key_name] = @owner.send(primary_key)
24
- # Need to flatten because a key may be :id giving a composite key
25
- values = primary_keys.map {|key| @owner.send(key)}.flatten
26
- key_values = @reflection.cpk_primary_key.zip(values)
27
- key_values.each {|key, value| record[key] = value}
28
- end
29
- end
30
- end
31
- end
32
- end
33
- end
@@ -1,27 +0,0 @@
1
- module ActiveRecord
2
- module Associations
3
- class HasOneAssociation
4
- def construct_sql
5
- case
6
- when @reflection.options[:as]
7
- @finder_sql =
8
- "#{@reflection.quoted_table_name}.#{@reflection.options[:as]}_id = #{owner_quoted_id} AND " +
9
- "#{@reflection.quoted_table_name}.#{@reflection.options[:as]}_type = #{@owner.class.quote_value(@owner.class.base_class.name.to_s)}"
10
- else
11
- # CPK
12
- #@finder_sql = "#{@reflection.quoted_table_name}.#{@reflection.primary_key_name} = #{owner_quoted_id}"
13
- @finder_sql = full_columns_equals(@reflection.table_name, @reflection.cpk_primary_key, owner_quoted_id)
14
- end
15
- @finder_sql << " AND (#{conditions})" if conditions
16
- end
17
-
18
- def owner_quoted_id
19
- if (keys = @reflection.options[:primary_key])
20
- keys.is_a?(Array) ? keys.collect {|k| @owner.class.quote_value(@owner.send(k)) } : @owner.class.quote_value(@owner.send(keys))
21
- else
22
- @owner.quoted_id
23
- end
24
- end
25
- end
26
- end
27
- end
@@ -1,103 +0,0 @@
1
- module ActiveRecord
2
- module Associations
3
- module ThroughAssociationScope
4
- def composite_join_clause(table1, keys1, table2, keys2)
5
- predicates = composite_join_predicates(table1, keys1, table2, keys2)
6
-
7
- join_clause = predicates.map do |predicate|
8
- predicate.to_sql
9
- end.join(" AND ")
10
-
11
- "(#{join_clause})"
12
- end
13
-
14
- def composite_join_predicates(table1, keys1, table2, keys2)
15
- attributes1 = [keys1].flatten.map do |key|
16
- table1[key]
17
- end
18
-
19
- attributes2 = [keys2].flatten.map do |key|
20
- table2[key]
21
- end
22
-
23
- [attributes1, attributes2].transpose.map do |attribute1, attribute2|
24
- attribute1.eq(attribute2)
25
- end
26
- end
27
-
28
- def composite_ids_hash(keys, ids)
29
- [keys].flatten.zip([ids].flatten).inject(Hash.new) do |hash, (key, value)|
30
- hash[key] = value
31
- hash
32
- end
33
- end
34
-
35
- def construct_quoted_owner_attributes(reflection)
36
- if as = reflection.options[:as]
37
- { "#{as}_id" => owner_quoted_id,
38
- "#{as}_type" => reflection.klass.quote_value(
39
- @owner.class.base_class.name.to_s,
40
- reflection.klass.columns_hash["#{as}_type"]) }
41
- elsif reflection.macro == :belongs_to
42
- # CPK
43
- # { reflection.klass.primary_key => @owner[reflection.primary_key_name] }
44
- composite_ids_hash(reflection.klass.primary_key, @owner.quoted_id)
45
- else
46
- # CPK
47
- #{ reflection.primary_key_name => owner_quoted_id }
48
- composite_ids_hash(reflection.cpk_primary_key, @owner.quoted_id)
49
- end
50
- end
51
-
52
- # Construct attributes for associate pointing to owner.
53
- def construct_owner_attributes(reflection)
54
- if as = reflection.options[:as]
55
- { "#{as}_id" => @owner.id,
56
- "#{as}_type" => @owner.class.base_class.name.to_s }
57
- else
58
- # CPK
59
- # { reflection.primary_key_name => @owner.id }
60
- composite_ids_hash(reflection.cpk_primary_key, @owner.id)
61
- end
62
- end
63
-
64
- def construct_joins(custom_joins = nil)
65
- polymorphic_join = nil
66
- if @reflection.source_reflection.macro == :belongs_to
67
- reflection_primary_key = @reflection.klass.primary_key
68
- source_primary_key = @reflection.source_reflection.cpk_primary_key
69
- if @reflection.options[:source_type]
70
- polymorphic_join = "AND %s.%s = %s" % [
71
- @reflection.through_reflection.quoted_table_name, "#{@reflection.source_reflection.options[:foreign_type]}",
72
- @owner.class.quote_value(@reflection.options[:source_type])
73
- ]
74
- end
75
- else
76
- reflection_primary_key = @reflection.source_reflection.cpk_primary_key
77
- source_primary_key = @reflection.through_reflection.klass.primary_key
78
- if @reflection.source_reflection.options[:as]
79
- polymorphic_join = "AND %s.%s = %s" % [
80
- @reflection.quoted_table_name, "#{@reflection.source_reflection.options[:as]}_type",
81
- @owner.class.quote_value(@reflection.through_reflection.klass.name)
82
- ]
83
- end
84
- end
85
-
86
- # CPK
87
- # "INNER JOIN %s ON %s.%s = %s.%s %s #{@reflection.options[:joins]} #{custom_joins}" % [
88
- # @reflection.through_reflection.quoted_table_name,
89
- # @reflection.quoted_table_name, reflection_primary_key,
90
- # @reflection.through_reflection.quoted_table_name, source_primary_key,
91
- # polymorphic_join
92
- # ]
93
-
94
- "INNER JOIN %s ON %s %s #{@reflection.options[:joins]} #{custom_joins}" % [
95
- @reflection.through_reflection.quoted_table_name,
96
- composite_join_clause(@reflection.klass.arel_table, reflection_primary_key,
97
- @reflection.through_reflection.klass.arel_table, source_primary_key),
98
- polymorphic_join
99
- ]
100
- end
101
- end
102
- end
103
- end