eeeeeean eeeeeean - 2 months ago 8
Ruby Question

How to conditionally include association definitions?

I'm able to get the behavior I'd like if I create a Foo class, some STI classes that inherit it (Foo1, Foo2, etc.) and then to add different

has_many :bars
associations to each class. For example:

class Foo < ApplicationRecord
has_many :bars
end

class Foo1 < Foo
has_many :bars, -> { where(user_id: 1) }
end


I want to be able to call
bars
on an object and get a different association behavior depending on the state of the object. This works, but is there a way to do it without setting up STI?

I tried doing everything inside foo.rb but I seem to be loading my first
has_many :bars
definition even if I do something like this:

has_many :bars ... if some_method_returning_boolean?
has_many :bars ... if some_other_method_returning_boolean?


And even if this did work, it seems kind of clunky.

I also considered scopes, but as far as I understand scopes then I'd have to call
foo.bars.something
and
foo.bars.something_else
instead of relying on the state of the object
foo
to give me
foo.bars
differently. Also, it looks like scopes only cover part of a
has_many
definition but can't modify arguments like
:source
,
:foreign_key
, but I may be wrong.

Is there another way?

Answer

STI is the correct way of doing this. It's generally understood that any particular model class should have well-defined and consistent relationships with other records.

If you have relationships that only apply to certain kinds of records that's exactly what STI is for: Create a subclass that defines these relationships.

You see this all the time. An example would be that both "Parent" and "Student" are of base type "Person", but that the students have a belongs_to: parent association and the parents have a has_many: children relationship.

Of course this presumes parents are unlikely to become students, and students parents, an assumption that may not be correct. Whatever assumptions you make, I hope there's some serious thinking about if these restrictions are relevant or just overly paranoid.

It's generally bad form to switch types on a record even though it can technically be done. You could use this to adjust how a record's relationships are defined if you think this is strictly necessary.

Generally I'd advise you to stick with a consistent relationship structure. Those records which should not be related to anything don't need those methods physically removed, they can be there while not doing anything useful. They come along for free anyway.