First off - I wouldn't use HABTM here, but instead a named join table (called Relationship) with it's own model and use has_many :people, through: :relationships
.
- I have created 2 people. I want the second person to be included when I query for Person.first.people and vice versa! (i.e the first person shall be included when I query for Person.second.people). I was close to achieve this with has_and_belongs_to_many :(people|reversed_people): https://stackoverflow.com/a/46230787/6030239
You can achieve this with a single activerecord relationship (either has-many through or HABTM) by adding two rows for each relationship (one in each direction). For example:
def add_bi_directional_relationship(first:, second:, type:)
Relation.create!(person_a: first, person_b: second, connection: type)
Relation.create!(person_a: second, person_b: first, connection: type)
end
# first.people => [second]
# second.people => [first]
Activerecord associations are designed to query a table by a foreign key, so to use them in a straightforward way you need a table where the value you want to query is going to be in a single column.
However, why do you need it to be done via an activerecord association? You can write a method that does the query you need.
class Person
has_many :forward_people, through: :relations, #...
has_many :reversed_people, through: :relations, #...
def people
forward_people + reversed_people
# or build the joins in SQL strings or Arel
end
end
Or lots of other potential solutions, depending on your needs.
- Relationship which connects the two has a connection value of friends. I want to create a has_many :friends method, such that the second person will appear in Person.first.friends query and vice versa!
Not sure I totally understand this... but if you take the first approach of adding a relationship for each direction, then you can write a method like:
def friends
people.where(relations: {connection: 'friends'})
end
You can also do this with another activerecord relationship... but I wouldn't recommend defining multiple activerecord associations for the same foreign keys. An alternative approach could be to define a .friends
scope that would allow you to do Person.first.people.friends
.
In general these goals are difficult to accomplish because you're specifying an implementation (an activerecord association that returns specific values) without indicating why you need it to be done like / what problems you're trying to solve with it. Activerecord associations are helpful to a point, but they also introduce a layer of abstraction that can add complexity/confusion. Discussing the actual business/application needs you want to solve (e.g. a report that shows X, a view that renders X, or a form that saves X) would allow people to suggest alternative approaches that might be a better fit what you're trying to accomplish.