2

クライアントがクエリ パラメータを使用して記事を検索できるようにする Web サービスがあります。パラメータが 1 つだけ含まれている場合は正常に機能しますが、 と を組み合わせるsearch_queryと 失敗しますcategory。これは、for_categoryが見つかったComfort_Mexican_Sofaに基づいています。orderステートメントを削除しても、このエラーが発生します。

エラー

PG::InvalidColumnReference: エラー: SELECT DISTINCT の場合、ORDER BY 式を選択リストに含める必要があります 行 1: ...ms_categories"."label" = 'Company News' ORDER BY pg_search_... ^ : SELECT DISTINCT "comfy_cms_pages". * FROM "comfy_cms_pages" INNER JOIN "comfy_cms_categorizations" ON "comfy_cms_categorizations"."categorized_id" = "comfy_cms_pages"."id" AND "comfy_cms_categorizations"."categorized_type" = $1 INNER JOIN "comfy_cms_categories" ON "comfy_cms_categorizations"."." "comfy_cms_categorizations"."category_id" INNER JOIN (SELECT "comfy_cms_pages"."id" AS pg_search_id,(ts_rank((to_tsvector('simple', 合体("comfy_cms_pages"."content_cache"::text, '')) || to_tsvector('simple', 合体("comfy_cms_pages"."label"::text, '') ))), (to_tsquery('simple', ''' ' || 'オースティン' || ' ''' || ':')), 0)) AS ランク FROM "comfy_cms_pages" WHERE (((to_tsvector('simple', 合体 ("comfy_cms_pages"."content_cache"::text, '')) || to_tsvector('simple', 合体( "comfy_cms_pages"."label"::text, ''))) @@ (to_tsquery('simple', ''' ' || 'austin' || ' ''' || ': '))))) pg_search_comfy_cms_pages ON "comfy_cms_pages"."id" = pg_search_comfy_cms_pages.pg_search_id WHERE (layout_id = '1' AND is_published = 't') AND "comfy_cms_categories"."label" = '企業ニュース' ORDER BY pg_search_comfy_cms_pages.rank DESCcms_comfy_ ."id" ASC、"comfy_cms_pages"."created_at" DESC

アプリ/モデル/記事.rb

class Article < Comfy::Cms::Page
  cms_is_categorized
  include PgSearch


  pg_search_scope :search_by_keywords, against: [:content_cache, :label], using: { tsearch: { any_word: true, prefix: true } }

app/commands/search_articles_command.rb

class SearchArticlesCommand
  def initialize(params = {})
    @since = params[:since_date]
    @keys = params[:search_query]
    @category = params[:category]
  end

  def execute
    Article.unscoped do
      query = if @since.present?
                Article.article.since_date(@since)
              else
                Article.published_article
              end
      query = query.for_category(@category) if @category.present?
      query = query.search_by_keywords(@keys) if @keys.present?
      query.where('').order(created_at: :desc)
    end
  end
end

快適なメキシカンソファ/lib/comfortable_mexican_sofa/extensions/is_categorized.rb

module ComfortableMexicanSofa::IsCategorized

  def self.included(base)
    base.send :extend, ClassMethods
  end

  module ClassMethods
    def cms_is_categorized
      include ComfortableMexicanSofa::IsCategorized::InstanceMethods

      has_many :categorizations,
        :as         => :categorized,
        :class_name => 'Comfy::Cms::Categorization',
        :dependent  => :destroy
      has_many :categories,
        :through    => :categorizations,
        :class_name => 'Comfy::Cms::Category'

      attr_accessor :category_ids

      after_save :sync_categories

      scope :for_category, lambda { |*categories|
        if (categories = [categories].flatten.compact).present?
          self.distinct.
            joins(:categorizations => :category).
            where('comfy_cms_categories.label' => categories)
        end
      }
    end
  end

  module InstanceMethods
    def sync_categories
      (self.category_ids || {}).each do |category_id, flag|
        case flag.to_i
        when 1
          if category = Comfy::Cms::Category.find_by_id(category_id)
            category.categorizations.create(:categorized => self)
          end
        when 0
          self.categorizations.where(:category_id => category_id).destroy_all
        end
      end
    end
  end
end

ActiveRecord::Base.send :include、ComfortableMexicanSofa::IsCategorized

更新されたエラー

PG::SyntaxError: ERROR:  syntax error at or near "."
LINE 4: ...e = 'Class' AND categorized_id = 'comfy_cms_pages'.'id' AND ...
                                                             ^
: SELECT "comfy_cms_pages".* FROM "comfy_cms_pages" INNER JOIN (SELECT "comfy_cms_pages"."id" AS pg_search_id, (ts_rank((to_tsvector('simple', coalesce("comfy_cms_pages"."content_cache"::text, '')) || to_tsvector('simple', coalesce("comfy_cms_pages"."label"::text, ''))), (to_tsquery('simple', ''' ' || 'austin' || ' ''' || ':*')), 0)) AS rank FROM "comfy_cms_pages" WHERE (((to_tsvector('simple', coalesce("comfy_cms_pages"."content_cache"::text, '')) || to_tsvector('simple', coalesce("comfy_cms_pages"."label"::text, ''))) @@ (to_tsquery('simple', ''' ' || 'austin' || ' ''' || ':*'))))) pg_search_comfy_cms_pages ON "comfy_cms_pages"."id" = pg_search_comfy_cms_pages.pg_search_id WHERE "comfy_cms_pages"."layout_id" = $1 AND "comfy_cms_pages"."is_published" = $2 AND (
        EXISTS (
          SELECT 1 FROM categorizations
          WHERE categorized_type = 'Class' AND categorized_id = 'comfy_cms_pages'.'id' AND category_id IN (2)
        ))  ORDER BY pg_search_comfy_cms_pages.rank DESC, "comfy_cms_pages"."id" ASC

有効なソリューションですが、スコープではなく、呼び出される順序に注意する必要があります

  def self.for_category(_category)
    Comfy::Cms::Categorization.includes(:category).references(:category).select(:categorized).pluck(:categorized_id)
    find(ids)
  end
4

2 に答える 2

2

for_categoryCMS の組み込みフィルターをオーバーライドするのが最善だと思います。そのクエリの結合が多すぎます。

次のようにオーバーライドfor_categoryします。

scope :for_category, lambda { |*categories|
  if (categories = [categories].flatten.compact).present?
    self_ids = "{connection.quote_table_name(self.table_name)}.#{connection.quote_column_name(self.primary_key)}"
    self.where(
      "EXISTS (" +
        Comfy::Cms::Categorization.select('1').
          where(categorized_type: self.name).
          where('categorized_id' => self_ids).
          where(category_id: Comfy::Cms::Category.where(label: categories).pluck(:id)).to_sql +
      ")"
    )
  end
}

Railsでの SQLEXISTSの使用法について詳しくは、私のRails: SQL EXISTS brief how-to を参照してください。

そのエラーにぶつかる理由の詳細については、質問を読んでここで答えることができます。

具体的にpg_searchは、結果をランク順に並べたいと考えています。記事の個別のフィールドのみを選択し、for_category検索ランクは気にしません。EXISTS複雑なクエリではなく単純なクエリを使用するようにコードを変更すると、それJOINが修正されます。

于 2015-08-27T14:19:50.690 に答える