Skip to content

HTTPS clone URL

Subversion checkout URL

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