Кажется, что нет последовательности ассоциаций, которые работают для этого шаблона:

Каждый пользователь содержит ссылку на двух других пользователей в одной таблице.

Таблица User содержит два поля: user_a_id и user_b_id. Я пытался заставить работать следующие ассоциации моделей:

class User < ApplicationRecord
    has_one :user_a, class_name: "User", foreign_key: "user_a_id"
    has_one :user_b, class_name: "User", foreign_key: "user_b_id"
end

Ссылка должна работать только в одном направлении. Я просто хочу использовать модель следующим образом:

user.user_a.name
user.user_b.name

Мне никогда не понадобится доступ к user_a.parent_user. Мне не нужны такие отношения.

Проблема возникает, когда я ссылаюсь на self.user_a в обратном вызове before_save. Я в основном получаю рекурсивный цикл запросов SQL, который в конечном итоге выдает ошибку stack too deep.

Кто-нибудь знает, что здесь происходит?

0
sambecker 27 Май 2017 в 22:37

2 ответа

Лучший ответ

Наконец-то нашел решение. Это может быть крайний случай, НО мне нужно было использовать belongs_to вместо has_one, и мне нужно было удалить id из моей таблицы и foreign_key. Кроме того, поскольку я хранил свои ссылки в обратном вызове before_save, и они были бы пустыми во время проверки, мне нужно было добавить параметр optional: true. Это единственное объединение, которое позволило моей программе надежно работать:

class User < ApplicationRecord
    belongs_to :user_a, class_name: "User", foreign_key: "user_a", optional: true
    belongs_to :user_b, class_name: "User", foreign_key: "user_b", optional: true
end

Надеюсь, это кому-нибудь поможет!

0
sambecker 29 Май 2017 в 16:53

Я просто попробовал то, чего ты хочешь достичь. Это миграция для таблицы пользователей:

create_table :users do |t|
  t.string :name
  t.references :user_a
  t.references :user_b

  t.timestamps
end

Обратите внимание, как это генерирует следующий schema.rb

create_table "users", force: :cascade do |t|
  t.string "name"
  t.integer "user_a_id"
  t.integer "user_b_id"
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
  t.index ["user_a_id"], name: "index_users_on_user_a_id"
  t.index ["user_b_id"], name: "index_users_on_user_b_id"
end

В модели пользователя у меня есть

class User < ApplicationRecord
  has_one :user_a, class_name: "User", foreign_key: "user_a_id"
  has_one :user_b, class_name: "User", foreign_key: "user_b_id"
end

После миграции я могу сделать в своем rails console следующее:

User.create(
  name: "inception_user",
  user_a: User.create(name: "Adam"),
  user_b: User.create(name: "Berta")
)

inception_user = User.find_by_name "inception_user"

inception_user.user_a.name
=> "Adam"

inception_user.user_b.name
=> "Berta"

С этой настройкой все работает как положено. Прокомментируйте, если у вас все еще есть проблемы!
Дополнительная информация о самостоятельных объединениях: http://guides.rubyonrails.org/association_basics.html. # Самосоединения

2
Niklas 27 Май 2017 в 20:31