diff --git a/app/models/rule.rb b/app/models/rule.rb index c7b532fe5..fc262d6b2 100644 --- a/app/models/rule.rb +++ b/app/models/rule.rb @@ -42,6 +42,6 @@ class Rule < ApplicationRecord def translation_for(locale) @cached_translations ||= {} - @cached_translations[locale] ||= translations.where(language: [locale, locale.to_s.split('-').first]).order('length(language) desc').first || RuleTranslation.new(language: locale, text: text, hint: hint) + @cached_translations[locale] ||= translations.for_locale(locale).by_language_length.first || translations.build(language: locale, text: text, hint: hint) end end diff --git a/app/models/rule_translation.rb b/app/models/rule_translation.rb index 99991b2ee..71e5773e5 100644 --- a/app/models/rule_translation.rb +++ b/app/models/rule_translation.rb @@ -17,4 +17,7 @@ class RuleTranslation < ApplicationRecord validates :language, presence: true, uniqueness: { scope: :rule_id } validates :text, presence: true, length: { maximum: Rule::TEXT_SIZE_LIMIT } + + scope :for_locale, ->(locale) { where(language: I18n::Locale::Tag.tag(locale).to_a.first) } + scope :by_language_length, -> { order(Arel.sql('LENGTH(LANGUAGE)').desc) } end diff --git a/spec/models/rule_translation_spec.rb b/spec/models/rule_translation_spec.rb new file mode 100644 index 000000000..649bd5c0e --- /dev/null +++ b/spec/models/rule_translation_spec.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe RuleTranslation do + describe 'Associations' do + it { is_expected.to belong_to(:rule) } + end + + describe 'Validations' do + subject { Fabricate.build :rule_translation } + + it { is_expected.to validate_presence_of(:language) } + it { is_expected.to validate_presence_of(:text) } + it { is_expected.to validate_length_of(:text).is_at_most(Rule::TEXT_SIZE_LIMIT) } + it { is_expected.to validate_uniqueness_of(:language).scoped_to(:rule_id) } + end + + describe 'Scopes' do + describe '.for_locale' do + let!(:matching) { Fabricate :rule_translation, language: 'en' } + let!(:missing) { Fabricate :rule_translation, language: 'es' } + + context 'when sent top-level string' do + it 'includes expected records' do + results = described_class.for_locale('en') + + expect(results) + .to include(matching) + .and not_include(missing) + end + end + + context 'when sent sub string' do + it 'includes expected records' do + results = described_class.for_locale('en-US') + + expect(results) + .to include(matching) + .and not_include(missing) + end + end + end + + describe '.by_language_length' do + let!(:top_level) { Fabricate :rule_translation, language: 'en' } + let!(:sub_level) { Fabricate :rule_translation, language: 'en-US' } + + it 'returns results ordered by length' do + expect(described_class.by_language_length) + .to eq([sub_level, top_level]) + end + end + end +end