更新后 Rails 损坏的查询 Arel::Visitors::UnsupportedVisitError而是构建一个 Arel 节点

问题描述

带有 PostgreSQL 数据库的 Ruby on Rails 应用程序 有一个用 Arel 5.x 构造的搜索查询类:

class Sample

  def url
    audio_url.gsub(self.class.to_s.underscore,'user_profile_audio_sample') if audio_url
  end

  class << self

    def search(query={},app_id='pv',page=1,per_page=20)
      arel = tables.project(
        profile_table[:id].as('profile_id'),audio_table[:id].as('id'),audio_table[:age].as('age'),audio_table[:audio].as('audio'),web_site_language_table[:name].as('language_name'),audio_categories_table[:name].as('category_name'),audio_categories_table[:identifier].as('category_identifier'),profile_table[:full_name].as('full_name'),profile_table[:nickname].as('nickname'),profile_table[:gender].as('gender')
        ).
          where(profile_query).
          where(genders_query(query)).
          where(ages_query(query)).
          where(categories_query(query)).
          where(languages_query(query)).
          where(website_query(app_id)).
          where(audios_query).
          where(audios_published).
          order(profile_table[:id].desc)

      sql = arel.to_sql.gsub(/SELECT/,'\\0 DISTINCT ON (1)')

      paginate_by_sql(sql,page: page,per_page: per_page)
    end

    protected

    def profile_query
      profile_table[:nickname].not_eq(nil)
    end

    def audios_query
      audio_table[:id].not_eq(nil)
    end

    def audios_published
      audio_table[:published].eq(true)
    end

    def languages_query(query={})
      if valid_query_param? query[:languages]
        audio_web_site_language_table[:web_site_language_id].in(query[:languages].select &:present?)
      else
        true
      end
    end

    def website_query(app_id)
      web_sites_table[:app_id].eq(app_id)
    end

    def categories_query(query)
      if valid_query_param? query[:categories]
        audio_table[:audio_category_id].in(query[:categories].select &:present?)
      else
        true
      end
    end

    def ages_query(query)
      if valid_query_param? query[:ages]
        audio_table[:age].in(query[:ages].select &:present?)
      else
        true
      end
    end

    def genders_query(query)
      if valid_query_param? query[:genders]
        profile_table[:gender].in(query[:genders].select &:present?)
      else
        true
      end
    end

    def valid_query_param?(name)
      name.present? && !name.select(&:present?).empty?
    end

    def tables
      profile_table \
      .join(audio_table,Arel::Nodes::OuterJoin) \
      .on(profile_table[:id].eq(audio_table[:user_profile_id])) \
      .join(audio_categories_table,Arel::Nodes::OuterJoin) \
      .on(audio_table[:audio_category_id].eq(audio_categories_table[:id])) \
      .join(audio_web_site_table,Arel::Nodes::OuterJoin) \
      .on(audio_table[:id].eq(audio_web_site_table[:audio_id])) \
      .join(audio_web_site_language_table,Arel::Nodes::OuterJoin) \
      .on(audio_web_site_table[:id].eq(audio_web_site_language_table[:audio_web_site_id]))  \
      .join(web_site_language_table,Arel::Nodes::OuterJoin) \
      .on(audio_web_site_language_table[:web_site_language_id].eq(web_site_language_table[:id])) \
      .join(web_sites_table,Arel::Nodes::OuterJoin) \
      .on(web_site_language_table[:web_site_id].eq(web_sites_table[:id]))
    end

    def profile_table
      Arel::Table.new(:user_profiles)
    end

    def audio_table
      Arel::Table.new(:user_profile_audio_samples)
    end

    def audio_web_site_table
      Arel::Table.new(:user_profile_audio_sample_web_sites)
    end

    def audio_web_site_language_table
      Arel::Table.new(:user_profile_audio_sample_web_site_languages)
    end

    def web_site_language_table
      Arel::Table.new(:web_site_languages)
    end

    def audio_categories_table
      Arel::Table.new(:audio_categories)
    end

    def web_sites_table
      Arel::Table.new(:web_sites)
    end

  end

end

生成的 SQL 是:

SELECT DISTINCT ON (1) 
"user_profiles"."id" AS profile_id,"user_profile_audio_samples"."id" AS id,"user_profile_audio_samples"."age" AS age,"user_profile_audio_samples"."audio" AS audio,"web_site_languages"."name" AS language_name,"audio_categories"."name" AS category_name,"audio_categories"."identifier" AS category_identifier,"user_profiles"."full_name" AS full_name,"user_profiles"."nickname" AS nickname,"user_profiles"."gender" AS gender 
FROM "user_profiles" 
LEFT OUTER JOIN "user_profile_audio_samples" ON "user_profiles"."id" = "user_profile_audio_samples"."user_profile_id" 
LEFT OUTER JOIN "audio_categories" ON "user_profile_audio_samples"."audio_category_id" = "audio_categories"."id" 
LEFT OUTER JOIN "user_profile_audio_sample_web_sites" ON "user_profile_audio_samples"."id" = "user_profile_audio_sample_web_sites"."audio_id" 
LEFT OUTER JOIN "user_profile_audio_sample_web_site_languages" ON "user_profile_audio_sample_web_sites"."id" = "user_profile_audio_sample_web_site_languages"."audio_web_site_id" 
LEFT OUTER JOIN "web_site_languages" ON "user_profile_audio_sample_web_site_languages"."web_site_language_id" = "web_site_languages"."id" 
LEFT OUTER JOIN "web_sites" ON "web_site_languages"."web_site_id" = "web_sites"."id" 
WHERE "user_profiles"."nickname" IS NOT NULL AND 't' AND 't' AND 't' AND 't' AND "web_sites"."app_id" = 'pv' AND "user_profile_audio_samples"."id" IS NOT NULL AND "user_profile_audio_samples"."published" = 't'  
ORDER BY "user_profiles"."id" DESC 
LIMIT 20 OFFSET 0

升级到 Rails 6.1 后,我开始收到错误消息: Arel::Visitors::UnsupportedVisitError:不支持的参数类型:TrueClass。而是构建一个 Arel 节点。 我相信它与 audios_published 方法有关。我尝试使用 Arel::Node::Binary 和 Arel::Node::Quoted 但我没有足够的了解我需要使用哪些 Arel 类。另外我认为其他方法需要类似的更改,而不仅仅是audios_published。 将查询返回到与升级前相同的状态的模式是什么?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...