Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 135 lines (116 sloc) 5.093 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)
b82fab2 @jonleighton Refactoring: replace the mix of variables like @finder_sql, @counter_…
jonleighton authored
27 options[:joins] = Arel::SqlLiteral.new(@scope[:find][:joins])
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])
e1e7122 @tenderlove mark SQL literals as SQL literals
tenderlove authored
29 options[:select] ||= (@reflection.options[:select] || Arel::SqlLiteral.new('*'))
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)
e444439 @josevalim Partialy revert f1c13b0dd7b22b5f6289ca1a09f1d7a8c7c8584b
josevalim 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
1563351 @tenderlove removing some calls to insert on arel
tenderlove authored
52 attributes = columns.map do |column|
f3e4229 @josevalim Ensure all join table attributes will be in the same timestamp.
josevalim authored
53 name = column.name
ea35ccf @miloops Perf: refactor method.
miloops authored
54 value = 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
ea35ccf @miloops Perf: refactor method.
miloops authored
56 @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
ea35ccf @miloops Perf: refactor method.
miloops authored
58 record.id
f3e4229 @josevalim Ensure all join table attributes will be in the same timestamp.
josevalim authored
59 when *timestamps
ea35ccf @miloops Perf: refactor method.
miloops authored
60 timezone
b29c01e @dhh Added that has_and_belongs_to_many associations with additional attri…
dhh authored
61 else
ea35ccf @miloops Perf: refactor method.
miloops authored
62 @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
63 end
ea35ccf @miloops Perf: refactor method.
miloops authored
64 [relation[name], value] unless value.nil?
1563351 @tenderlove removing some calls to insert on arel
tenderlove authored
65 end
b29c01e @dhh Added that has_and_belongs_to_many associations with additional attri…
dhh authored
66
1563351 @tenderlove removing some calls to insert on arel
tenderlove authored
67 stmt = relation.compile_insert Hash[attributes]
68 @owner.connection.insert stmt.to_sql
db045db @dhh Initial
dhh authored
69 end
800b899 @jeremy Remove deprecated push_with_attributes.
jeremy authored
70
a3bd62e @miloops Remove explicit return.
miloops authored
71 true
db045db @dhh Initial
dhh authored
72 end
800b899 @jeremy Remove deprecated push_with_attributes.
jeremy authored
73
db045db @dhh Initial
dhh authored
74 def delete_records(records)
6abda69 @dhh Added preliminary support for join models [DHH] Added preliminary sup…
dhh authored
75 if sql = @reflection.options[:delete_sql]
4979448 @technoweenie Ensure that modifying has_and_belongs_to_many actions clear the query…
technoweenie authored
76 records.each { |record| @owner.connection.delete(interpolate_sql(sql, record)) }
db045db @dhh Initial
dhh authored
77 else
5971842 @lifo Use Arel::Table instead of ActiveRecord::Relation from HABTM and has_…
lifo authored
78 relation = Arel::Table.new(@reflection.options[:join_table])
95274b2 @lifo Rename Model.conditions and relation.conditions to .where
lifo authored
79 relation.where(relation[@reflection.primary_key_name].eq(@owner.id).
79ef26c @tenderlove do not pass nil values to arel
tenderlove authored
80 and(relation[@reflection.association_foreign_key].in(records.map { |x| x.id }.compact))
5971842 @lifo Use Arel::Table instead of ActiveRecord::Relation from HABTM and has_…
lifo authored
81 ).delete
db045db @dhh Initial
dhh authored
82 end
83 end
a3bd62e @miloops Remove explicit return.
miloops authored
84
b82fab2 @jonleighton Refactoring: replace the mix of variables like @finder_sql, @counter_…
jonleighton authored
85 def construct_joins
86 "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}"
87 end
800b899 @jeremy Remove deprecated push_with_attributes.
jeremy authored
88
b82fab2 @jonleighton Refactoring: replace the mix of variables like @finder_sql, @counter_…
jonleighton authored
89 def construct_conditions
90 sql = "#{@owner.connection.quote_table_name @reflection.options[:join_table]}.#{@reflection.primary_key_name} = #{owner_quoted_id} "
91 sql << " AND (#{conditions})" if conditions
92 sql
823554e @dhh Added support for associating unsaved objects #402 [Tim Bates]
dhh authored
93 end
53aa8da @dhh Fixed that records returned from has_and_belongs_to_many associations…
dhh authored
94
b82fab2 @jonleighton Refactoring: replace the mix of variables like @finder_sql, @counter_…
jonleighton authored
95 def construct_find_scope
96 {
97 :conditions => construct_conditions,
98 :joins => construct_joins,
99 :readonly => false,
100 :order => @reflection.options[:order],
101 :include => @reflection.options[:include],
102 :limit => @reflection.options[:limit]
103 }
02adc49 @jeremy Simplify association proxy implementation by factoring construct_scop…
jeremy authored
104 end
105
b451de0 @spastorino Deletes trailing whitespaces (over text files only find * -type f -ex…
spastorino authored
106 # Join tables with additional columns on top of the two foreign keys must be considered
107 # ambiguous unless a select clause has been explicitly defined. Otherwise you can get
108 # 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
109 # then overwrite the id column of the records coming back.
e3b49c0 @dhh Fixed spelling errors (closes #9706) [tarmo/rmm5t]
dhh authored
110 def finding_with_ambiguous_select?(select_clause)
3ee4e00 @lukeludwig Cache columns for has_and_belongs_to_many associations
lukeludwig authored
111 !select_clause && columns.size != 2
53aa8da @dhh Fixed that records returned from has_and_belongs_to_many associations…
dhh authored
112 end
a72c1ec @jeremy Refactor association create and build so before & after callbacks beh…
jeremy authored
113
114 private
36b8073 @NZKoz Make HABTM#create behave the same as << with after_add callbacks. Cl…
NZKoz authored
115 def create_record(attributes, &block)
a72c1ec @jeremy Refactor association create and build so before & after callbacks beh…
jeremy authored
116 # Can't use Base.create because the foreign key may be a protected attribute.
e444439 @josevalim Partialy revert f1c13b0dd7b22b5f6289ca1a09f1d7a8c7c8584b
josevalim authored
117 ensure_owner_is_persisted!
a72c1ec @jeremy Refactor association create and build so before & after callbacks beh…
jeremy authored
118 if attributes.is_a?(Array)
119 attributes.collect { |attr| create(attr) }
120 else
36b8073 @NZKoz Make HABTM#create behave the same as << with after_add callbacks. Cl…
NZKoz authored
121 build_record(attributes, &block)
a72c1ec @jeremy Refactor association create and build so before & after callbacks beh…
jeremy authored
122 end
123 end
f3e4229 @josevalim Ensure all join table attributes will be in the same timestamp.
josevalim authored
124
125 def record_timestamp_columns(record)
126 if record.record_timestamps
a7eb8d9 @sikachu Removing most of the symbol to proc usage in Active Record
sikachu authored
127 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
128 else
129 []
130 end
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.