Active Serializer объект не возвращает все записи ассоциации (имеет много: через отношения) - PullRequest
0 голосов
/ 10 января 2019

Итак, у меня есть модели User & Role, которые связаны с моделью UserRole с помощью has_many: посредством ассоциации. И я использую сериализатор для пользователя. Примечание. У пользователя много ролей. Но по какой-то причине я не могу получить все роли в сериализаторе. Это запрос,

unless params['roles'].blank?
  render json: User.includes(:roles)
                    .references(:user_roles)
                    .where('roles.name IN (?)', params['roles'])
else
  render json: User.all
end

И в моем пользовательском сериализаторе у меня есть

attributes :id, :name, :email, :roles

def roles
  object.roles.pluck(:name)
end

Дело в том, что у меня есть пользователь с обеими ролями "администратор" и "автор". Когда я передаю «admin» в качестве параметров, объект Output json просто имеет roles: ["admin"] для этого пользователя. После отладки для этого объекта object.roles.count равен 2 НО, когда я делаю object.roles, он показывает только 1 запись. Что происходит?

Когда я делаю User.find(object.id).roles.pluck(:name), это работает. Но это запускает запросы в цикле сериализатора.

Выходной отклик отлично подходит для User.all без параметров. (получение ролей: ["author", "admin"]). Проблема в том, когда я передаю param. Возможно, что-то не так с моим запросом?

1 Ответ

0 голосов
/ 10 января 2019

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

User.includes(:roles).where(
  id: User.joins(:roles).where(roles: { name: params[:roles] })
)

Если вы посмотрите на сгенерированный SQL, то увидите, что предложение where здесь применимо только к подзапросу - таким образом, загружаются все связанные роли, а не только те, которые соответствуют WHERE "roles"."name" = $1.

  User Load (3.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" IN (SELECT "users"."id" FROM "users" INNER JOIN "user_roles" ON "user_roles"."user_id" = "users"."id" INNER JOIN "roles" ON "roles"."id" = "user_roles"."role_id" WHERE "roles"."name" IN ($1, $2, $3)) LIMIT $4  [["name", "admin"], ["name", "foo"], ["name", "bar"], ["LIMIT", 11]]
  UserRole Load (0.6ms)  SELECT "user_roles".* FROM "user_roles" WHERE "user_roles"."user_id" = $1  [["user_id", 1]]
  Role Load (0.5ms)  SELECT "roles".* FROM "roles" WHERE "roles"."id" = $1  [["id", 1]]

Также, если вы хотите использовать загруженные записи, вам нужно использовать map, а не pluck, так как сборщик данных создает отдельный запрос на выборку.

def roles
  object.roles.map(&:name)
end
...