11

Rails 3.2.9
を使用して、所有者のいない組織に関連付けられているアイテムのリストを取得しようとしています。

以下を使用して配列リストを取得できましたが、私には醜いようです。これを行うより良い方法はありますか?

Items.all(:select => "items.id, items.name",
  :joins => "INNER JOIN organizations on items.organization_id = organizations.id",
  :conditions => "NOT EXISTS (select * from items k JOIN items_owners on items.id = items_owners.item_id) and items.organization_id = 1")

テーブルのセットアップ:
所有者:

  • ID
  • 名前

アイテム:

  • ID
  • 名前
  • 組織ID

アイテム所有者:

  • owner_id
  • item_id

組織:

  • ID
  • リスト項目

モデル:

class Organization < ActiveRecord::Base
   attr_accessible :name

   has_many :items
end

class Item < ActiveRecord::Base
   attr_accessible :description, :name, :owner_ids, :organization_id

   has_many :items_owner
   has_many :owners, :through => :items_owner
   belongs_to :organization
end

class Owner < ActiveRecord::Base
   attr_accessible :name

   has_many :items_owner
   has_many :items, :through => :items_owner
end

class ItemsOwner < ActiveRecord::Base
   attr_accessible :owner_id, :item_id

   belongs_to :item
   belongs_to :owner
end
4

3 に答える 3

10

編集:の削除.all、追加references、および追加の使用arel_table

Items.joins(:organization).includes(:owners).references(:owners).
  where('owners.id IS NULL')

そして、両方に使用したい場合includes

Items.includes(:organization, :owners).references(:organization, :owners).
  where('organisations.id IS NOT NULL AND owners.id IS NULL')

そして、@Dario Barrionuevo が書いたように、それは Item の belongs_to :organisation でなければなりません

最初の例での使用arel_table:

Items.joins(:organization).includes(:owners).references(:owners).
  where(Owner.arel_table[:id].eq(nil))

Rails 5 の場合 (@aNoble のコメントから):

Items.joins(:organization).left_joins(:owners).
  where(Owner.arel_table[:id].eq(nil))

ただしincludes、余分な読み取りを避けるために、リレーションをコードで参照する必要がある場合は、使用することをお勧めします。

于 2012-11-21T16:00:13.477 に答える
4

レール 5、6 で NOT EXISTS を実行する方法はいくつかあります。

  1. item_owners.id が nullの個別のアイテムOUTER JOIN item_owners
  2. items.id NOT IN (item_owners から item_id を選択)
  3. NOT EXISTS (item_id = items.id の item_owners から 1 を選択)
  4. where ( item_owners where item_id = items.id) = 0 からCOUNT (*) を選択

頭から離れて 4 つのアプローチを思いつくことができますが、7 つあったことを覚えているようです。

NOT IN アプローチを使用することが、私のチームが作成および維持するのに最も簡単であることがわかりました。私たちの目標は、arel を回避し、所有者テーブル (例: admin owner) で WHERE 句をサポートし、複数レベルの rails :through をサポートすることでした。

Items.where.not(id: Items.joins(:owners).select(:id))
     .select(:id, :name)

Items.where.not(id: Items.joins(:items_owners).select(:id))
     .select(:id, :name)

Items.where.not(id: ItemOwners.select(:item_id))

最初のものを使用しますが、これらの例は、最適化されていないものから最適化されたものの順に並べる必要があります。また、モデルの知識が最も少ないものから順に並べてあります。

于 2020-10-19T22:40:15.830 に答える
-1

これを試して

Items.joins(:organisations).where(Items.joins(:items_owners).exists.not).select('items.id,items.name')
于 2012-11-21T15:37:07.357 に答える