объединение двух отношений в Rails - PullRequest
0 голосов
/ 07 ноября 2018

Это должно быть легко, я думаю ...

Организация имеет владельца и участников - оба являются пользователями.

Это настраивается организацией, используя имя_класса: «Пользователь», например:

class Organisation < ApplicationRecord
   belongs_to :owner, class_name: "User", foreign_key: "owner_id"
   has_many :organisations_users
   has_many :members, class_name: "User", through: :organisations_users, source: :user
end

Это работает, но мне нужна функция all_members (или область действия), чтобы я мог вернуть владельца и членов в одном массиве (или объекте ActiveRecord). Я думал, что это будет тривиально, но на самом деле это не так.

Я пробовал:

def all_members
   members << owner
end

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

def all_members
   [owner, members]
end

этот тип работает, но возвращает вложенный массив, к которому трудно получить правильный доступ.

  scope :all_members, joins(:members).merge(:owner)

это не работает вообще. Наверное ерунда.

  def all_members
     members_array = members.dup
     members_array << owner
  end

Это все еще постоянно изменяет членов, включая владельца? !!

Помощь! (Спасибо)

Ответы [ 2 ]

0 голосов
/ 07 ноября 2018

Если достаточно вернуть массив, тогда вы можете просто использовать:

def all_members
  [owner] + members
end

Если вам нужно отношение, то самый простой (но не самый эффективный) подход будет:

def all_members
  User.where(id: [owner] + members.ids)
end

Это не самый эффективный вариант, поскольку генерируемый SQL может содержать довольно большой оператор IN, который не может быть эффективно кэширован анализатором базы данных. Тем не менее, если числа находятся в диапазоне нескольких десятков, этого было бы достаточно даже для этого трюка с отношениями.

0 голосов
/ 07 ноября 2018

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

If Rails 5

def all_members
  # not sure if you could just do 
  # owner.or(members) since they are both User 
  # but it seems unlikely due to the join table 
  User.where(id: self.owner_id).or(
    User.where(id: organisation_users.select(:user_id))
  )
end 

Все версии Rails (кроме Rails 5 включительно) мы можем использовать Arel для построения более сложного запроса

def all_members
  user_table = User.arel_table   
  User.where(
    users_table[:id].eq(self.owner_id).or(
       users_table[:id].in(
         organisation_users.select(:user_id).arel
       )
    )
  ) 
end 

оба приведут к следующему SQL

SELECT users.* 
FROM users 
WHERE 
  (users.id = [YOUR_OWNER_ID] OR 
   users.id IN (
     SELECT organisations_users.user_id 
     FROM organisations_users
     WHERE organisations_users.organisation_id = [YOUR_ORGANISATION_ID]
  ))

конечный результат будет ActiveRecord::Relation из User объектов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...