2017-05-03 12 views
0

多相の関係で、複数のオブジェクトを単一のクエリで取得する必要があります。Rails 5:多相関係を介して複数のオブジェクトを取得する

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 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 Company < ApplicationRecord 
    has_many :accounts, dependent: :destroy 
    has_many :users, through: :accounts 
    has_many :medias, class_name: 'Media::Medias', inverse_of: :company 
end 

はどのようにして、各メディアのcurrent_userと企業のために、すべてのマスコミのためActiveRecord::Relation objectを返すのですか?それは、Permissionモデルを通して関係を使用しなければならないことが重要です、私はAccountsを通して企業を得るべきではありません。今のところ私はcurrent_userのすべてのメディアを取得するためにCurrent.user.mediasを使用できるようにモデルを設定しました。

ありがとうございました!ここで

更新

は私が試したいくつかのバージョンから得たものである:

[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

012あなたのUserクラスの関連を追加
[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

あなたは 'current_user.medias.includesのために何を得るのです(:企業)'? –

+0

@ Md.FarhanMemon私はこれをコンソールで見る: '[2] pry(main)> user.medias.includes(:companies) Media ::メディアロード(1.6ms)SELECT" media_medias "。* FROM" media_medias "INNER "user_id" = $ 1 AND "permissions"。 "permitable_type" = $ 2 [["" user_id "、2]、[ "Allowable_type"、 "Media :: Medias"]] =># ' – matiss

+0

@ Md.FarhanMemonそれは私の望む結果を与えてくれるとは思わない+私は両方を取り戻す必要がある - メディアと企業。 – matiss

答えて

1

この問題を解決するには、モデル名と関連付けに複数の/特異な要素が混在しているように見えるか、少なくとも大きな問題があるように見えます。一般的に:

  1. モデル名は単数形です。この場合、「媒体」は単数であり、「媒体」は複数である。
  2. モデルでアソシエーション構成を使用する場合、「has_many」は通常複数の値を取るが、「belongs_to」は単数をとる。したがって、has_many :companiesbelongs_to :userが必要です。
  3. 下位のテーブル名は複数です。したがって、「中」モデルは「メディア」テーブルに基づいています。

私は単純なRailsアプリケーションを作成しましたが、これは上記のコードの最小限の動作例です。 「アカウント」モデルはここには表示されないので、私は会社のモデルから対応する要素を削除しました。逆の関連付けも追加しました。テストデータと

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">]> 

はちょうどあなたのモデル名が正しい取得することを確認し、それが動作するはずです。サンプル・コードは、ここからダウンロードすることができる。

https://github.com/mdchaney/so_43765182

+1

ありがとう、これは助けます!私はあなたの提案と[Rails docs](http://guides.rubyonrails.org/active_record_basics.html#naming-conventions)に従って私のモデル、テーブル、カラムを改訂しました。それはうまく動作し、素敵に見えます:) Railsコミュニティは最高です! – matiss

0

試してみてください。

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関連を持っているので、あなたが使用することを検討すべきですMedia::Mediasクラスの単数belongs_to :companyあなたがそれを行う場合

、あなたがあることを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 
+0

ありがとうございます!私は、1)企業を会社に、2)メディア::メディアをメディア::メディアに変更した@MichaelChaneyが提案した。私は今会社を取り戻す。ユーザーのためにメディアを入手するにはどうすればいいですか? – matiss

+0

私はそれを得ました - 'User.find(2).media.includes(:company)'は今うまく動作します:) – matiss

関連する問題