0

私はアプリの小さなバグに取り組んでおり、ここで単純化しようとしています。

私はこの会社モデルを持っています (実際のモデルにはさらに多くの関連付けがありますが、ここに問題が表示されます):

class Company < ActiveRecord::Base
  has_many :contacts

  def self.search(query, page=1)
    companies = includes(:contacts).order("companies.name ASC")

    if query.present?
      companies = companies.where(%(
        companies.name ILIKE :q,
        OR contacts.name ILIKE :q
      ), q: "%#{query}%")
    end

    companies.paginate(page: page)
  end
end

現在、これはほとんどうまく機能しています。唯一の問題は、会社に 2 つ以上の連絡先があり、ユーザーが連絡先の名前の 1 つに基づいて検索する場合です。会社が正しく検出され、オートコンプリート UI に会社が表示されます。ただし、ユーザーがオートコンプリートから会社を選択すると、ドロップダウン リストから連絡先を選択できるはずですが、ドロップダウンにはフィルターで絞り込んだ 1 つの連絡先しか含まれません。会社は検索基準に基づいてフィルタリングする必要がありますが、そのドロップダウンには、ユーザーが選択できる会社の連絡先がすべて含まれている必要があります。

なぜこれを行っているのかはわかっています。それは、クエリが実行された瞬間にレールがすべての関連付けを自動ロードして、すべての関連付けプロパティ取得し、同時にすべての条件を含めることができるためです。

それはselect {every_attribute_from_every_included_table} left outer join {all_included_tables}一種のクエリを実行していますが、私がやりたいのはこれです:

select companies.* from companies
left outer join contacts <and other included tables> on <join criteria>
where <filter criteria>

次の企業をフィルタリングするには:

select contacts.* from contacts
where company_id IN (<company_ids from previous query>)

includeテーブルもwhere句に含まれていない場合、通常はどのようにエントリが含まれますか。

Rails はここでマジックを使いすぎているので、特別なマジックではなく、通常のマジックに戻してほしいです! どうやってやるの?または、私が達成しようとしていることを達成するためのより良い方法は何ですか (連絡先名に基づいてフィルタリングしますが、呼び出し時に他の連絡先が含まれるのを止めないでくださいcompany.contacts)。

4

2 に答える 2

1

さて、あなたが望むようにクエリをしましょう

select companies.* from companies
left outer join contacts <and other included tables> on <join criteria>
where <filter criteria>

手動で上書きしましょう.joins(...)

Company.includes(:contacts).
        joins("left outer join contacts c on c.company_id = companies.id").
        where(...)

これにより、:contactsリレーションはそのまま残り、代わりに同じcontactsテーブルの別の「エイリアス」に結合されます。

于 2013-06-10T23:19:47.073 に答える
0

2 つのクエリが必要であることがわかりました。

  • 会社を選択するための1つ(または複数の会社)
  • (選択された)会社の連絡先を選択するためのもの

Rails マジックを使用すると、以下を使用して会社を選択できますjoins

@companies = Company.joins(:contacts).where(...).uniq

与えるSELECT DISTINCT "companies".* FROM "companies" INNER JOIN "contacts" ON ... WHERE (...)

次に、特定の会社のすべての連絡先を取得します。

company= @companies.first
@contacts = company.contacts
于 2013-06-10T22:25:25.010 に答える