Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 136 lines (115 sloc) 5.379 kB
db045db @dhh Initial
dhh authored
1 module ActiveRecord
2 module Associations
3 class HasAndBelongsToManyAssociation < AssociationCollection #:nodoc:
3b6a9a0 @jeremy Revert "Assert primary key does not exist in habtm when the associati…
jeremy authored
4 def initialize(owner, reflection)
5 super
6 @primary_key_list = {}
7 end
8
06075a9 @technoweenie Fix the has_and_belongs_to_many #create doesn't populate the join for…
technoweenie authored
9 def create(attributes = {})
a72c1ec @jeremy Refactor association create and build so before & after callbacks beh…
jeremy authored
10 create_record(attributes) { |record| insert_record(record) }
06075a9 @technoweenie Fix the has_and_belongs_to_many #create doesn't populate the join for…
technoweenie authored
11 end
4979448 @technoweenie Ensure that modifying has_and_belongs_to_many actions clear the query…
technoweenie authored
12
7010ee3 @NZKoz Stop users from calling .create on a has_many / habtm association whe…
NZKoz authored
13 def create!(attributes = {})
a72c1ec @jeremy Refactor association create and build so before & after callbacks beh…
jeremy authored
14 create_record(attributes) { |record| insert_record(record, true) }
7010ee3 @NZKoz Stop users from calling .create on a has_many / habtm association whe…
NZKoz authored
15 end
06075a9 @technoweenie Fix the has_and_belongs_to_many #create doesn't populate the join for…
technoweenie authored
16
3ee4e00 @lukeludwig Cache columns for has_and_belongs_to_many associations
lukeludwig authored
17 def columns
18 @reflection.columns(@reflection.options[:join_table], "#{@reflection.options[:join_table]} Columns")
19 end
20
21 def reset_column_information
22 @reflection.reset_column_information
23 end
24
3b6a9a0 @jeremy Revert "Assert primary key does not exist in habtm when the associati…
jeremy authored
25 def has_primary_key?
26 return @has_primary_key unless @has_primary_key.nil?
27 @has_primary_key = (ActiveRecord::Base.connection.supports_primary_key? &&
28 ActiveRecord::Base.connection.primary_key(@reflection.options[:join_table]))
29 end
30
9bc75fd @lifo Remove duplicate code from associations. [Pratik]
lifo authored
31 protected
32 def construct_find_options!(options)
53aa8da @dhh Fixed that records returned from has_and_belongs_to_many associations…
dhh authored
33 options[:joins] = @join_sql
2e47db2 @dhh Fixed that habtm associations should be able to set :select as part o…
dhh authored
34 options[:readonly] = finding_with_ambiguous_select?(options[:select] || @reflection.options[:select])
9bc75fd @lifo Remove duplicate code from associations. [Pratik]
lifo authored
35 options[:select] ||= (@reflection.options[:select] || '*')
db045db @dhh Initial
dhh authored
36 end
9bc75fd @lifo Remove duplicate code from associations. [Pratik]
lifo authored
37
db045db @dhh Initial
dhh authored
38 def count_records
823554e @dhh Added support for associating unsaved objects #402 [Tim Bates]
dhh authored
39 load_target.size
db045db @dhh Initial
dhh authored
40 end
41
5cda000 @dhh Fixed that autosave should validate associations even if master is in…
dhh authored
42 def insert_record(record, force = true, validate = true)
3b6a9a0 @jeremy Revert "Assert primary key does not exist in habtm when the associati…
jeremy authored
43 if has_primary_key?
44 raise ActiveRecord::ConfigurationError,
45 "Primary key is not allowed in a has_and_belongs_to_many join table (#{@reflection.options[:join_table]})."
46 end
47
85fbb22 @dhh Backed out of new_record? to new? transformation as it would screw up…
dhh authored
48 if record.new_record?
7010ee3 @NZKoz Stop users from calling .create on a has_many / habtm association whe…
NZKoz authored
49 if force
50 record.save!
51 else
5cda000 @dhh Fixed that autosave should validate associations even if master is in…
dhh authored
52 return false unless record.save(validate)
7010ee3 @NZKoz Stop users from calling .create on a has_many / habtm association whe…
NZKoz authored
53 end
a2f26b9 @dhh Fixed that adding a record to a has_and_belongs_to collection would a…
dhh authored
54 end
b29c01e @dhh Added that has_and_belongs_to_many associations with additional attri…
dhh authored
55
6abda69 @dhh Added preliminary support for join models [DHH] Added preliminary sup…
dhh authored
56 if @reflection.options[:insert_sql]
4979448 @technoweenie Ensure that modifying has_and_belongs_to_many actions clear the query…
technoweenie authored
57 @owner.connection.insert(interpolate_sql(@reflection.options[:insert_sql], record))
db045db @dhh Initial
dhh authored
58 else
8b5f4e4 @jeremy Ruby 1.9 compat: fix warnings, shadowed block vars, and unitialized i…
jeremy authored
59 attributes = columns.inject({}) do |attrs, column|
6c1c16b @ddollar Fixes a subtle bug when using symbols for key definitions in habtm as…
ddollar authored
60 case column.name.to_s
61 when @reflection.primary_key_name.to_s
0b12da4 @indirect Extract owner_quoted_id so it can be overridden. [#292 state:committed]
indirect authored
62 attrs[column.name] = owner_quoted_id
6c1c16b @ddollar Fixes a subtle bug when using symbols for key definitions in habtm as…
ddollar authored
63 when @reflection.association_foreign_key.to_s
8b5f4e4 @jeremy Ruby 1.9 compat: fix warnings, shadowed block vars, and unitialized i…
jeremy authored
64 attrs[column.name] = record.quoted_id
b29c01e @dhh Added that has_and_belongs_to_many associations with additional attri…
dhh authored
65 else
8b5f4e4 @jeremy Ruby 1.9 compat: fix warnings, shadowed block vars, and unitialized i…
jeremy authored
66 if record.has_attribute?(column.name)
85fbb22 @dhh Backed out of new_record? to new? transformation as it would screw up…
dhh authored
67 value = @owner.send(:quote_value, record[column.name], column)
8b5f4e4 @jeremy Ruby 1.9 compat: fix warnings, shadowed block vars, and unitialized i…
jeremy authored
68 attrs[column.name] = value unless value.nil?
83e2f6a @jamis Allow unspecified join-table columns to use to their default values w…
jamis authored
69 end
b29c01e @dhh Added that has_and_belongs_to_many associations with additional attri…
dhh authored
70 end
8b5f4e4 @jeremy Ruby 1.9 compat: fix warnings, shadowed block vars, and unitialized i…
jeremy authored
71 attrs
b29c01e @dhh Added that has_and_belongs_to_many associations with additional attri…
dhh authored
72 end
73
74 sql =
ebe3a0d @jeremy More thoroughly quote table names. Exposes some issues with sqlite2 a…
jeremy authored
75 "INSERT INTO #{@owner.connection.quote_table_name @reflection.options[:join_table]} (#{@owner.send(:quoted_column_names, attributes).join(', ')}) " +
9870396 @dhh Fixed incompatibility in DB2 adapter with the new limit/offset approa…
dhh authored
76 "VALUES (#{attributes.values.join(', ')})"
b29c01e @dhh Added that has_and_belongs_to_many associations with additional attri…
dhh authored
77
4979448 @technoweenie Ensure that modifying has_and_belongs_to_many actions clear the query…
technoweenie authored
78 @owner.connection.insert(sql)
db045db @dhh Initial
dhh authored
79 end
800b899 @jeremy Remove deprecated push_with_attributes.
jeremy authored
80
b29c01e @dhh Added that has_and_belongs_to_many associations with additional attri…
dhh authored
81 return true
db045db @dhh Initial
dhh authored
82 end
800b899 @jeremy Remove deprecated push_with_attributes.
jeremy authored
83
db045db @dhh Initial
dhh authored
84 def delete_records(records)
6abda69 @dhh Added preliminary support for join models [DHH] Added preliminary sup…
dhh authored
85 if sql = @reflection.options[:delete_sql]
4979448 @technoweenie Ensure that modifying has_and_belongs_to_many actions clear the query…
technoweenie authored
86 records.each { |record| @owner.connection.delete(interpolate_sql(sql, record)) }
db045db @dhh Initial
dhh authored
87 else
88 ids = quoted_record_ids(records)
0b12da4 @indirect Extract owner_quoted_id so it can be overridden. [#292 state:committed]
indirect authored
89 sql = "DELETE FROM #{@owner.connection.quote_table_name @reflection.options[:join_table]} WHERE #{@reflection.primary_key_name} = #{owner_quoted_id} AND #{@reflection.association_foreign_key} IN (#{ids})"
4979448 @technoweenie Ensure that modifying has_and_belongs_to_many actions clear the query…
technoweenie authored
90 @owner.connection.delete(sql)
db045db @dhh Initial
dhh authored
91 end
92 end
800b899 @jeremy Remove deprecated push_with_attributes.
jeremy authored
93
823554e @dhh Added support for associating unsaved objects #402 [Tim Bates]
dhh authored
94 def construct_sql
6abda69 @dhh Added preliminary support for join models [DHH] Added preliminary sup…
dhh authored
95 if @reflection.options[:finder_sql]
8cfdcdb @zerowidth Updated has_and_belongs_to_many association to fix :finder_sql interp…
zerowidth authored
96 @finder_sql = interpolate_sql(@reflection.options[:finder_sql])
71bdf13 @dhh Removed the default order by id on has_and_belongs_to_many queries as…
dhh authored
97 else
0b12da4 @indirect Extract owner_quoted_id so it can be overridden. [#292 state:committed]
indirect authored
98 @finder_sql = "#{@owner.connection.quote_table_name @reflection.options[:join_table]}.#{@reflection.primary_key_name} = #{owner_quoted_id} "
a3502c4 @technoweenie Use association's :conditions when eager loading. [jeremyevans0@gmail…
technoweenie authored
99 @finder_sql << " AND (#{conditions})" if conditions
71bdf13 @dhh Removed the default order by id on has_and_belongs_to_many queries as…
dhh authored
100 end
d21ba5a @jeremy has_and_belongs_to_many: use JOIN instead of LEFT JOIN. References #…
jeremy authored
101
ebe3a0d @jeremy More thoroughly quote table names. Exposes some issues with sqlite2 a…
jeremy authored
102 @join_sql = "INNER JOIN #{@owner.connection.quote_table_name @reflection.options[:join_table]} ON #{@reflection.quoted_table_name}.#{@reflection.klass.primary_key} = #{@owner.connection.quote_table_name @reflection.options[:join_table]}.#{@reflection.association_foreign_key}"
44af2ef @ernie Refactored AssociationCollection#count for uniformity and Ruby 1.8.7 …
ernie authored
103
45e6f19 @lifo Revert "Revert "Generate proper :counter_sql from :finder_sql when th…
lifo authored
104 construct_counter_sql
823554e @dhh Added support for associating unsaved objects #402 [Tim Bates]
dhh authored
105 end
53aa8da @dhh Fixed that records returned from has_and_belongs_to_many associations…
dhh authored
106
02adc49 @jeremy Simplify association proxy implementation by factoring construct_scop…
jeremy authored
107 def construct_scope
440f289 @jeremy Dynamic finders on association collections respect association :limit…
jeremy authored
108 { :find => { :conditions => @finder_sql,
109 :joins => @join_sql,
110 :readonly => false,
111 :order => @reflection.options[:order],
e94e53f @bkeepers fix eager loading with dynamic finders
bkeepers authored
112 :include => @reflection.options[:include],
440f289 @jeremy Dynamic finders on association collections respect association :limit…
jeremy authored
113 :limit => @reflection.options[:limit] } }
02adc49 @jeremy Simplify association proxy implementation by factoring construct_scop…
jeremy authored
114 end
115
e3b49c0 @dhh Fixed spelling errors (closes #9706) [tarmo/rmm5t]
dhh authored
116 # Join tables with additional columns on top of the two foreign keys must be considered ambiguous unless a select
18a3333 @NZKoz Formatting, grammar and spelling fixes for the associations documenta…
NZKoz authored
117 # clause has been explicitly defined. Otherwise you can get broken records back, if, for example, the join column also has
118 # an id column. This will then overwrite the id column of the records coming back.
e3b49c0 @dhh Fixed spelling errors (closes #9706) [tarmo/rmm5t]
dhh authored
119 def finding_with_ambiguous_select?(select_clause)
3ee4e00 @lukeludwig Cache columns for has_and_belongs_to_many associations
lukeludwig authored
120 !select_clause && columns.size != 2
53aa8da @dhh Fixed that records returned from has_and_belongs_to_many associations…
dhh authored
121 end
a72c1ec @jeremy Refactor association create and build so before & after callbacks beh…
jeremy authored
122
123 private
36b8073 @NZKoz Make HABTM#create behave the same as << with after_add callbacks. Cl…
NZKoz authored
124 def create_record(attributes, &block)
a72c1ec @jeremy Refactor association create and build so before & after callbacks beh…
jeremy authored
125 # Can't use Base.create because the foreign key may be a protected attribute.
126 ensure_owner_is_not_new
127 if attributes.is_a?(Array)
128 attributes.collect { |attr| create(attr) }
129 else
36b8073 @NZKoz Make HABTM#create behave the same as << with after_add callbacks. Cl…
NZKoz authored
130 build_record(attributes, &block)
a72c1ec @jeremy Refactor association create and build so before & after callbacks beh…
jeremy authored
131 end
132 end
823554e @dhh Added support for associating unsaved objects #402 [Tim Bates]
dhh authored
133 end
db045db @dhh Initial
dhh authored
134 end
68d1056 @dhh Fixed that has_and_belongs_to_many would generate bad sql when naming…
dhh authored
135 end
Something went wrong with that request. Please try again.