Как добиться многого через отношения между пользователями

Я создаю систему сопоставления между пользователями, изначально она имела и принадлежит многим ассоциациям, но из-за некоторых проверок и дополнительных данных, которые мне нужны для этой таблицы соединений, мне нужно иметь модель для этой таблицы и изменить ее на множество.

has_and_belongs_to_many(:likes,
    class_name: :User,
    join_table: :user_likes,
    foreign_key: :user_liker_id,
    association_foreign_key: :user_liked_id)

has_and_belongs_to_many(:likeds,
    class_name: :User,
    join_table: :user_likes,
    foreign_key: :user_liked_id,
    association_foreign_key: :user_liker_id)

Это старая реализация, которую нужно преобразовать в has_many через. Как вы можете видеть, с этим я могу получить всех пользователей, которые мне понравились, и пользователей, которые мне понравились. Я создал UserLike модель, но у меня нет никакого успеха в том, чтобы сделать ее работоспособной внутри пользовательской модели. То, что я уже попробовал, следующее:

user.rb

has_many :user_likes
has_many :likes, through: :user_likes, foreign_key: :user_liked_id
has_many :likeds, through: :user_likes, foreign_key: :user_liker_id

user_like.rb

class UserLike < ApplicationRecord
    belongs_to :user
end

Эта реализация вызывает следующее исключение:

ActiveRecord:: HasManyThroughSourceAssociationNotFoundError: Не удалось найти ассоциацию (и) источника "like" или: likes в модели UserLike. Попробуйте 'has_many:likes,:through =>:user_likes,:source => '. Это один из user или user_likes?

Я не знаю, что мне здесь не хватает, любая помощь будет оценена:)

2 ответа

Решение

При создании таблицы соединения, которая дважды объединяет одну и ту же таблицу, необходимо две отдельные ассоциации, поскольку пользователь может использовать любой внешний ключ:

class User < ApplicationRecord
  has_many :likes_as_liker,
    class_name: 'Like',
    foreign_key: 'liker_id'
  has_many :likes_as_liked,
    class_name: 'Like',
    foreign_key: 'liked_id'
end

class Like < ApplicationRecord
  belongs_to :liker, class_name: 'User'
  belongs_to :liked, class_name: 'User'
end

Сделав две наши ассоциации has_many, мы можем начать создавать косвенные ассоциации:

class User < ApplicationRecord
  has_many :likes_as_liker,
    class_name: 'Like',
    foreign_key: 'liker_id'
  has_many :likes_as_liked,
    class_name: 'Like',
    foreign_key: 'liked_id'
  has_many :likers,
    through: :likes_as_liked
  has_many :liked_users,
      through: :likes_as_liker,
      source: :liked
end

Который работает отлично:

irb(main):002:0> u.likers
  User Load (2.8ms)  SELECT  "users".* FROM "users" INNER JOIN "likes" ON "users"."id" = "likes"."liker_id" WHERE "likes"."liked_id" = $1 LIMIT $2  [["liked_id", 1], ["LIMIT", 11]]
=> #<ActiveRecord::Associations::CollectionProxy []>
irb(main):003:0> u.liked_users
  User Load (1.3ms)  SELECT  "users".* FROM "users" INNER JOIN "likes" ON "users"."id" = "likes"."liked_id" WHERE "likes"."liker_id" = $1 LIMIT $2  [["liker_id", 1], ["LIMIT", 11]]
=> #<ActiveRecord::Associations::CollectionProxy []>

В соответствии с описанием, упомянутым в посте, вы пытаетесь найти пользователей, которым понравился мой пост, и пользователей, которые мне понравились.

Ниже упомянутый код не говорит рельсам, что лайки и лайки на самом деле являются пользователями.

has_many :user_likes
has_many :likes, through: :user_likes, foreign_key: :user_liked_id
has_many :likeds, through: :user_likes, foreign_key: :user_liker_id

Изменить его ниже

has_many :user_likes
has_many :likes, through: :user_likes, foreign_key: :user_liked_id, source: :liked
has_many :likeds, through: :user_likes, foreign_key: :user_liker_id, source: :liked

Наилучший подход определяет класс вместе с именем класса, чтобы рельсы знали, в каком классе отображается этот внешний ключ при указании имен настраиваемых отношений

Если имя вашей ассоциации отличается от имени, используемого в:through, вы должны определить параметр источника. Если вы посмотрите на сообщение об исключении, оно явно попросит вас сделать это.

Надеюсь, что это отвечает на вопрос.

Другие вопросы по тегам