我需要通过多态关系优先在单个查询中检索多个对象。
在用户模型中,我有:
class User < ApplicationRecord
has_many :companies, through: :accounts
has_many :permissions
has_many :medias, class_name: 'Media::Medias', through: :permissions,
source: :permitable, source_type: 'Media::Medias'
end
然后我的权限模型如下所示:
class Permission < ApplicationRecord
belongs_to :permitable, polymorphic: true
belongs_to :user, optional: true
end
媒体::媒体模型:
module Media
class Medias < ApplicationRecord
belongs_to :companies, optional: true, inverse_of: :medias
has_many :permissions, class_name: 'Permission', as: :permitable
has_many :users, through: :permissions
end
end
公司模式:
class Company < ApplicationRecord
has_many :accounts, dependent: :destroy
has_many :users, through: :accounts
has_many :medias, class_name: 'Media::Medias', inverse_of: :company
end
如何为ActiveRecord::Relation object
和每家媒体公司的所有媒体返回current_user
?重要的是,我必须通过Permission
使用关系模型,我不应该让公司通过Accounts
。到目前为止,我已经设置了模型,因此我可以使用Current.user.medias
来获取current_user
的所有媒体。
谢谢!
更新
以下是我尝试过的几个版本的内容:
[4] pry(main)> user.medias.includes(:companies).map{|media| media.companies.id }
Media::Medias Load (1.4ms) SELECT "media_medias".* FROM "media_medias" INNER JOIN "permissions" ON "media_medias"."id" = "permissions"."permitable_id" WHERE "permissions"."user_id" = $1 AND "permissions"."permitable_type" = $2 [["user_id", 2], ["permitable_type", "Media::Medias"]]
NameError: uninitialized constant Media::Medias::Companies
from /home/ubuntu/.rvm/gems/ruby-2.3.3/gems/activerecord-5.1.0/lib/active_record/inheritance.rb:166:in `compute_type'
[5] pry(main)> user.medias.preload(:companies).select(['medias.id', 'medias.company.id'])
Media::Medias Load (1.3ms) SELECT medias.id, medias.company.id FROM "media_medias" INNER JOIN "permissions" ON "media_medias"."id" = "permissions"."permitable_id" WHERE "permissions"."user_id" = $1 AND "permissions"."permitable_type" = $2 [["user_id", 2], ["permitable_type", "Media::Medias"]]
=> #<Media::Medias::ActiveRecord_AssociationRelation:0x33dd094>
[6] pry(main)> user.medias.select(['medias.id', 'medias.company_id'])
Media::Medias Load (1.1ms) SELECT medias.id, medias.company_id FROM "media_medias" INNER JOIN "permissions" ON "media_medias"."id" = "permissions"."permitable_id" WHERE "permissions"."user_id" = $1 AND "permissions"."permitable_type" = $2 [["user_id", 2], ["permitable_type", "Media::Medias"]]
=> #<Media::Medias::ActiveRecord_AssociationRelation:0x3413234>
更新2
[4] pry(main)> puts user.medias.preload(:companies).select(['medias.id', 'medias.company.id'])
Media::Medias Load (1.4ms) SELECT medias.id, medias.company.id FROM "media_medias" INNER JOIN "permissions" ON "media_medias"."id" = "permissions"."permitable_id" WHERE "permissions"."user_id" = $1 AND "permissions"."permitable_type" = $2 [["user_id", 2], ["permitable_type", "Media::Medias"]]
ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR: missing FROM-clause entry for table "medias"
LINE 1: SELECT medias.id, medias.company.id FROM "media_medias" INNE...
^
: SELECT medias.id, medias.company.id FROM "media_medias" INNER JOIN "permissions" ON "media_medias"."id" = "permissions"."permitable_id" WHERE "permissions"."user_id" = $1 AND "permissions"."permitable_type" = $2
from /home/ubuntu/.rvm/gems/ruby-2.3.3/gems/activerecord-5.1.0/lib/active_record/connection_adapters/postgresql_adapter.rb:620:in `async_exec'
[5] pry(main)> puts user.medias.select(['medias.id', 'medias.company_id'])
Media::Medias Load (1.2ms) SELECT medias.id, medias.company_id FROM "media_medias" INNER JOIN "permissions" ON "media_medias"."id" = "permissions"."permitable_id" WHERE "permissions"."user_id" = $1 AND "permissions"."permitable_type" = $2 [["user_id", 2], ["permitable_type", "Media::Medias"]]
ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR: missing FROM-clause entry for table "medias"
LINE 1: SELECT medias.id, medias.company_id FROM "media_medias" INNE...
^
: SELECT medias.id, medias.company_id FROM "media_medias" INNER JOIN "permissions" ON "media_medias"."id" = "permissions"."permitable_id" WHERE "permissions"."user_id" = $1 AND "permissions"."permitable_type" = $2
from /home/ubuntu/.rvm/gems/ruby-2.3.3/gems/activerecord-5.1.0/lib/active_record/connection_adapters/postgresql_adapter.rb:620:in `async_exec'
更新3
[1] pry(main)> User.find(2).medias.preload(:companies).select(['medias.id', 'medias.company.id'])
User Load (21.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 2], ["LIMIT", 1]]
Media::Medias Load (1.7ms) SELECT medias.id, medias.company.id FROM "media_medias" INNER JOIN "permissions" ON "media_medias"."id" = "permissions"."permitable_id" WHERE "permissions"."user_id" = $1 AND "permissions"."permitable_type" = $2 [["user_id", 2], ["permitable_type", "Media::Medias"]]
=> #<Media::Medias::ActiveRecord_AssociationRelation:0x17688f0>
[2] pry(main)> User.find(2).medias.select(['medias.id', 'medias.company_id'])
User Load (1.7ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 2], ["LIMIT", 1]]
Media::Medias Load (1.8ms) SELECT medias.id, medias.company_id FROM "media_medias" INNER JOIN "permissions" ON "media_medias"."id" = "permissions"."permitable_id" WHERE "permissions"."user_id" = $1 AND "permissions"."permitable_type" = $2 [["user_id", 2], ["permitable_type", "Media::Medias"]]
=> #<Media::Medias::ActiveRecord_AssociationRelation:0x2155d90>
答案 0 :(得分:1)
为了解决这个问题,看起来问题(或者至少是一个大问题)是模型名称和关联中复数/单数元素的混淆。一般来说:
has_many :companies
和belongs_to :user
。有了这个,我创建了一个简单的Rails应用程序,作为上述代码的最小工作示例。自&#34;帐户&#34;模型没有出现在这里我从公司模型中删除了相应的元素。我还添加了反向关联。
class User < ApplicationRecord
has_many :permissions, inverse_of: :user
has_many :media, class_name: 'Medium::Medium', through: :permissions, source: :permitable, source_type: 'Medium::Medium'
end
class Company < ApplicationRecord
has_many :media, class_name: 'Medium::Medium', inverse_of: :company
end
class Medium::Medium < ApplicationRecord
belongs_to :company, optional: true, inverse_of: :media
has_many :permissions, class_name: 'Permission', as: :permitable, inverse_of: :permitable
has_many :users, through: :permissions
end
class Permission < ApplicationRecord
belongs_to :permitable, polymorphic: true, inverse_of: :permissions
belongs_to :user, inverse_of: :permissions
end
包含测试数据的示例控制台会话:
2.2.7 :001 > Company.create(name: 'IBM')
(0.1ms) begin transaction
SQL (0.4ms) INSERT INTO "companies" ("name", "created_at", "updated_at") VALUES (?, ?, ?) [["name", "IBM"], ["created_at", "2017-05-05 19:11:49.017155"], ["updated_at", "2017-05-05 19:11:49.017155"]]
(0.5ms) commit transaction
=> #<Company id: 1, name: "IBM", created_at: "2017-05-05 19:11:49", updated_at: "2017-05-05 19:11:49">
2.2.7 :002 > User.create(name: 'Joe')
(0.0ms) begin transaction
SQL (0.8ms) INSERT INTO "users" ("name", "created_at", "updated_at") VALUES (?, ?, ?) [["name", "Joe"], ["created_at", "2017-05-05 19:11:59.401417"], ["updated_at", "2017-05-05 19:11:59.401417"]]
(2.3ms) commit transaction
=> #<User id: 1, name: "Joe", created_at: "2017-05-05 19:11:59", updated_at: "2017-05-05 19:11:59">
2.2.7 :003 > Medium::Medium.create(name: 'TV')
(0.0ms) begin transaction
SQL (0.2ms) INSERT INTO "medium_media" ("name", "created_at", "updated_at") VALUES (?, ?, ?) [["name", "TV"], ["created_at", "2017-05-05 19:12:11.453440"], ["updated_at", "2017-05-05 19:12:11.453440"]]
(2.0ms) commit transaction
=> #<Medium::Medium id: 1, company_id: nil, name: "TV", created_at: "2017-05-05 19:12:11", updated_at: "2017-05-05 19:12:11">
2.2.7 :004 > Medium::Medium.create(name: 'Newspaper')
(0.1ms) begin transaction
SQL (0.3ms) INSERT INTO "medium_media" ("name", "created_at", "updated_at") VALUES (?, ?, ?) [["name", "Newspaper"], ["created_at", "2017-05-05 19:12:18.433671"], ["updated_at", "2017-05-05 19:12:18.433671"]]
(2.0ms) commit transaction
=> #<Medium::Medium id: 2, company_id: nil, name: "Newspaper", created_at: "2017-05-05 19:12:18", updated_at: "2017-05-05 19:12:18">
2.2.7 :005 > user = User.first
User Load (0.3ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? [["LIMIT", 1]]
=> #<User id: 1, name: "Joe", created_at: "2017-05-05 19:11:59", updated_at: "2017-05-05 19:11:59">
2.2.7 :006 > user.permissions.create(permitable: Medium::Medium.first)
Medium::Medium Load (0.2ms) SELECT "medium_media".* FROM "medium_media" ORDER BY "medium_media"."id" ASC LIMIT ? [["LIMIT", 1]]
(0.0ms) begin transaction
SQL (0.2ms) INSERT INTO "permissions" ("permitable_type", "permitable_id", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?) [["permitable_type", "Medium::Medium"], ["permitable_id", 1], ["user_id", 1], ["created_at", "2017-05-05 19:12:50.694383"], ["updated_at", "2017-05-05 19:12:50.694383"]]
(0.5ms) commit transaction
=> #<Permission id: 1, permitable_type: "Medium::Medium", permitable_id: 1, user_id: 1, created_at: "2017-05-05 19:12:50", updated_at: "2017-05-05 19:12:50">
2.2.7 :007 > user = User.first
User Load (0.2ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? [["LIMIT", 1]]
=> #<User id: 1, name: "Joe", created_at: "2017-05-05 19:11:59", updated_at: "2017-05-05 19:11:59">
2.2.7 :008 > user.media
Medium::Medium Load (0.2ms) SELECT "medium_media".* FROM "medium_media" INNER JOIN "permissions" ON "medium_media"."id" = "permissions"."permitable_id" WHERE "permissions"."user_id" = ? AND "permissions"."permitable_type" = ? LIMIT ? [["user_id", 1], ["permitable_type", "Medium::Medium"], ["LIMIT", 11]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Medium::Medium id: 1, company_id: nil, name: "TV", created_at: "2017-05-05 19:12:11", updated_at: "2017-05-05 19:12:11">]>
2.2.7 :009 > user.media.includes(:company)
Medium::Medium Load (0.2ms) SELECT "medium_media".* FROM "medium_media" INNER JOIN "permissions" ON "medium_media"."id" = "permissions"."permitable_id" WHERE "permissions"."user_id" = ? AND "permissions"."permitable_type" = ? LIMIT ? [["user_id", 1], ["permitable_type", "Medium::Medium"], ["LIMIT", 11]]
=> #<ActiveRecord::AssociationRelation [#<Medium::Medium id: 1, company_id: nil, name: "TV", created_at: "2017-05-05 19:12:11", updated_at: "2017-05-05 19:12:11">]>
只需确保您的模型名称正确无误即可。示例代码可以在此处下载:
答案 1 :(得分:0)
尝试在User类上添加关联:
class User < ApplicationRecord
has_many :companies, through: :accounts
has_many :permissions
has_many :medias, class_name: 'Media::Medias', through: :permissions,
source: :permitable, source_type: 'Media::Medias'
has_many :media_companies, through: :medias, source: :companies
end
然后你应该能够做到:
User.find(2).media_companies
由于您在媒体与公司之间建立了belongs_to
关联,因此您应该考虑在belongs_to :company
课程中使用单数Media::Medias
。
如果您这样做,那么您可以将User
类中的关联修改为:
has_many :media_companies, through: :medias, source: :company
如果你想保持复数,那么你需要添加一个关联选项才能使它工作(避免NameError: uninitialized constant Media::Medias::Companies
错误):
module Media
class Medias < ApplicationRecord
belongs_to :companies, class_name: :Company, optional: true, inverse_of: :medias
...
end
end
虽然将它切换为单数会更常规:
belongs_to :company, optional: true, inverse_of: :medias