сначала вы должны рассмотреть использование отношений соответствия rails / activerecord. Это означает, что внешний ключ в таблице text_translations должен называться text_id
Создайте свои модели и ассоциации, как это:
class Text < ActiveRecord::Base
# all possible translations!
has_many :text_translations
scope :with_translation_for, lambda { |lang| {
:select => "texts.*, tt.translation",
:joins => "LEFT OUTER JOIN text_translations AS tt ON tt.text_id = texts.id AND tt.locale = #{ActiveRecord::Base.sanitize(lang)}"
}}
# return nil if translation hasn't been loaded, otherwise you get a nasty NoMethod exception
def translation
read_attribute(:translation)
end
end
и
class TextTranslation < ActiveRecord::Base
# every translation belongs to a text
belongs_to :text
# define a scope for the language
scope :language, lambda { |lang| where(['locale = ?', lang]) }
end
Как использовать:
texts = Text.with_translation_for('en')
texts.each do |c_text|
unless c_text.translation.nil?
puts c_text.translation
else
puts "No translation available!"
end
end
Теперь о плюсах и минусах, способ использования LEFT OUTER join загрузит вас всех текстов, даже если для нужного языка нет перевода текста. Дело в том, что вы не получите объект модели «TextTranslation».
Другим способом является загрузка только текста, который имеет желаемый перевод. Вы можете сделать это как:
texts = Text.includes(:text_translations).where(:text_translations => {:locale => 'en'})
сейчас texts[i].text_translations
вернет массив со всеми объектами модели TextTranslations для этого текста, соответствующего локали 'en'. Но тексты без перевода в локали "en" не будут отображаться.
Редактировать
На ваш комментарий:
Проблема использования .join(:tablename)
в отношении заключается в том, что это приведет к ВНУТРЕННЕМУ СОЕДИНЕНИЮ, поэтому это не вариант. Вы должны явно объявить левое соединение. Другое дело, что если вы используете что-то вроде Text.includes(:text_translations).where(['text_translations.locale = ?', 'en'])
, условие будет применено к SQL-запросу в целом, а не к возможному левому соединению. Что вы можете сделать, так это объявить ассоциации типа
has_many :english_translations, :class_name => 'TextTranslation', :conditions => ['locale = ?', 'en']
Таким образом, вы можете загружать только переводы на английский язык с нетерпением (без каких-либо объединений):
Text.includes(:english_translations).all
Проверьте это: