Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 166 lines (139 sloc) 5.982 kb
db045db David Heinemeier Hansson Initial
dhh authored
1 module ActiveRecord
2 module Associations
3 class HasAndBelongsToManyAssociation < AssociationCollection #:nodoc:
6abda69 David Heinemeier Hansson Added preliminary support for join models [DHH] Added preliminary suppor...
dhh authored
4 def initialize(owner, reflection)
823554e David Heinemeier Hansson Added support for associating unsaved objects #402 [Tim Bates]
dhh authored
5 super
6 construct_sql
db045db David Heinemeier Hansson Initial
dhh authored
7 end
800b899 Jeremy Kemper Remove deprecated push_with_attributes.
jeremy authored
8
823554e David Heinemeier Hansson Added support for associating unsaved objects #402 [Tim Bates]
dhh authored
9 def build(attributes = {})
10 load_target
6abda69 David Heinemeier Hansson Added preliminary support for join models [DHH] Added preliminary suppor...
dhh authored
11 record = @reflection.klass.new(attributes)
823554e David Heinemeier Hansson Added support for associating unsaved objects #402 [Tim Bates]
dhh authored
12 @target << record
13 record
14 end
15
06075a9 risk danger olson Fix the has_and_belongs_to_many #create doesn't populate the join for ne...
technoweenie authored
16 def create(attributes = {})
18a3333 Michael Koziarski Formatting, grammar and spelling fixes for the associations documentatio...
NZKoz authored
17 # Can't use Base.create because the foreign key may be a protected attribute.
7010ee3 Michael Koziarski Stop users from calling .create on a has_many / habtm association when t...
NZKoz authored
18 ensure_owner_is_not_new
06075a9 risk danger olson Fix the has_and_belongs_to_many #create doesn't populate the join for ne...
technoweenie authored
19 if attributes.is_a?(Array)
20 attributes.collect { |attr| create(attr) }
21 else
22 record = build(attributes)
85fbb22 David Heinemeier Hansson Backed out of new_record? to new? transformation as it would screw up ex...
dhh authored
23 insert_record(record) unless @owner.new_record?
06075a9 risk danger olson Fix the has_and_belongs_to_many #create doesn't populate the join for ne...
technoweenie authored
24 record
25 end
26 end
7010ee3 Michael Koziarski Stop users from calling .create on a has_many / habtm association when t...
NZKoz authored
27
28 def create!(attributes = {})
29 # Can't use Base.create! because the foreign key may be a protected attribute.
30 ensure_owner_is_not_new
31 if attributes.is_a?(Array)
32 attributes.collect { |attr| create(attr) }
33 else
34 record = build(attributes)
35 insert_record(record, true) unless @owner.new_record?
36 record
37 end
38 end
06075a9 risk danger olson Fix the has_and_belongs_to_many #create doesn't populate the join for ne...
technoweenie authored
39
6bd672e David Heinemeier Hansson Added that Base#find takes an optional options hash, including :conditio...
dhh authored
40 def find_first
823554e David Heinemeier Hansson Added support for associating unsaved objects #402 [Tim Bates]
dhh authored
41 load_target.first
6bd672e David Heinemeier Hansson Added that Base#find takes an optional options hash, including :conditio...
dhh authored
42 end
800b899 Jeremy Kemper Remove deprecated push_with_attributes.
jeremy authored
43
6bd672e David Heinemeier Hansson Added that Base#find takes an optional options hash, including :conditio...
dhh authored
44 def find(*args)
edd68a5 David Heinemeier Hansson Refactored in use of extract_options! (closes #9079) [josh]
dhh authored
45 options = args.extract_options!
6bd672e David Heinemeier Hansson Added that Base#find takes an optional options hash, including :conditio...
dhh authored
46
47 # If using a custom finder_sql, scan the entire collection.
6abda69 David Heinemeier Hansson Added preliminary support for join models [DHH] Added preliminary suppor...
dhh authored
48 if @reflection.options[:finder_sql]
34f9d30 David Heinemeier Hansson Added support for calling constrained class methods on has_many and has_...
dhh authored
49 expects_array = args.first.kind_of?(Array)
50 ids = args.flatten.compact.uniq
51
6bd672e David Heinemeier Hansson Added that Base#find takes an optional options hash, including :conditio...
dhh authored
52 if ids.size == 1
4307d7e David Heinemeier Hansson Fixed various problems with has_and_belongs_to_many when using customer ...
dhh authored
53 id = ids.first.to_i
823554e David Heinemeier Hansson Added support for associating unsaved objects #402 [Tim Bates]
dhh authored
54 record = load_target.detect { |record| id == record.id }
4307d7e David Heinemeier Hansson Fixed various problems with has_and_belongs_to_many when using customer ...
dhh authored
55 expects_array ? [record] : record
6bd672e David Heinemeier Hansson Added that Base#find takes an optional options hash, including :conditio...
dhh authored
56 else
823554e David Heinemeier Hansson Added support for associating unsaved objects #402 [Tim Bates]
dhh authored
57 load_target.select { |record| ids.include?(record.id) }
6bd672e David Heinemeier Hansson Added that Base#find takes an optional options hash, including :conditio...
dhh authored
58 end
db045db David Heinemeier Hansson Initial
dhh authored
59 else
34f9d30 David Heinemeier Hansson Added support for calling constrained class methods on has_many and has_...
dhh authored
60 conditions = "#{@finder_sql}"
6abda69 David Heinemeier Hansson Added preliminary support for join models [DHH] Added preliminary suppor...
dhh authored
61
34f9d30 David Heinemeier Hansson Added support for calling constrained class methods on has_many and has_...
dhh authored
62 if sanitized_conditions = sanitize_sql(options[:conditions])
328ef3f Jeremy Kemper Parenthesize :conditions
jeremy authored
63 conditions << " AND (#{sanitized_conditions})"
34f9d30 David Heinemeier Hansson Added support for calling constrained class methods on has_many and has_...
dhh authored
64 end
6abda69 David Heinemeier Hansson Added preliminary support for join models [DHH] Added preliminary suppor...
dhh authored
65
34f9d30 David Heinemeier Hansson Added support for calling constrained class methods on has_many and has_...
dhh authored
66 options[:conditions] = conditions
53aa8da David Heinemeier Hansson Fixed that records returned from has_and_belongs_to_many associations wi...
dhh authored
67 options[:joins] = @join_sql
e3b49c0 David Heinemeier Hansson Fixed spelling errors (closes #9706) [tarmo/rmm5t]
dhh authored
68 options[:readonly] = finding_with_ambiguous_select?(options[:select])
34f9d30 David Heinemeier Hansson Added support for calling constrained class methods on has_many and has_...
dhh authored
69
6abda69 David Heinemeier Hansson Added preliminary support for join models [DHH] Added preliminary suppor...
dhh authored
70 if options[:order] && @reflection.options[:order]
71 options[:order] = "#{options[:order]}, #{@reflection.options[:order]}"
72 elsif @reflection.options[:order]
73 options[:order] = @reflection.options[:order]
db045db David Heinemeier Hansson Initial
dhh authored
74 end
34f9d30 David Heinemeier Hansson Added support for calling constrained class methods on has_many and has_...
dhh authored
75
e5d9ad3 David Heinemeier Hansson Added option inheritance for find calls on has_and_belongs_to_many and h...
dhh authored
76 merge_options_from_reflection!(options)
77
d4bf5e9 Michael Koziarski Make habtm respect the :select option. Closes #9207. [Aleksey Kondratenk...
NZKoz authored
78 options[:select] ||= '*'
79
34f9d30 David Heinemeier Hansson Added support for calling constrained class methods on has_many and has_...
dhh authored
80 # Pass through args exactly as we received them.
81 args << options
6abda69 David Heinemeier Hansson Added preliminary support for join models [DHH] Added preliminary suppor...
dhh authored
82 @reflection.klass.find(*args)
db045db David Heinemeier Hansson Initial
dhh authored
83 end
84 end
85
86 protected
87 def count_records
823554e David Heinemeier Hansson Added support for associating unsaved objects #402 [Tim Bates]
dhh authored
88 load_target.size
db045db David Heinemeier Hansson Initial
dhh authored
89 end
90
7010ee3 Michael Koziarski Stop users from calling .create on a has_many / habtm association when t...
NZKoz authored
91 def insert_record(record, force=true)
85fbb22 David Heinemeier Hansson Backed out of new_record? to new? transformation as it would screw up ex...
dhh authored
92 if record.new_record?
7010ee3 Michael Koziarski Stop users from calling .create on a has_many / habtm association when t...
NZKoz authored
93 if force
94 record.save!
95 else
96 return false unless record.save
97 end
a2f26b9 David Heinemeier Hansson Fixed that adding a record to a has_and_belongs_to collection would alwa...
dhh authored
98 end
b29c01e David Heinemeier Hansson Added that has_and_belongs_to_many associations with additional attribut...
dhh authored
99
6abda69 David Heinemeier Hansson Added preliminary support for join models [DHH] Added preliminary suppor...
dhh authored
100 if @reflection.options[:insert_sql]
101 @owner.connection.execute(interpolate_sql(@reflection.options[:insert_sql], record))
db045db David Heinemeier Hansson Initial
dhh authored
102 else
6abda69 David Heinemeier Hansson Added preliminary support for join models [DHH] Added preliminary suppor...
dhh authored
103 columns = @owner.connection.columns(@reflection.options[:join_table], "#{@reflection.options[:join_table]} Columns")
b29c01e David Heinemeier Hansson Added that has_and_belongs_to_many associations with additional attribut...
dhh authored
104
105 attributes = columns.inject({}) do |attributes, column|
106 case column.name
6abda69 David Heinemeier Hansson Added preliminary support for join models [DHH] Added preliminary suppor...
dhh authored
107 when @reflection.primary_key_name
b29c01e David Heinemeier Hansson Added that has_and_belongs_to_many associations with additional attribut...
dhh authored
108 attributes[column.name] = @owner.quoted_id
6abda69 David Heinemeier Hansson Added preliminary support for join models [DHH] Added preliminary suppor...
dhh authored
109 when @reflection.association_foreign_key
b29c01e David Heinemeier Hansson Added that has_and_belongs_to_many associations with additional attribut...
dhh authored
110 attributes[column.name] = record.quoted_id
111 else
83e2f6a Jamis Buck Allow unspecified join-table columns to use to their default values when...
jamis authored
112 if record.attributes.has_key?(column.name)
85fbb22 David Heinemeier Hansson Backed out of new_record? to new? transformation as it would screw up ex...
dhh authored
113 value = @owner.send(:quote_value, record[column.name], column)
83e2f6a Jamis Buck Allow unspecified join-table columns to use to their default values when...
jamis authored
114 attributes[column.name] = value unless value.nil?
115 end
b29c01e David Heinemeier Hansson Added that has_and_belongs_to_many associations with additional attribut...
dhh authored
116 end
117 attributes
118 end
119
120 sql =
6abda69 David Heinemeier Hansson Added preliminary support for join models [DHH] Added preliminary suppor...
dhh authored
121 "INSERT INTO #{@reflection.options[:join_table]} (#{@owner.send(:quoted_column_names, attributes).join(', ')}) " +
9870396 David Heinemeier Hansson Fixed incompatibility in DB2 adapter with the new limit/offset approach ...
dhh authored
122 "VALUES (#{attributes.values.join(', ')})"
b29c01e David Heinemeier Hansson Added that has_and_belongs_to_many associations with additional attribut...
dhh authored
123
db045db David Heinemeier Hansson Initial
dhh authored
124 @owner.connection.execute(sql)
125 end
800b899 Jeremy Kemper Remove deprecated push_with_attributes.
jeremy authored
126
b29c01e David Heinemeier Hansson Added that has_and_belongs_to_many associations with additional attribut...
dhh authored
127 return true
db045db David Heinemeier Hansson Initial
dhh authored
128 end
800b899 Jeremy Kemper Remove deprecated push_with_attributes.
jeremy authored
129
db045db David Heinemeier Hansson Initial
dhh authored
130 def delete_records(records)
6abda69 David Heinemeier Hansson Added preliminary support for join models [DHH] Added preliminary suppor...
dhh authored
131 if sql = @reflection.options[:delete_sql]
190e046 David Heinemeier Hansson Fixed that :delete_sql in has_and_belongs_to_many associations couldn't ...
dhh authored
132 records.each { |record| @owner.connection.execute(interpolate_sql(sql, record)) }
db045db David Heinemeier Hansson Initial
dhh authored
133 else
134 ids = quoted_record_ids(records)
6abda69 David Heinemeier Hansson Added preliminary support for join models [DHH] Added preliminary suppor...
dhh authored
135 sql = "DELETE FROM #{@reflection.options[:join_table]} WHERE #{@reflection.primary_key_name} = #{@owner.quoted_id} AND #{@reflection.association_foreign_key} IN (#{ids})"
db045db David Heinemeier Hansson Initial
dhh authored
136 @owner.connection.execute(sql)
137 end
138 end
800b899 Jeremy Kemper Remove deprecated push_with_attributes.
jeremy authored
139
823554e David Heinemeier Hansson Added support for associating unsaved objects #402 [Tim Bates]
dhh authored
140 def construct_sql
6abda69 David Heinemeier Hansson Added preliminary support for join models [DHH] Added preliminary suppor...
dhh authored
141 interpolate_sql_options!(@reflection.options, :finder_sql)
34f9d30 David Heinemeier Hansson Added support for calling constrained class methods on has_many and has_...
dhh authored
142
6abda69 David Heinemeier Hansson Added preliminary support for join models [DHH] Added preliminary suppor...
dhh authored
143 if @reflection.options[:finder_sql]
144 @finder_sql = @reflection.options[:finder_sql]
71bdf13 David Heinemeier Hansson Removed the default order by id on has_and_belongs_to_many queries as it...
dhh authored
145 else
6abda69 David Heinemeier Hansson Added preliminary support for join models [DHH] Added preliminary suppor...
dhh authored
146 @finder_sql = "#{@reflection.options[:join_table]}.#{@reflection.primary_key_name} = #{@owner.quoted_id} "
a3502c4 risk danger olson Use association's :conditions when eager loading. [jeremyevans0@gmail.co...
technoweenie authored
147 @finder_sql << " AND (#{conditions})" if conditions
71bdf13 David Heinemeier Hansson Removed the default order by id on has_and_belongs_to_many queries as it...
dhh authored
148 end
d21ba5a Jeremy Kemper has_and_belongs_to_many: use JOIN instead of LEFT JOIN. References #293...
jeremy authored
149
56af14d risk danger olson Changed has_and_belongs_to_many join to INNER JOIN for Mysql 3.23.x. Cl...
technoweenie authored
150 @join_sql = "INNER JOIN #{@reflection.options[:join_table]} ON #{@reflection.klass.table_name}.#{@reflection.klass.primary_key} = #{@reflection.options[:join_table]}.#{@reflection.association_foreign_key}"
823554e David Heinemeier Hansson Added support for associating unsaved objects #402 [Tim Bates]
dhh authored
151 end
53aa8da David Heinemeier Hansson Fixed that records returned from has_and_belongs_to_many associations wi...
dhh authored
152
02adc49 Jeremy Kemper Simplify association proxy implementation by factoring construct_scope o...
jeremy authored
153 def construct_scope
154 { :find => { :conditions => @finder_sql, :joins => @join_sql, :readonly => false } }
155 end
156
e3b49c0 David Heinemeier Hansson Fixed spelling errors (closes #9706) [tarmo/rmm5t]
dhh authored
157 # Join tables with additional columns on top of the two foreign keys must be considered ambiguous unless a select
18a3333 Michael Koziarski Formatting, grammar and spelling fixes for the associations documentatio...
NZKoz authored
158 # clause has been explicitly defined. Otherwise you can get broken records back, if, for example, the join column also has
159 # an id column. This will then overwrite the id column of the records coming back.
e3b49c0 David Heinemeier Hansson Fixed spelling errors (closes #9706) [tarmo/rmm5t]
dhh authored
160 def finding_with_ambiguous_select?(select_clause)
53aa8da David Heinemeier Hansson Fixed that records returned from has_and_belongs_to_many associations wi...
dhh authored
161 !select_clause && @owner.connection.columns(@reflection.options[:join_table], "Join Table Columns").size != 2
162 end
823554e David Heinemeier Hansson Added support for associating unsaved objects #402 [Tim Bates]
dhh authored
163 end
db045db David Heinemeier Hansson Initial
dhh authored
164 end
68d1056 David Heinemeier Hansson Fixed that has_and_belongs_to_many would generate bad sql when naming co...
dhh authored
165 end
Something went wrong with that request. Please try again.