| In: |
lib/active_record/associations.rb
|
Associations is a set of macro-like class methods for tying objects together through foreign keys. Each macro adds a range of methods to the class which are specialized according to the collection or association symbol and the options hash. It works much the same was as Ruby’s own attr* methods.
Simple example:
class Project < ActiveRecord::Base
belongs_to :portofolio
has_one :project_manager
has_many :milestones
end
The project class now has the following methods:
Adds methods for retrival and query of collections of associated objects.
Example: A Firm class declares has_many :clients, which will add:
The declaration can also include an options hash to specialize the generated methods.
Options are:
# File lib/active_record/associations.rb, line 41
41: def has_many(collection_id, options = {})
42: validate_options([ :foreign_key, :class_name, :constraint, :order, :finder_sql ], options.keys)
43:
44: collection_name = collection_id.id2name
45: collection_class_name = options[:class_name] || class_name(collection_id.id2name)
46: class_primary_key_name = options[:foreign_key] || name.downcase + "_id"
47:
48: if options[:finder_sql]
49: collection_finder = "#{collection_class_name}.find_by_sql(\"#{options[:finder_sql]}\")"
50:
51: counter_sql = options[:finder_sql].gsub(/SELECT (.*) FROM/, "SELECT COUNT(*) FROM")
52: collection_counter = "#{collection_class_name}.count_by_sql(\"#{counter_sql}\")"
53: else
54: collection_finder = "\#{collection_class_name}.find_all(\n\"\#{class_primary_key_name} = \\\#{id}\#{options[:constraint] ? \" AND \" + options[:constraint] : \"\"}\",\n\#{options[:order] ? \"\\\"\" + options[:order] + \"\\\"\" : \"nil\" }\n)\n"
55:
56: collection_counter = "#{collection_class_name}.count(\"#{class_primary_key_name} = \#{id}\")"
57: end
58:
59:
60: module_eval "\# Ex: clients\ndef \#{collection_name}\nif @\#{collection_name}.nil?\n@\#{collection_name} = \#{collection_finder}\nend\n\nreturn @\#{collection_name}\nend\n\n\# Ex: has_clients?\ndef has_\#{collection_name}?\n\#{collection_name}.length > 0\nend\n\n\# Ex: clients_count\ndef \#{collection_name}_count\nif @\#{collection_name}.nil?\n\#{collection_counter}\nelse\n@\#{collection_name}.length\nend\nend\n"
61:
62: # Can't use constrained finds with specialized finder SQL
63: unless options[:finder_sql]
64: module_eval "\# Ex: find_in_clients(id)\ndef find_in_\#{collection_name}(association_id)\n\#{collection_class_name}.find_with_constraint(\nassociation_id, \"\#{class_primary_key_name} = \\\#{id}\#{options[:constraint] ? \" AND \" + options[:constraint] : \"\"}\"\n)\nend\n"
65: end
66: end
# File lib/active_record/associations.rb, line 106
106: def has_one(association_id, options = {})
107: validate_options([ :class_name, :foreign_key, :remote ], options.keys)
108:
109: association_name = association_id.id2name
110: association_class_name = options[:class_name] || class_name(association_id.id2name)
111: association_class_primary_key_name = options[:foreign_key] || association_class_name.downcase + "_id"
112: class_primary_key_name = options[:foreign_key] || name.downcase + "_id"
113:
114: if options[:remote]
115: association_finder = "#{association_class_name}.find_first(\"#{class_primary_key_name} = \#{id}\")"
116: else
117: association_finder = "#{association_class_name}.find(#{association_class_primary_key_name})"
118: end
119:
120: module_eval "\# Ex: credit_card\ndef \#{association_name}\nif @\#{association_name}.nil?\n@\#{association_name} = \#{association_finder}\nend\n\nreturn @\#{association_name}\nend\n\n\# Ex: has_credit_card?\ndef has_\#{association_name}?\nbegin\n!\#{association_name}.nil?\nrescue Exception\nfalse\nend\nend\n\n\# Ex: credit_card?(same_credit_card)\ndef \#{association_name}?(comparison_object)\nif comparison_object.kind_of?(\#{association_class_name})\nbegin\n\#{association_name}.id == comparison_object.id\nrescue Exception\nfalse\nend\nelse\nraise \"Comparison object is a \#{association_class_name}, should have been \\\#{comparison_object.class.name}\"\nend\nend\n"
121: end
# File lib/active_record/associations.rb, line 155
155: def belongs_to(association_id, options = {})
156: validate_options([ :class_name, :foreign_key ], options.keys)
157:
158: association_name = association_id.id2name
159: association_class_name = options[:class_name] || class_name(association_id.id2name)
160: association_class_primary_key_name = options[:foreign_key] || association_class_name.downcase + "_id"
161:
162: module_eval "\# Ex: credit_card\ndef \#{association_name}\nif @\#{association_name}.nil?\n@\#{association_name} = \#{association_class_name}.find(\#{association_class_primary_key_name})\nend\n\nreturn @\#{association_name}\nend\n\n\# Ex: has_credit_card?\ndef has_\#{association_name}?\n!\#{association_name}.nil?\nend\n\n\# Ex: credit_card?(same_credit_card)\ndef \#{association_name}?(comparison_object)\nif comparison_object.kind_of?(\#{association_class_name})\n\#{association_name}.id == comparison_object.id\nelse\nraise \"Comparison object is a \\\#{comparison_object.class.name}, should have been \#{association_class_name}\"\nend\nend\n"
163: end