And now I’ve waffled back. I found the Recipe #29 in Advanced Rails
Recipes: Create Meaningful Relationships Through Proxies.
So now I’ve defined on the User class:
has_many :profiles, :as => :profilable do
def default(reload=false)
@default_profile = nil if reload
@default_profile ||= find_by_is_default(true)
end
end
And this lets me do stuff like:
User.find(:first).profiles.default # => a Profile object that is
flagged with the :is_default boolean.
(which is nicely similar to: User.find(:first).profiles.first and
other such calls)
The main reason is that I’m using polymorphism on the objects that
have profiles, so I don’t have to define a FK on each table. I like
the cleanness of this although it means I’ll need to do Jon’s logic to
ensure that when a new default is set, the old is unset. But as the
number of profiles per user should be very small I’m not worried.
So functionally, it really does come back to:
a) do I put a FK on each table that has a default Profile and use that
for referencing the default Profile object?
- upside: simple association assigment. Nice, neat.
- downside: additional field on table, loses some functionality?
b) do I put a boolean in the Profiles table and use the proxy idea for
referencing the object?
- upside: make for a nice call: i.e. like .first I can now do .default
(for an association of Profiles). I can use polymorphism fully, so the
User table doesn’t have anything referencing Profiles and it’s all
handled in the models.
- downside: need to handle “singularity” of the is_default field.
Performance issues?
Ultimately, I realize that either will work very well. so I dunno. I
don’t want to think about it too much anymore. I still think that my
original idea is interesting: building a “validates_singularity_of”
helper. Then, it would just to Jon’s code, and could include scoping
constraints, i.e. something like:
validates_singularity_of :is_default, :scope => :user_id
or in my case, where I’m using polymorphism I’d have:
validates_singularity_of :is_default, :scope => :profilable_id
and maybe a :force => true option that instead of returning a
validation error would enforce the singularity, i.e. set the object
and unset all the others within the scope.
Hmmm… choices choices
I guess I’ll build out my controllers and views for this and see if
that guides it one way or the other.