Отношение многие ко многим работает только в одном направлении в Rails - PullRequest
0 голосов
/ 23 октября 2018

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

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

У директора по доставке есть директора по работе с клиентами, у Pods есть менеджеры по работе с клиентами, есть компании.

Следовательно, у директоров по доставке должны быть компании.

Вся эта структура работает, вплоть до компаний, изатем внезапно останавливается.Директор по доставке возвращает [] для компаний.

class DeliveryDirector < User
  has_many :account_directors
  has_many :pods, through: :account_directors
  has_many :account_managers, through: :pods
  has_many :companies, through: :account_managers
end

И класс компании выглядит так:

class Company < ApplicationRecord
   belongs_to :account_manager
   has_one :pod, through: :account_manager
   has_one :account_director, through: :pod
   has_one :delivery_director, through: :account_manager
end

Как я уже сказал, все работает.В компании даже есть директор по доставке!Это просто DeliveryDirector.all.first.companies возвращает [].

Если бы кто-нибудь мог просто указать мне правильное направление, это было бы здорово.Нет сообщения об ошибке, и, кажется, ничего не происходит неправильно.

О, если это поможет, вот SQL, сгенерированный запросом:

Company Load (0.7ms)  SELECT "companies".* FROM "companies" INNER JOIN "users" ON "companies"."account_manager_id" = "users"."id" INNER JOIN "pods" ON "users"."pod_id" = "pods"."id" INNER JOIN "users" "account_directors_companies" ON "pods"."account_director_id" = "account_directors_companies"."id" WHERE "users"."type" IN ('AccountDirector') AND "account_directors_companies"."delivery_director_id" = $1  [["delivery_director_id", 2]]

Спасибо!

Редактировать: Запрос на другие модели, схема

Под:

class Pod < ApplicationRecord
   belongs_to :account_director
   has_many :account_managers
   has_many :companies, through: :account_managers
end

Менеджер аккаунта:

class AccountManager < User
  belongs_to :pod
  has_one :account_director, through: :pod
  has_one :delivery_director, through: :account_director
  has_many :companies
end

Схема:

ActiveRecord::Schema.define(version: 2018_10_19_141416) do


  enable_extension "plpgsql"

  create_table "companies", force: :cascade do |t|
    t.string "name"
    t.string "officelocation"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.string "campaign_link"
    t.string "company_logo"
    t.string "website"
    t.integer "account_manager_id"
  end

  create_table "images", force: :cascade do |t|
    t.string "name"
    t.string "location"
    t.bigint "company_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["company_id"], name: "index_images_on_company_id"
  end

  create_table "jwt_blacklist", id: :serial, force: :cascade do |t|
    t.string "jti", null: false
    t.index ["jti"], name: "index_jwt_blacklist_on_jti"
  end

  create_table "markets", force: :cascade do |t|
    t.string "name"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "markets_users", id: false, force: :cascade do |t|
    t.bigint "market_id", null: false
    t.bigint "talent_manager_id", null: false
  end

  create_table "pods", force: :cascade do |t|
    t.string "name"
    t.integer "account_director_id"
    t.integer "delivery_director_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "table_campaigns", force: :cascade do |t|
    t.bigint "user_id"
    t.bigint "company_id"
    t.string "name"
    t.integer "iterations"
    t.integer "interviews"
    t.index ["company_id"], name: 
    "index_table_campaigns_on_company_id"
    t.index ["user_id"], name: "index_table_campaigns_on_user_id"
 end

  create_table "users", force: :cascade do |t|
    t.string "name"
    t.string "jobtitle"
    t.string "linkedin"
    t.string "office"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.string "type"
    t.integer "team_lead_id"
    t.integer "delivery_director_id"
    t.string "email", default: "", null: false
    t.string "encrypted_password", default: "", null: false
    t.string "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    t.integer "sign_in_count", default: 0, null: false
    t.datetime "current_sign_in_at"
    t.datetime "last_sign_in_at"
    t.inet "current_sign_in_ip"
    t.inet "last_sign_in_ip"
    t.bigint "pod_id"
    t.string "user_photo"
    t.index ["email"], name: "index_users_on_email", unique: true
    t.index ["pod_id"], name: "index_users_on_pod_id"
    t.index ["reset_password_token"], name: 
     "index_users_on_reset_password_token", unique: true
  end

  add_foreign_key "table_campaigns", "companies"
  add_foreign_key "table_campaigns", "users"
end

А теперь добавление директора аккаунта:

class AccountDirector < User
  belongs_to :delivery_director
  has_one :pod
  has_many :account_managers, through: :pod
  has_many :companies, through: :account_managers
end

1 Ответ

0 голосов
/ 23 октября 2018

Вы используете наследование одной таблицы.3 из ваших моделей: DeliveryDirector, AccountDirector и AccountManager являются потомками модели User.Когда выполняется неглубокий запрос, он работает нормально, но когда вы создаете запросы, включающие все 3 модели, Rails не может построить правильный запрос.Если вы попытаетесь спроектировать, как найти все компании директора по доставке с точки зрения базы данных, вы попадете в цепочку таблиц:

companies -> users (account managers) -> pods -> users (account directors) -> users (delivery directors)

SQL-запрос для вашего запроса может выглядеть следующим образом:

SELECT companies.* FROM companies
  INNER JOIN users AS account_managers ON companies.account_manager_id = account_managers.id
  INNER JOIN pods ON account_managers.pod_id = pods.id
  INNER JOIN users AS account_directors ON pods.account_director_id = account_directors.id
  INNER JOIN users AS delivery_directors ON account_directors.delivery_director_id = delivery_directors.id
WHERE delivery_directors.id = 2;

но, очевидно, Rails не добавляет в запрос предложение AS, чтобы различать роли пользователей, и вместо этого использует users имя таблицы.Для фильтрации результатов используется условие "users"."type" IN ('AccountDirector'), которого недостаточно в вашем случае, потому что в вашем запросе также должно быть AccountManager (как ссылка между pods и companies).

Другой знакчто Rails сбит с толку: несмотря на правильную ассоциацию в ваших моделях, Rails пытается использовать таблицу account_directors_companies, которой у вас явно нет.

Я бы порекомендовал рассмотреть схему вашей базы данных и выделить роли пользователей и отношения между ними в отдельныевещества.

ОБНОВЛЕНИЕ:

Например, данные аутентификации / регистрации пользователя можно оставить в таблице users, как сейчас.Вся информация о ролях пользователей и их отношениях может быть перенесена в дополнительные таблицы, поддерживаемые моделями:

class DeliveryDirector < ApplicationRecord
  belongs_to :user
  has_many :account_directors
  has_many :pods, through: :account_directors
  has_many :account_managers, through: :pods
  has_many :companies, through: :account_managers
end

class AccountDirector < ApplicationRecord
  belongs_to :user
  has_one :pod
  has_many :account_managers, through: :pod
  has_many :companies, through: :account_managers
end

class AccountManager < ApplicationRecord
  belongs_to :user
  has_many :companies
end

Каждая из этих моделей имеет свою собственную таблицу в базе данных.

Таким образом, чтобыПризовите компании директора по доставке, которые вы могли бы позвонить:

DeliveryDirector.find_by(user_id: user_id).companies
...