Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 135 lines (110 sloc) 4.34 kB
db045db @dhh Initial
dhh authored
1 module ActiveRecord
fde9504 @rizwanreza Adds title to activerecord/lib/active_record/associations/*
rizwanreza authored
2 # = Active Record Has And Belongs To Many Association
db045db @dhh Initial
dhh authored
3 module Associations
4 class HasAndBelongsToManyAssociation < AssociationCollection #:nodoc:
90171ad @tenderlove avoid creating so many Arel::Table objects
tenderlove authored
5 attr_reader :join_table
6
7 def initialize(owner, reflection)
8 @join_table_name = reflection.options[:join_table]
9 @join_table = Arel::Table.new(@join_table_name)
10 super
11 end
3103296 @jonleighton Let AssociationCollection#find use #scoped to do its finding. Note th…
jonleighton authored
12
3ee4e00 @lukeludwig Cache columns for has_and_belongs_to_many associations
lukeludwig authored
13 def columns
90171ad @tenderlove avoid creating so many Arel::Table objects
tenderlove authored
14 @reflection.columns(@join_table_name, "#{@join_table_name} Columns")
3ee4e00 @lukeludwig Cache columns for has_and_belongs_to_many associations
lukeludwig authored
15 end
16
17 def reset_column_information
18 @reflection.reset_column_information
19 end
20
3b6a9a0 @jeremy Revert "Assert primary key does not exist in habtm when the associati…
jeremy authored
21 def has_primary_key?
90171ad @tenderlove avoid creating so many Arel::Table objects
tenderlove authored
22 @has_primary_key ||= @owner.connection.supports_primary_key? && @owner.connection.primary_key(@join_table_name)
3b6a9a0 @jeremy Revert "Assert primary key does not exist in habtm when the associati…
jeremy authored
23 end
24
9bc75fd @lifo Remove duplicate code from associations. [Pratik]
lifo authored
25 protected
c1f833d @miloops habtm delete method integrated with ARel.
miloops authored
26
db045db @dhh Initial
dhh authored
27 def count_records
823554e @dhh Added support for associating unsaved objects #402 [Tim Bates]
dhh authored
28 load_target.size
db045db @dhh Initial
dhh authored
29 end
30
5cda000 @dhh Fixed that autosave should validate associations even if master is in…
dhh authored
31 def insert_record(record, force = true, validate = true)
e444439 @josevalim Partialy revert f1c13b0dd7b22b5f6289ca1a09f1d7a8c7c8584b
josevalim authored
32 if record.new_record?
379c022 @jonleighton Specify insert_record with NotImplementedError in AssociationCollecti…
jonleighton authored
33 return false unless save_record(record, force, validate)
a2f26b9 @dhh Fixed that adding a record to a has_and_belongs_to collection would a…
dhh authored
34 end
b29c01e @dhh Added that has_and_belongs_to_many associations with additional attri…
dhh authored
35
6abda69 @dhh Added preliminary support for join models [DHH] Added preliminary sup…
dhh authored
36 if @reflection.options[:insert_sql]
4979448 @technoweenie Ensure that modifying has_and_belongs_to_many actions clear the query…
technoweenie authored
37 @owner.connection.insert(interpolate_sql(@reflection.options[:insert_sql], record))
db045db @dhh Initial
dhh authored
38 else
8bdc191 @tenderlove we have a method for this, so let's use it
tenderlove authored
39 relation = join_table
f3e4229 @josevalim Ensure all join table attributes will be in the same timestamp.
josevalim authored
40 timestamps = record_timestamp_columns(record)
41 timezone = record.send(:current_time_from_proper_timezone) if timestamps.any?
42
1563351 @tenderlove removing some calls to insert on arel
tenderlove authored
43 attributes = columns.map do |column|
f3e4229 @josevalim Ensure all join table attributes will be in the same timestamp.
josevalim authored
44 name = column.name
ea35ccf @miloops Perf: refactor method.
miloops authored
45 value = case name.to_s
1267598 @jonleighton Rename AssociationReflection#primary_key_name to foreign_key, since t…
jonleighton authored
46 when @reflection.foreign_key.to_s
ea35ccf @miloops Perf: refactor method.
miloops authored
47 @owner.id
6c1c16b @ddollar Fixes a subtle bug when using symbols for key definitions in habtm as…
ddollar authored
48 when @reflection.association_foreign_key.to_s
ea35ccf @miloops Perf: refactor method.
miloops authored
49 record.id
f3e4229 @josevalim Ensure all join table attributes will be in the same timestamp.
josevalim authored
50 when *timestamps
ea35ccf @miloops Perf: refactor method.
miloops authored
51 timezone
b29c01e @dhh Added that has_and_belongs_to_many associations with additional attri…
dhh authored
52 else
ea35ccf @miloops Perf: refactor method.
miloops authored
53 @owner.send(:quote_value, record[name], column) if record.has_attribute?(name)
b29c01e @dhh Added that has_and_belongs_to_many associations with additional attri…
dhh authored
54 end
ea35ccf @miloops Perf: refactor method.
miloops authored
55 [relation[name], value] unless value.nil?
1563351 @tenderlove removing some calls to insert on arel
tenderlove authored
56 end
b29c01e @dhh Added that has_and_belongs_to_many associations with additional attri…
dhh authored
57
1563351 @tenderlove removing some calls to insert on arel
tenderlove authored
58 stmt = relation.compile_insert Hash[attributes]
59 @owner.connection.insert stmt.to_sql
db045db @dhh Initial
dhh authored
60 end
800b899 @jeremy Remove deprecated push_with_attributes.
jeremy authored
61
a3bd62e @miloops Remove explicit return.
miloops authored
62 true
db045db @dhh Initial
dhh authored
63 end
800b899 @jeremy Remove deprecated push_with_attributes.
jeremy authored
64
db045db @dhh Initial
dhh authored
65 def delete_records(records)
6abda69 @dhh Added preliminary support for join models [DHH] Added preliminary sup…
dhh authored
66 if sql = @reflection.options[:delete_sql]
4979448 @technoweenie Ensure that modifying has_and_belongs_to_many actions clear the query…
technoweenie authored
67 records.each { |record| @owner.connection.delete(interpolate_sql(sql, record)) }
db045db @dhh Initial
dhh authored
68 else
8bdc191 @tenderlove we have a method for this, so let's use it
tenderlove authored
69 relation = join_table
1267598 @jonleighton Rename AssociationReflection#primary_key_name to foreign_key, since t…
jonleighton authored
70 stmt = relation.where(relation[@reflection.foreign_key].eq(@owner.id).
79ef26c @tenderlove do not pass nil values to arel
tenderlove authored
71 and(relation[@reflection.association_foreign_key].in(records.map { |x| x.id }.compact))
9a3e29e @tenderlove remove calls to deprecated methods
tenderlove authored
72 ).compile_delete
73 @owner.connection.delete stmt.to_sql
db045db @dhh Initial
dhh authored
74 end
75 end
a3bd62e @miloops Remove explicit return.
miloops authored
76
b82fab2 @jonleighton Refactoring: replace the mix of variables like @finder_sql, @counter_…
jonleighton authored
77 def construct_joins
e468a62 @tenderlove use arel ast construction rather than generating strings
tenderlove authored
78 right = join_table
79 left = @reflection.klass.arel_table
80
81 condition = left[@reflection.klass.primary_key].eq(
82 right[@reflection.association_foreign_key])
83
84 right.create_join(right, right.create_on(condition))
b82fab2 @jonleighton Refactoring: replace the mix of variables like @finder_sql, @counter_…
jonleighton authored
85 end
800b899 @jeremy Remove deprecated push_with_attributes.
jeremy authored
86
e8ada11 @jonleighton Associations: DRY up the code which is generating conditions, and mak…
jonleighton authored
87 def construct_owner_conditions
88 super(join_table)
823554e @dhh Added support for associating unsaved objects #402 [Tim Bates]
dhh authored
89 end
53aa8da @dhh Fixed that records returned from has_and_belongs_to_many associations…
dhh authored
90
770e689 @jonleighton Construct an actual ActiveRecord::Relation object for the association…
jonleighton authored
91 def association_scope
92 scope = super.joins(construct_joins)
93 scope = scope.readonly if ambiguous_select?(@reflection.options[:select])
94 scope
95 end
96
97 def select_value
98 super || [@reflection.klass.arel_table[Arel.star], join_table[Arel.star]]
02adc49 @jeremy Simplify association proxy implementation by factoring construct_scop…
jeremy authored
99 end
100
b451de0 @spastorino Deletes trailing whitespaces (over text files only find * -type f -ex…
spastorino authored
101 # Join tables with additional columns on top of the two foreign keys must be considered
102 # ambiguous unless a select clause has been explicitly defined. Otherwise you can get
103 # broken records back, if, for example, the join column also has an id column. This will
1ce40ca @neerajdotname ensuring that description does not exceed 100 columns
neerajdotname authored
104 # then overwrite the id column of the records coming back.
3103296 @jonleighton Let AssociationCollection#find use #scoped to do its finding. Note th…
jonleighton authored
105 def ambiguous_select?(select)
106 extra_join_columns? && select.nil?
107 end
108
109 def extra_join_columns?
110 columns.size > 2
53aa8da @dhh Fixed that records returned from has_and_belongs_to_many associations…
dhh authored
111 end
a72c1ec @jeremy Refactor association create and build so before & after callbacks beh…
jeremy authored
112
113 private
f3e4229 @josevalim Ensure all join table attributes will be in the same timestamp.
josevalim authored
114 def record_timestamp_columns(record)
115 if record.record_timestamps
a7eb8d9 @sikachu Removing most of the symbol to proc usage in Active Record
sikachu authored
116 record.send(:all_timestamp_attributes).map { |x| x.to_s }
f3e4229 @josevalim Ensure all join table attributes will be in the same timestamp.
josevalim authored
117 else
118 []
119 end
120 end
9f5c18c @jonleighton Refactor we_can_set_the_inverse_on_this? to use a less bizarre name a…
jonleighton authored
121
122 def invertible_for?(record)
123 false
124 end
3103296 @jonleighton Let AssociationCollection#find use #scoped to do its finding. Note th…
jonleighton authored
125
126 def find_by_sql(*args)
127 options = args.extract_options!
128 ambiguous = ambiguous_select?(@reflection.options[:select] || options[:select])
129
130 scoped.readonly(ambiguous).find(*(args << options))
131 end
823554e @dhh Added support for associating unsaved objects #402 [Tim Bates]
dhh authored
132 end
db045db @dhh Initial
dhh authored
133 end
68d1056 @dhh Fixed that has_and_belongs_to_many would generate bad sql when naming…
dhh authored
134 end
Something went wrong with that request. Please try again.