gpt4 book ai didi

ruby-on-rails - Rails 自引用关联加入条件

转载 作者:行者123 更新时间:2023-12-04 02:16:26 24 4
gpt4 key购买 nike

我有以下数据库模式和模型,它们构成了一个自引用关联,其中一个 Phrase 通过 Translation 有许多其他 Phrase 的翻译 关联:

架构:

ActiveRecord::Schema.define(version: 20151003213732) do

enable_extension "plpgsql"

create_table "phrases", force: :cascade do |t|
t.integer "language"
t.string "text"
end

create_table "translations", force: :cascade do |t|
t.integer "source_id"
t.integer "destination_id"
end
end

短语:

class Phrase < ActiveRecord::Base

has_many :translations,
class_name: "Translation",
foreign_key: "source_id"
has_many :destination_phrases,
through: :translations
has_many :inverse_translations,
class_name: "Translation",
foreign_key: "destination_id"
has_many :source_phrases,
through: :inverse_translations

enum language: [:eng, :spa, ...]
end

翻译:

class Translation < ActiveRecord::Base
belongs_to :source_phrase,
class_name: "Phrase",
foreign_key: "source_id"
belongs_to :destination_phrase,
class_name: "Phrase",
foreign_key: "destination_id"
end

现在,我想基于 语言和目标 语言运行查询。例如,我想查找英语 短语及其各自的西类牙语 翻译。目前我正在查询基于 语言的短语,但随后我必须使用目标语言的select 方法过滤出结果。我的内容如下所示:

@translations = Translation.includes(:source_phrase, :destination_phrase)
.where(phrases: {language: @source_language})

# Select only destination phrases where the language matches
@translations = @translations.select {
|t| t.destination_phrase.language == @destination_language
}

我想消除 select 调用,因为这在 ActiveRecord 中绝对是可能的。 select 将被模型的 where 查询中的附加参数替换,但我不知道如何指定它。

它应该看起来像这样:

@translations =
Translation.includes(:source_phrase, :destination_phrase)
.where([source_phrase: {language: @source_language},
destination_phrase: {language: @destination_language}])

但是,ActiveRecord 认为(正确地)where 子句中的source_phrasedestination_phrase 是表名。所以表名仍然必须是 phrases,但是当它是时,我不能为both 连接指定连接条件,只能指定第一个。

如何在自引用关联上指定 2 个单独的连接条件,它们都访问同一模型(Phrase 模型上的 language)的相同属性?

最佳答案

我的 Phrase 模型被证明定义不正确,这是第一个问题。我已将其修改为:

短语:

class Phrase < ActiveRecord::Base

has_many :translations,
class_name: "Translation",
foreign_key: "source_id"
has_many :source_phrases, # this changed
through: :translations
has_many :inverse_translations,
class_name: "Translation",
foreign_key: "destination_id"
has_many :destination_phrases, # this changed
through: :inverse_translations

enum language: [:eng, :spa, ...]
end

翻译保持不变:

class Translation < ActiveRecord::Base
belongs_to :source_phrase,
class_name: "Phrase",
foreign_key: "source_id"
belongs_to :destination_phrase,
class_name: "Phrase",
foreign_key: "destination_id"
end

现在我可以执行以下任一查询来获得正确的结果:

Translation
.includes(:source_phrase => :source_phrases, :destination_phrase => :destination_phrases)
.where(source_phrases_phrases: {language: 0}, destination_phrases_phrases: {language: 2})

Translation
.joins(:source_phrase => :source_phrases, :destination_phrase => :destination_phrases)
.where(source_phrases_phrases: {language: 0}, destination_phrases_phrases: {language: 2})
.distinct

答案是指定 joined 关联(在本例中为 source_phrasesdestination_phrases in Phrase) ,然后可以在 where 子句中用作不同的表名。

我应该注意,我在 where 子句中使用了 source_phrases_phrasesdestination_phrases_phrases 因为 Rails 似乎期望表名(phrases ) 附加到关联(source_phrasesdestination_phrases)。它会产生一些丑陋的查询,但也许我可以在 Phrase 模型中更好地命名我的关联...

EXPLAIN 输出(放在这里太长了)看来,joins 版本有 6,000 个短语和 12,000 个翻译,速度提高了大约 25%。这些表越大,它的速度也呈指数级增长。

学到了什么? self 参照联想是一种痛苦。我当然希望这对将来的人有所帮助。

关于ruby-on-rails - Rails 自引用关联加入条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33467874/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com