Извлечение строк из одной таблицы с полиморфными ассоциациями - PullRequest
3 голосов
/ 23 августа 2011

У меня есть одна модель, которая имеет полиморфную связь с тремя другими таблицами:

class User < ActiveRecord::Base
    belongs_to :authenticatable, :polymorphic => true


# == Schema Information
#
# Table name: employees
#
#  id                     :integer(4)      not null, primary key
#  ...
#  school_id              :integer(4)

class Guardian < ActiveRecord::Base
    has_one :user, :as => :authenticatable
    belongs_to :school


# == Schema Information
#
# Table name: guardians
#
#  id                     :integer(4)      not null, primary key
#  ...
#  school_id              :integer(4)

class Guardian < ActiveRecord::Base
    has_one :user, :as => :authenticatable
    belongs_to :school

# == Schema Information
#
# Table name: students
#
#  id                     :integer(4)      not null, primary key
#  ...
#  school_id              :integer(4)

class Student < ActiveRecord::Base
    has_one :user, :as => :authenticatable
    belongs_to :school

Как вы можете видеть, последние 3 модели относятся к "школьной" модели и поэтому имеют столбец с именем * 1004.*.Я хочу извлечь все строки из user так, чтобы их соответствующий аутентифицируемый school_id был равен некоторому значению.Чтобы уточнить, я хотел бы сделать что-то вроде этого:

User.joins(:authenticatable).where(:school_id => some_value)

Как так, это приведет к

ActiveRecord::EagerLoadPolymorphicError

на последней ноте, мне удалось посмотреть вверхнекоторая документация, которая предполагает, что использование include для полиморфной ассоциации должно работать, например:

User.find(:all, :include => :authenticatable) (This works)

Однако, если я сделаю это:

User.find(:all, :include => :authenticatable).where(:school_id => some_value)

Это ломает рельсы, потому что User.find(...) возвращаетArray и метод where не определен для этого класса.

Я пробовал некоторые другие варианты и не нашел способа выполнить то, что я хочу.Вы можете мне помочь?Спасибо!

Ответы [ 2 ]

1 голос
/ 23 августа 2011

Вы можете попытаться решить эту проблему с помощью SQL-запроса в joins инструкции:

Model1.joins("INNER JOIN model2 ON model2.id = model1.polymorphizm_id INNER JOIN model3 ON model3.id = model1.polymorphizm_id INNER JOIN model4 ON model4.id = model1.polymorphizm_id").where("model2.column_id = ... or model3.column_id = ... or model4.column_id = ...")

Я на самом деле не пробую, но полиморфный асс. добавляет в модель 2 столбца: xxx_type и xxx_id. Они служат для обработки доц. с несколькими моделями.

0 голосов
/ 20 мая 2017

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

User.where(authenticable: Guardian.where(school_id: some_value))

Если вы используете Rails 5, они добавили .or к ActiveRecord, так что вы можетеобъедините некоторые из них, например:

User.where(authenticable: Guardian.where(school_id: some_value))
    .or.where(authenticable: Student.where(school_id: some_value))

merge - это еще один метод, который может дать некоторые результаты:

User.all.merge(Guardian.where(school_id: some_value))

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

user_ids = Guardian.joins(:user).select('users.id').where(school_id: some_value).pluck(:user_id) +
           Student.joins(:user).select('users.id').where(school_id: some_value).pluck(:user_id)
users = User.where(id: user_ids)

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

class User < ActiveRecord::Base
  belongs_to :school
end

class Student < User
end

class Guardian < User
end

Тогда вы просто скажете:

User.where(school_id: some_value)

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

...