Rails 5.1 has_many через связанные поля

(см. пример изображения схемы ниже)

Я пытаюсь запросить одного пользователя из таблицы users, используя поле email вместе с полями id и key из таблицы applications. Результаты должны содержать найденного пользователя (если он есть), а также приложение (ссылку на которое можно получить с помощью полей key и id) и связанные с ним данные applications_users.

Пример схемы

Я могу легко написать SQL вручную для выполнения этой операции:

SELECT
  "users".*,
  "applications_users"."scopes",
  "jwt_applications".*
FROM 
  "users"
INNER JOIN
  "applications_users" ON "applications_users"."user_id" = "users"."id"
INNER JOIN
  "jwt_applications" ON "jwt_applications"."id" = "applications_users"."application_id"
WHERE
  "users"."email" = '[email protected]'
  AND "jwt_applications"."id" = '01daafc9-2169-4c78-83e9-37ac0a473e3d'
  AND "jwt_applications"."key" = 'follow_the_rainbow'
LIMIT 1

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

Это неудачные попытки, которые я сделал до сих пор:

user = User.where(email: args[:username]).joins(:applications).merge(
  JwtApplication.where(id: args[:application][:id], key: args[:application][:key])
).take!

Это правильно получает пользователя, однако Rails выполняет второй запрос SQL, когда я пытаюсь получить доступ к user.applications (и он также возвращает все приложения, связанные с пользователем, поэтому, похоже, он игнорирует условия id и key)

user = User.where(email: args[:username]).joins(:applications).merge(
  JwtApplication.where(id: args[:application][:id], key: args[:application][:key])
).references(:applications_users).take!

Это правильно возвращает пользователя, а также правильное приложение (ура!), однако Rails выполняет второй запрос SQL, если я пытаюсь вызвать user.applications_users -- он также возвращает коллекцию для всех данных внутри таблицы applications_users (опять же, игнорируя id и key условия)

user = User.where(email: args[:username]).joins(:applications).where(
  jwt_applications: {
    id: args[:application][:id],
    key: args[:application][:key]
  }
).take!

Это дает правильного пользователя, однако Rails выполняет другой запрос SQL, когда я пытаюсь получить доступ к user.applications, также возвращая все приложения.

В любом случае, надеюсь, гений Rails сможет пролить свет на этот вопрос! Я буду первым, кто признает, что я ни в коем случае не являюсь экспертом по Rails; Я провел последние 10 лет своей профессиональной карьеры за программированием на PHP и C++, поэтому, пожалуйста, потерпите меня, если это покажется глупым вопросом :)


person Nate Strandberg    schedule 23.06.2017    source источник


Ответы (1)


Не уверен, что это то, что вы ищете, но... Вы можете написать запрос ActiveRecord, например (модель соединения должна быть неявно добавлена ​​в ваш запрос):

User.joins(:applications).where(email: email).where(applications: { key: key, id: id})

Где адрес электронной почты, ключ и идентификатор в качестве параметров для передачи в запрос.

В дополнение к этому запросу вы можете использовать поля выбора, чтобы получить все, что вам нужно:

user = User.joins(:applications).where(email: email).where(applications: { key: key, id: id}).select('users.*, applications.id as appid applications.key as appkey').first

Это вернет вам пользовательскую модель (если она есть) или пустое отношение, если ничего не соответствует вашим критериям. Затем вы можете вызывать такие поля, как

user.appid

user.appkey

Вы всегда можете вызвать select ('users.*, application_users.scopes, applications.*), который вернет вам все поля в одном экземпляре (все еще в модели пользователя), НО повторяющиеся поля, такие как id, будут отображаться только один раз, поэтому лучше захватить только те поля, которые вы хотите, и дать им уникальные идентификаторы, такие как Я показал с помощью appid и appkey.

Опять же, это может быть не совсем то, что вам нужно, но, надеюсь, это укажет вам правильное направление!

person TomD    schedule 23.06.2017