ActiveRecord:如何从关系中的每个记录获取 has_many 关系

问题描述 投票:0回答:1

问题

class Sentence < ApplicationRecord
  belongs_to :speaker
end

class Speaker < ApplicationRecord
  has_many :sentences
  # Primary language
  belongs_to :language
  # Secondary languages
  has_many :speaker_languages
  has_many :secondary_languages, through: :speaker_languages, source: :languages
end

class Language < ApplicationRecord
  has_many :letters
  # As a speaker's primary language
  has_many :speakers
  # As a speaker's secondary language
  has_many :speaker_languages
  has_many :secondary_speakers, through: :speaker_languages, source: :speakers
end


class Letters < ApplicationRecord
  belongs_to :language
end

如何在

Sentence
上定义一个关联(或至少是一个方法)来获取
Letter
的所有可能的
Sentence
?例如,属于句子说话者的主要语言或句子说话者的第二语言之一的语言的所有字母。

如果它不能是关联而必须是方法,那么该方法可以返回 ActiveRecord 关系(不调用任何数据库)吗?

我尝试了什么

我们可以在

Speaker
上定义一个实例方法来获取所有语言(主要和次要):

class Speaker < ApplicationRecord
  ...
  def all_languages
    secondary_languages.or(Language.where(id: language_id))
  end
end

然后我们可以在

Sentence
上定义一个实例方法来获取所有语言的所有字母:

class Sentence < ApplicationRecord
  ...
  def possible_letters
    speaker.all_languages.map(&:letters).flatten.uniq
  end
end

但这会导致

Language
中的每个
all_languages
调用数据库。它还会导致调用数据库来获取
speaker
(与
has_many :languages, through: :speaker
关联不同)。

ruby-on-rails activerecord
1个回答
0
投票

可以用你现在拥有的关系来完成,但是有一种更简洁的方式来表达这些关系。在我看来,说话者的主要语言应该只是所有说话者语言的“特例”,因此请在

speaker_languages
表中指定一个标志。此外,一个句子似乎更正确地与发言者语言相关联。

我建议:

class Sentence < ApplicationRecord
  belongs_to :speaker_language
end

class SpeakerLanguage
  belongs_to :speaker
  belongs_to :language
end

class Speaker < ApplicationRecord
  has_many :speaker_languages
  has_many :languages, through: :speaker_languages

  def primary_language
    joins(speaker_languages: :language).where(speaker_languages: {primary: true}).first
  end

  def secondary_languages
   joins(speaker_languages: :language).where(speaker_languages: {primary: false})
  end
end

class Language < ApplicationRecord
  has_many :letters
  has_many :speaker_languages
  has_many :speakers, through: :speaker_languages
end


class Letters < ApplicationRecord
  belongs_to :language
end

现在字母查询已简化。对于

Sentence
的例子,我们找到说话者所说的所有语言的所有字母。由于我们想要返回字母,因此我们查询
Letter
模型:

# letter.rb

def self.all_possible_letters_for_speaker_of_sentence(sentence_id)
  joins(language: {speakers: :sentences}).where(sentence: {id: sentence_id}).distinct
end
© www.soinside.com 2019 - 2024. All rights reserved.