Module: ActiveRecord::PostgreSQLExtensions::ForeignKeyAssociations::ClassMethods
- Defined in:
- lib/active_record/postgresql_extensions/foreign_key_associations.rb
Class Method Summary collapse
Instance Method Summary collapse
-
#allocate_with_foreign_keys ⇒ Object
:nodoc:.
-
#dont_load_foreign_key_associations! ⇒ Object
Allows you to selectively disable foreign key association loading when the ActiveRecord setting enable_foreign_key_associations is enabled.
-
#foreign_keys ⇒ Object
Returns an Array of foreign keys in this model.
-
#load_foreign_key_associations ⇒ Object
Creates foreign key associations for the model.
-
#load_foreign_key_associations? ⇒ Boolean
Should we load a model’s foreign key associations? Maybe we should, and maybe we shouldn’t.
-
#new_with_foreign_keys(*args) ⇒ Object
:nodoc:.
-
#referenced_foreign_keys ⇒ Object
Returns an Array of foreign keys referencing this model.
-
#reflections_with_foreign_keys ⇒ Object
:nodoc:.
Class Method Details
.extended(base) ⇒ Object
128 129 130 131 132 133 134 |
# File 'lib/active_record/postgresql_extensions/foreign_key_associations.rb', line 128 def self.extended(base) class << base alias_method_chain :allocate, :foreign_keys alias_method_chain :new, :foreign_keys alias_method_chain :reflections, :foreign_keys end end |
Instance Method Details
#allocate_with_foreign_keys ⇒ Object
:nodoc:
136 137 138 139 |
# File 'lib/active_record/postgresql_extensions/foreign_key_associations.rb', line 136 def allocate_with_foreign_keys #:nodoc: load_foreign_key_associations if load_foreign_key_associations? && !@foreign_key_associations_loaded allocate_without_foreign_keys end |
#dont_load_foreign_key_associations! ⇒ Object
Allows you to selectively disable foreign key association loading when the ActiveRecord setting enable_foreign_key_associations is enabled. This works on a per-model basis, and prevents any foreign key associations from being created on this model. This applies to both foreign keys that reference this model as well as foreign keys within the model itself.
171 172 173 |
# File 'lib/active_record/postgresql_extensions/foreign_key_associations.rb', line 171 def dont_load_foreign_key_associations! @load_foreign_key_associations = false end |
#foreign_keys ⇒ Object
Returns an Array of foreign keys in this model. See ActiveRecord::Base#foreign_keys for details.
161 162 163 |
# File 'lib/active_record/postgresql_extensions/foreign_key_associations.rb', line 161 def foreign_keys @foreign_keys ||= connection.foreign_keys(table_name, "#{name} Foreign Keys") end |
#load_foreign_key_associations ⇒ Object
Creates foreign key associations for the model. This is essentially a three-step process:
-
Find any tables that reference this model via foreign keys and create the associations accordingly.
-
Find any foreign keys in this model and create the associations accordingly. This process creates both belongs_to associations on this model to the referenced models as well as has_many/has_one associations on the referenced models themselves. To determine whether the association is a has_many or a has_one, we take a look at UNIQUE indexes created on the table column. In cases where the index is UNIQUE, we create a has_one association; in all others, we create a has_many association.
-
Look at the model itself and try to determine whether or not we have a “has_many :through” association. We make this determination by looking to see if there are two foreign keys with the following conditions:
-
the model has an index with exactly two columns in it and the index itself is UNIQUE;
-
we’ve already created a belongs_to association with each column and the column names match the columns in the UNIQUE index; and
-
the model name is either “FirstModelSecondModel” or “SecondModelFirstModel”.
If these criteria match, then the “has_many :through” associations are created on both of the referenced models.
-
In all cases, we respect any dont_load_foreign_key_associations! settings on individual models as well as take into account existing associations with the same names as the ones we’re going to try to create. In other words, if you already have an association called :listings on a model and we find a foreign key that matches, we won’t blow away your existing association and instead just continue along merrily.
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 |
# File 'lib/active_record/postgresql_extensions/foreign_key_associations.rb', line 210 def load_foreign_key_associations return if @foreign_key_associations_loaded @foreign_key_associations_loaded = true indexes = connection.indexes(table_name, "#{name} Indexes") # This does the associations for the tables that reference # columns in this table. referenced_foreign_keys.each do |fk| begin referencing_class = compute_type(fk[:table].classify) referencing_class.load_foreign_key_associations if referencing_class.load_foreign_key_associations? rescue NameError # Do nothing. We won't bother creating associations # if the model class itself doesn't exist. end end # This does the foreign key associations for this model. foreign_keys.each do |fk| belongs_to_association_id = fk[:table].singularize.to_sym begin references_class_name = fk[:table].classify references_class = compute_type(references_class_name) unless method_defined?(belongs_to_association_id) belongs_to( belongs_to_association_id, :class_name => references_class_name, :foreign_key => fk[:column] ) end # If we have a unique index for this column, we'll # create a has_one association; otherwise, it's a # has_many. if indexes.detect { |i| i.columns.length == 1 && i.unique && i.columns.include?(fk[:column]) } has_association_id = self.name.demodulize.underscore.to_sym unless references_class.method_defined?(has_association_id) references_class.has_one( has_association_id, { :class_name => name, :foreign_key => fk[:column] } ) end else has_association_id = self.name.demodulize.underscore.pluralize.to_sym unless references_class.method_defined?(has_association_id) references_class.has_many( has_association_id, { :class_name => name, :foreign_key => fk[:column] } ) end end rescue NameError # Do nothing. NOTHING! We don't want to create # associations on non-existent classes. end end # If we have an index that contains exactly two columns and # it's a UNIQUE index, then we might have a # "has_many :through" association, so let's look for it now. if through = indexes.detect { |i| i.columns.length == 2 && i.unique } catch :not_a_has_many_through do hmt_associations = [] # This will loop through the columns in the UNIQUE # index and see if they're both foreign keys # referencing other tables. through.columns.each do |c| if foreign_keys.detect { |fk| fk[1] == c }.blank? throw(:not_a_has_many_through) end # Check that both columns have belongs_to # associations. unless hmt_association = reflections.detect { |r, v| v.macro == :belongs_to && v.primary_key_name == c } throw(:not_a_has_many_through) end hmt_associations << hmt_association end hmt_first = hmt_associations.first hmt_second = hmt_associations.last hmt_first_association_id = hmt_second.first.to_s.pluralize.to_sym hmt_second_association_id = hmt_first.first.to_s.pluralize.to_sym hmt_first_class = hmt_first.last.name.constantize hmt_second_class = hmt_second.last.name.constantize # Check to see if this model is named # "FirstModelSecondModel" or "SecondModelFirstModel". if strict_foreign_key_has_many_throughs unless [ "#{hmt_first_class}#{hmt_second_class}", "#{hmt_second_class}#{hmt_first_class}" ].include?(self.name) throw(:not_a_has_many_through) end end # If we haven't thrown up, we can create the # associations, assuming they don't already exist and # we're allowed to. through_association_id = self.name.demodulize.underscore.pluralize.to_sym if hmt_first_class.load_foreign_key_associations? unless hmt_first_class.method_defined?(hmt_first_association_id) hmt_first_class.has_many( hmt_first_association_id, :through => through_association_id ) end end if hmt_second_class.load_foreign_key_associations? unless hmt_second_class.method_defined?(hmt_second_association_id) hmt_second_class.has_many( hmt_second_association_id, :through => through_association_id ) end end end end end |
#load_foreign_key_associations? ⇒ Boolean
Should we load a model’s foreign key associations? Maybe we should, and maybe we shouldn’t.
349 350 351 352 353 354 |
# File 'lib/active_record/postgresql_extensions/foreign_key_associations.rb', line 349 def load_foreign_key_associations? ActiveRecord::Base.enable_foreign_key_associations && !abstract_class? && ( @load_foreign_key_associations.nil? || @load_foreign_key_associations ) end |
#new_with_foreign_keys(*args) ⇒ Object
:nodoc:
141 142 143 144 145 146 |
# File 'lib/active_record/postgresql_extensions/foreign_key_associations.rb', line 141 def new_with_foreign_keys(*args) #:nodoc: load_foreign_key_associations if load_foreign_key_associations? && !@foreign_key_associations_loaded new_without_foreign_keys(*args) { |*block_args| yield(*block_args) if block_given? } end |
#referenced_foreign_keys ⇒ Object
Returns an Array of foreign keys referencing this model. See ActiveRecord::Base#referenced_foreign_keys for details.
155 156 157 |
# File 'lib/active_record/postgresql_extensions/foreign_key_associations.rb', line 155 def referenced_foreign_keys @referenced_foreign_keys ||= connection.referenced_foreign_keys(table_name, "#{name} Referenced Foreign Keys") end |
#reflections_with_foreign_keys ⇒ Object
:nodoc:
148 149 150 151 |
# File 'lib/active_record/postgresql_extensions/foreign_key_associations.rb', line 148 def reflections_with_foreign_keys #:nodoc: load_foreign_key_associations if load_foreign_key_associations? && !@foreign_key_associations_loaded reflections_without_foreign_keys end |