Область для множественных отношений - PullRequest
0 голосов
/ 17 апреля 2020

В моей ситуации пользователь может быть владельцем многих проектов (User.projects) или участником многих проектов (User.projects_as_member). Я ищу возможность получить все проекты, владельцем которых является пользователь или член.

class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

  has_many :projects
  has_and_belongs_to_many :projects_as_member,
                          class_name: 'Project',
                          join_table: "members_projects",
                          foreign_key: "users_id",
                          association_foreign_key: "projects_id"
end
class Project < ApplicationRecord
  include ActivityRecorder
  belongs_to :user
  has_many :tasks
  has_many :activities, -> { order(created_at: :desc) }
  has_many :subjects, -> { order(created_at: :desc) }, as: 'subject'
  has_and_belongs_to_many :members,
                          class_name: 'User',
                          join_table: "members_projects",
                          foreign_key: "projects_id",
                          association_foreign_key: "users_id"

  validates_presence_of :title, :description, :user

  def invite(user)
    self.members << user unless self.members.include?(user)
  end
end
  create_table "projects", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci", force: :cascade do |t|
    t.string "title"
    t.string "description"
    t.bigint "user_id"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.string "notes"
    t.index ["user_id"], name: "index_projects_on_user_id"
  end

  create_table "users", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci", force: :cascade do |t|
    t.string "username", default: "", null: false
    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.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.index ["email"], name: "index_users_on_email", unique: true
    t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
  end

  create_table "members_projects", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci", force: :cascade do |t|
    t.bigint "projects_id"
    t.bigint "users_id"
    t.index ["projects_id"], name: "index_members_projects_on_projects_id"
    t.index ["users_id"], name: "index_members_projects_on_users_id"
  end

Я предполагаю область действия Метод - это способ сделать это, но я не уверен, как мне справиться с множественными отношениями.

1 Ответ

1 голос
/ 17 апреля 2020

Самое простое решение:

Project.where(user: user)
       .or(Project.where(id: user.projects_as_member))

Это создает подзапрос:

SELECT "projects".*
FROM   "projects"
WHERE  ( "projects"."user_id" = $1
          OR "projects"."id" IN (SELECT "projects"."id"
                                 FROM   "projects"
                                        INNER JOIN "members_projects"
                                                ON "projects"."id" =
"members_projects"."projects_id"
WHERE  "members_projects"."users_id" = $2) )
LIMIT  $3  
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...