组合搜索范围时出错

时间:2015-08-21 20:17:05

标签: ruby-on-rails ruby postgresql named-scope comfortable-mexican-sofa

我有一个网络服务,允许客户搜索带有查询参数的文章。如果只包含一个参数,但如果我合并search_querycategory则会失败。这基于Comfortable_Mexican_Sofa,其中找到了for_category。即使我删除order语句,我也会收到此错误。

错误

  

PG :: InvalidColumnReference:ERROR:用于SELECT DISTINCT,ORDER BY   表达式必须出现在选择列表LINE 1中:   ... ms_categories""标签" ='公司新闻'订购者pg_search _...                                                                ^:SELECT DISTINCT" comfy_cms_pages"。* FROM" comfy_cms_pages"内部联接   " comfy_cms_categorizations"上   #&34; comfy_cms_categorizations"" categorized_id" =" comfy_cms_pages"。" id"   AND" comfy_cms_categorizations"。" classifiedized_type" = $ 1 INNER JOIN   " comfy_cms_categories" ON" comfy_cms_categories"。" id" =   #&34; comfy_cms_categorizations"" CATEGORY_ID"内部联接(选择   " comfy_cms_pages"" ID" AS pg_search_id,   (ts_rank((to_tsvector('简单&#39 ;,   合并(" comfy_cms_pages"。" content_cache" :: text,''))||   to_tsvector('简单',合并(" comfy_cms_pages"。"标签" ::文字,''))),   (to_tsquery('简单',''' ||'奥斯汀' ||''&# 39;' ||':')),0))AS   排名来自" comfy_cms_pages"在哪里((to totsvector(' simple',   合并(" comfy_cms_pages"。" content_cache" :: text,''))||   to_tsvector('简单',合并(" comfy_cms_pages"。"标签" ::文字,'')))   @@(to_tsquery('简单','''' ||'奥斯汀' ||'' '' ||':')))))   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')和" comfy_cms_categories"。"标签" ='公司   新闻'订购者:pg_search_comfy_cms_pages.rank DESC,   " comfy_cms_pages"" ID" ASC," comfy_cms_pages"。" created_at" DESC

应用程序/模型/ article.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 } }

应用程序/指令/ 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 /扩展/ 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

2 个答案:

答案 0 :(得分:2)

我认为最好覆盖CMS的for_category内置过滤器。该查询中的连接太多。

像这样覆盖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中SQL EXISTS用法的更多信息,请参阅我的Rails: SQL EXISTS brief how-to

有关您遇到错误的原因,请参阅question and answer here

具体而言,pg_search希望按排名对结果进行排序。并且for_category想要仅选择Article的不同字段,而不关心搜索等级。更改其代码以使用简单的EXISTS而不是复杂的JOIN查询将解决此问题。

答案 1 :(得分:0)

我能够通过将reorder应用于pg_search结果的结果来解决这个问题。

search_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 = Article.article
      query = if @since.present?
                query.since_date(@since)
              else
                query.published
              end
      query = query.for_category(@category) if @category.present?
      query = query.search_by_keywords(@keys).reorder('updated_at DESC') if @keys.present?
      query
    end
  end
end

我也覆盖了for_category (不是必需的)

article.rb

  scope :for_category, (lambda do |category|
    published
      .joins(:categories)
      .group(:id)
      .where('comfy_cms_categories.label' => category)
      .select('comfy_cms_pages.*')
  end)