Как мне создать самореферентную ассоциацию (самосоединение) в отдельном классе с помощью ActiveRecord в Rails?

Я пытаюсь создать таблицу для самостоятельного присоединения, которая представляет собой список клиентов, которые могут направлять друг друга (возможно, к продукту или программе). Я пытаюсь ограничить свою модель одним классом «Клиент».

TL; DR доступен внизу.

Схема такая:

  create_table "customers", force: true do |t|
    t.string   "name"
    t.integer  "referring_customer_id"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  add_index "customers", ["referring_customer_id"], name: "index_customers_on_referring_customer_id"

Моя модель:

class Customer < ActiveRecord::Base
  has_many :referrals, class_name: "Customer", foreign_key: "referring_customer_id", conditions: {:referring_customer_id => :id}
  belongs_to :referring_customer, class_name: "Customer", foreign_key: "referring_customer_id"
end

У меня нет проблем с доступом к клиенту referring_customer:

@customer.referring_customer.name

... возвращает имя клиента, который направил @customer.

Однако при обращении к рефералам я продолжаю получать пустой массив:

@customer.referrals

... возвращает [].

Я запустил binding.pry, чтобы узнать, какой SQL выполнялся, учитывая, что у клиента есть «реферер» и должен иметь несколько рефералов. Это выполняемый SQL.

      Customer Load (0.3ms)  SELECT "customers".* FROM "customers"
WHERE "customers"."id" = ? ORDER BY "customers"."id"
ASC LIMIT 1  [["id", 2]]

      Customer Exists (0.2ms)  SELECT 1 AS one FROM "customers"
WHERE "customers"."referring_customer_id" = ? AND
"customers"."referring_customer_id" = 'id' LIMIT 1 
[["referring_customer_id", 3]]

Я немного растерялся и не уверен, в чем моя проблема. Я не думаю, что мой запрос верен - @ customer.referrals должны возвращать массив всех рефералов, которые являются клиентами, у которых @ customer.id в качестве их referring_customer_id.

TL; DR Возможно ли самостоятельное присоединение с использованием только одного класса? Если да, как мне настроить мои условия и внешние ключи, чтобы мои запросы давали мне правильные данные для отношения has_many?


person Daniel Chang    schedule 06.11.2013    source источник


Ответы (1)


Это определение ассоциации

has_many :referrals, class_name: "Customer", foreign_key: "referring_customer_id", conditions: {:referring_customer_id => :id}

не совсем верно. Нет необходимости определять предложение условий - в этом весь смысл has_many. Должен быть:

has_many :referrals, class_name: "Customer", foreign_key: "referring_customer_id" 

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

person Peter Goldstein    schedule 06.11.2013
comment
Заметил, что когда вынес условия, 1) все заработало! Спасибо! И 2) оператор sql, который проверял наличие ссылок, потерял запрос AND "customers"."referring_customer_id" = 'id'. Я предполагаю, что это были :conditions. Но почему это не сработало? Я думал, что это просто ограничение для клиентов с помощью referring_customer_id, равного идентификатору клиента. - person Daniel Chang; 06.11.2013
comment
Условия в том виде, в котором вы их написали, фактически ограничивали значение referring_customer_id равным строковой константе id. Это то, что сказано в вашем SQL, если вы внимательно его прочитаете. Пожалуйста, примите мой ответ, если он был полезен - спасибо! - person Peter Goldstein; 06.11.2013
comment
Аааа! Хотел бы я проверить это в последний час. Просто выяснил это, и на самом деле conditions: "referring_customer_id = id" проверяет эквивалентность двух целых чисел, тогда как conditions: {:referring_customer_id => :id} запускает оператор SQL, который проверяет, совпадает ли referring_customer_id со строкой 'id'. Спасибо за помощь, Питер! - person Daniel Chang; 06.11.2013