Rails is missing the capability to have a has_one association via a link table. I created this implementation that adds methods to add basic "has_one" support through a habtm association.
The following method defines a new type of association that is currently
missing in rails. There is currently no way to have a
has_one association when a join table is used.
This association requires that a has_and_belongs_to_many
association exists and adds methods to access the first
element of the resulting array.
Example: Enrollments have one registration, but is
modeled through the enrollments_registrations join table.
There is already a "has_and_belongs_to_many :registrations"
and the following operations are added
(and perform as expected):
- enrollment.registration => enrollments.registrations.first
- enrollment.registration_id => enrollments.registrations.first.id
- enrollment.registration= will set the assocation, erasing any existing registration.
This method will take an id or a registration object
- enrollment.registration_id= like registration=, but takes an id
- enrollment.has_registration? => true or false as the case may be
def self.has_one_through_join_table(class_name)
class_name = class_name.to_s
has_many_association_name = class_name.pluralize
# def registration
define_method(class_name) do
send(has_many_association_name).first
end
#def registration_id
define_method(class_name+"_id") do
send(class_name) ? send(class_name).id : nil
end
# def registration=(id_or_object)
define_method(class_name+"=") do |id_or_object|
clazz = eval(class_name.classify)
# the has_and_belong_to_many association (i.e. registrations)
habtm = send(class_name.pluralize)
if id_or_object.nil?
habtm.clear
return
end
id_or_object = clazz.find(id_or_object) unless
id_or_object.is_a?(clazz)
if id_or_object
habtm.clear # can only have one object
habtm << id_or_object
end
end
#def registration_id=(id)
define_method(class_name+"_id=") do |id|
send(class_name+"=", id)
end
# def has_registration?
define_method("has_#{class_name}?") do
! send(class_name).nil?
end
end # has_many_through_join_table