无法使用 Mobility 按 Rails 中已翻译的列进行排序
Unable to order by translated column in Rails using Mobility
此问题基于 issue post 移动 GitHub 项目。
上下文
- Rails: 5.0.6
- 移动性:0.4.2(使用 table 后端)
我正在处理支持多种文章类型的文章 table(例如,博客 post、案例研究、知识库文章)。此 table 包含一列,用于跟踪文章的查看次数 - 每次为文章调用 show
操作时递增的整数列。
在为这些文章实施翻译时,我想跟踪每个翻译的浏览量,而不是主要文章对象。为了实现这一目标,我将 views
属性 作为我对象的翻译属性之一:
class Article < ApplicationRecord
include Taggable
include PgSearch
translates :title, type: :string
translates :subtitle, type: :text
translates :body, type: :text
translates :views, type: :integer
multisearchable :against => [:title, :subtitle, :body]
has_and_belongs_to_many :products
attachment :hero_image, content_type: %w(image/jpeg image/png image/gif)
validates :title, :body, :posted_on, presence: true
scope :current, -> { where 'posted_on < ?', Date.tomorrow }
scope :news_articles, -> { where type: ['BlogPost', 'CaseStudy'] }
def log_view(by = 1)
self.views ||= 0
self.views += by
self.save(touch: false)
end
def to_param
"#{id} #{title}".parameterize
end
def published?
posted_on < Date.tomorrow
end
end
预期行为
在我的控制器中,我想列出查看次数最多的前十篇文章,这是我通过以下查询获得的:
@top_articles = Article.current.news_articles.order(views: :desc, posted_on: :desc).limit(10)
我希望收到一系列文章,就像我在实施移动性之前所做的那样。
实际行为
我得到的是 #<Article::ActiveRecord_Relation:0x233686c>
。如果我随后尝试将其转换为带有 @top_articles.to_a
的数组,我会收到此错误:
Article Load (0.7ms) SELECT "articles".* FROM "articles" WHERE (posted_on < '2018-02-11') AND "articles"."type" IN ('BlogPost', 'CaseStudy') ORDER BY "articles"."views" DESC, "articles"."posted_on" DESC LIMIT [["LIMIT", 10]]
ActiveRecord::StatementInvalid: PG::UndefinedColumn: ERROR: column articles.views does not exist
LINE 1: ...les"."type" IN ('BlogPost', 'CaseStudy') ORDER BY "articles"...
^
: SELECT "articles".* FROM "articles" WHERE (posted_on < '2018-02-11') AND "articles"."type" IN ('BlogPost', 'CaseStudy') ORDER BY "articles"."views" DESC, "articles"."posted_on" DESC LIMIT
from /usr/local/bundle/gems/activerecord-5.0.6/lib/active_record/connection_adapters/postgresql_adapter.rb:598:in `async_exec'
更改查询以包含 i18n
:
@top_articles = Article.i18n.current.news_articles.order(views: :desc, posted_on: :desc).limit(10)
…returns#<#<Mobility::Backends::ActiveRecord::Table::QueryMethods:0x00000000050a86d8>:0x286c3e0>
,当我尝试将其转换为数组时,我得到了同样的结果:
Article Load (0.7ms) SELECT "articles".* FROM "articles" WHERE (posted_on < '2018-02-11') AND "articles"."type" IN ('BlogPost', 'CaseStudy') ORDER BY "articles"."views" DESC, "articles"."posted_on" DESC LIMIT [["LIMIT", 10]]
ActiveRecord::StatementInvalid: PG::UndefinedColumn: ERROR: column articles.views does not exist
LINE 1: ...les"."type" IN ('BlogPost', 'CaseStudy') ORDER BY "articles"...
^
: SELECT "articles".* FROM "articles" WHERE (posted_on < '2018-02-11') AND "articles"."type" IN ('BlogPost', 'CaseStudy') ORDER BY "articles"."views" DESC, "articles"."posted_on" DESC LIMIT
from /usr/local/bundle/gems/activerecord-5.0.6/lib/active_record/connection_adapters/postgresql_adapter.rb:598:in `async_exec'
事实证明,虽然 Mobility 支持在 where
子句中使用翻译字段,但目前在 Active Record 查询的 order
子句中不支持它们。
解决方法尝试
1。在 order
子句
中引用翻译 table
根据 gem 作者的反馈,我尝试了查询:
Article.i18n.current.news_articles.order('article_translations.views desc', 'articles.posted_on desc')
… returns 一个 #<#<Mobility::Backends::ActiveRecord::Table::QueryMethods>>
对象,并且 to_a
returns 这个错误:
ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR: missing FROM-clause entry for table "article_translations"
LINE 1: ...les"."type" IN ('BlogPost', 'CaseStudy') ORDER BY article_tr...
^
: SELECT "articles".* FROM "articles" WHERE (posted_on < '2018-02-12') AND "articles"."type" IN ('BlogPost', 'CaseStudy') ORDER BY article_translations.views desc, articles.posted_on desc LIMIT
from /usr/local/bundle/gems/activerecord-5.0.6/lib/active_record/connection_adapters/postgresql_adapter.rb:598:in `async_exec'
2。为翻译 table
添加 joins
或 includes
子句
Article.i18n.joins(:article_translations).order('article_translations.views desc', 'articles.posted_on desc').limit(10)
此查询再次 returns 一个 #<#<Mobility::Backends::ActiveRecord::Table::QueryMethods>>
对象,并且 to_a
结果为:
ActiveRecord::ConfigurationError: Can't join 'Article' to association named 'article_translations'; perhaps you misspelled it?
from /usr/local/bundle/gems/activerecord-5.0.6/lib/active_record/associations/join_dependency.rb:231:in `find_reflection'
3。将 has_many :article_translations
添加到模型
向模型添加关系会引发此错误:
uninitialized constant Article::ArticleTranslation
所以……
接下来我应该尝试什么?
更新
从版本 0.8.0 开始支持按翻译属性排序/
只需这样做:
Article.i18n.current.news_articles.
order(:views => :desc, :'articles.posted_on' => :desc)
Mobility会搞定一切(不需要加入翻译table等)
原始答案
您是对的,您需要加入翻译 table,但该协会名为 translations
,而不是 article_translations
。
无论如何,有一个方法join_translations
加入翻译table,所以这个应该可以工作:
Article.i18n.
current.
news_articles.
join_translations.
order('article_translations.views desc', 'articles.posted_on desc')
此问题基于 issue post 移动 GitHub 项目。
上下文
- Rails: 5.0.6
- 移动性:0.4.2(使用 table 后端)
我正在处理支持多种文章类型的文章 table(例如,博客 post、案例研究、知识库文章)。此 table 包含一列,用于跟踪文章的查看次数 - 每次为文章调用 show
操作时递增的整数列。
在为这些文章实施翻译时,我想跟踪每个翻译的浏览量,而不是主要文章对象。为了实现这一目标,我将 views
属性 作为我对象的翻译属性之一:
class Article < ApplicationRecord
include Taggable
include PgSearch
translates :title, type: :string
translates :subtitle, type: :text
translates :body, type: :text
translates :views, type: :integer
multisearchable :against => [:title, :subtitle, :body]
has_and_belongs_to_many :products
attachment :hero_image, content_type: %w(image/jpeg image/png image/gif)
validates :title, :body, :posted_on, presence: true
scope :current, -> { where 'posted_on < ?', Date.tomorrow }
scope :news_articles, -> { where type: ['BlogPost', 'CaseStudy'] }
def log_view(by = 1)
self.views ||= 0
self.views += by
self.save(touch: false)
end
def to_param
"#{id} #{title}".parameterize
end
def published?
posted_on < Date.tomorrow
end
end
预期行为
在我的控制器中,我想列出查看次数最多的前十篇文章,这是我通过以下查询获得的:
@top_articles = Article.current.news_articles.order(views: :desc, posted_on: :desc).limit(10)
我希望收到一系列文章,就像我在实施移动性之前所做的那样。
实际行为
我得到的是 #<Article::ActiveRecord_Relation:0x233686c>
。如果我随后尝试将其转换为带有 @top_articles.to_a
的数组,我会收到此错误:
Article Load (0.7ms) SELECT "articles".* FROM "articles" WHERE (posted_on < '2018-02-11') AND "articles"."type" IN ('BlogPost', 'CaseStudy') ORDER BY "articles"."views" DESC, "articles"."posted_on" DESC LIMIT [["LIMIT", 10]]
ActiveRecord::StatementInvalid: PG::UndefinedColumn: ERROR: column articles.views does not exist
LINE 1: ...les"."type" IN ('BlogPost', 'CaseStudy') ORDER BY "articles"...
^
: SELECT "articles".* FROM "articles" WHERE (posted_on < '2018-02-11') AND "articles"."type" IN ('BlogPost', 'CaseStudy') ORDER BY "articles"."views" DESC, "articles"."posted_on" DESC LIMIT
from /usr/local/bundle/gems/activerecord-5.0.6/lib/active_record/connection_adapters/postgresql_adapter.rb:598:in `async_exec'
更改查询以包含 i18n
:
@top_articles = Article.i18n.current.news_articles.order(views: :desc, posted_on: :desc).limit(10)
…returns#<#<Mobility::Backends::ActiveRecord::Table::QueryMethods:0x00000000050a86d8>:0x286c3e0>
,当我尝试将其转换为数组时,我得到了同样的结果:
Article Load (0.7ms) SELECT "articles".* FROM "articles" WHERE (posted_on < '2018-02-11') AND "articles"."type" IN ('BlogPost', 'CaseStudy') ORDER BY "articles"."views" DESC, "articles"."posted_on" DESC LIMIT [["LIMIT", 10]]
ActiveRecord::StatementInvalid: PG::UndefinedColumn: ERROR: column articles.views does not exist
LINE 1: ...les"."type" IN ('BlogPost', 'CaseStudy') ORDER BY "articles"...
^
: SELECT "articles".* FROM "articles" WHERE (posted_on < '2018-02-11') AND "articles"."type" IN ('BlogPost', 'CaseStudy') ORDER BY "articles"."views" DESC, "articles"."posted_on" DESC LIMIT
from /usr/local/bundle/gems/activerecord-5.0.6/lib/active_record/connection_adapters/postgresql_adapter.rb:598:in `async_exec'
事实证明,虽然 Mobility 支持在 where
子句中使用翻译字段,但目前在 Active Record 查询的 order
子句中不支持它们。
解决方法尝试
1。在 order
子句
中引用翻译 table
根据 gem 作者的反馈,我尝试了查询:
Article.i18n.current.news_articles.order('article_translations.views desc', 'articles.posted_on desc')
… returns 一个 #<#<Mobility::Backends::ActiveRecord::Table::QueryMethods>>
对象,并且 to_a
returns 这个错误:
ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR: missing FROM-clause entry for table "article_translations"
LINE 1: ...les"."type" IN ('BlogPost', 'CaseStudy') ORDER BY article_tr...
^
: SELECT "articles".* FROM "articles" WHERE (posted_on < '2018-02-12') AND "articles"."type" IN ('BlogPost', 'CaseStudy') ORDER BY article_translations.views desc, articles.posted_on desc LIMIT
from /usr/local/bundle/gems/activerecord-5.0.6/lib/active_record/connection_adapters/postgresql_adapter.rb:598:in `async_exec'
2。为翻译 table
添加joins
或 includes
子句
Article.i18n.joins(:article_translations).order('article_translations.views desc', 'articles.posted_on desc').limit(10)
此查询再次 returns 一个 #<#<Mobility::Backends::ActiveRecord::Table::QueryMethods>>
对象,并且 to_a
结果为:
ActiveRecord::ConfigurationError: Can't join 'Article' to association named 'article_translations'; perhaps you misspelled it?
from /usr/local/bundle/gems/activerecord-5.0.6/lib/active_record/associations/join_dependency.rb:231:in `find_reflection'
3。将 has_many :article_translations
添加到模型
向模型添加关系会引发此错误:
uninitialized constant Article::ArticleTranslation
所以……
接下来我应该尝试什么?
更新
从版本 0.8.0 开始支持按翻译属性排序/
只需这样做:
Article.i18n.current.news_articles.
order(:views => :desc, :'articles.posted_on' => :desc)
Mobility会搞定一切(不需要加入翻译table等)
原始答案
您是对的,您需要加入翻译 table,但该协会名为 translations
,而不是 article_translations
。
无论如何,有一个方法join_translations
加入翻译table,所以这个应该可以工作:
Article.i18n.
current.
news_articles.
join_translations.
order('article_translations.views desc', 'articles.posted_on desc')