ruby-on-railsminitestmobility

Testing with Minitest validation of translation presence using mobility gem


Testing an application that implements the mobility gem with Minitest, a custom validator

class CustomValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    if translation_exists?(record, attribute)
      record.errors.add(attribute, options[:message] || :taken)
    end
  end

  private

  def translation_exists?(record, attribute)
    attribute, locale = attribute.to_s.split('_')
    record.class.joins(:string_translations).exists?(
      mobility_string_translations: { locale: locale, key: attribute }
    )
  end
end

is invoked in the model as follows:

  validates :name, presence: true
  I18n.available_locales.each do |locale|
    validates :"name_#{locale}", presence: true, custom: true
  end

the model has a focus locale (that which is being learned) and is destined to populate the name column and be present.
An array of translations also needs to be present (for now all available_locales).

But the following test fails:

  test "validity of fixtures" do
    assert tags(:en_assigned).valid?
  end

because the fixture

en_assigned:
  name: MyString

is deemed invalid as a puts tags(:en_assigned).errors.first.full_message is adamant that
Name can't be blank which is unexpected?

How can this setup be effectively tested?


Solution

  • This answer may be incomplete, but does address the issue.
    The error arises in the database migration relative to the goal at hand.

    class CreateTags < ActiveRecord::Migration[7.0]
      def change
        create_table :tags do |t|
          t.string :element, index: true, null: false
      [...]
    

    the , null: false is what gums up the works; the presence of mobility will populate the translation table, but not the class column. If one really desires to hold the original value and ensure it is not empty, it should be a separate column - unlss proven otherwise, at present, the saving of a master value in the column is not a funciotn carried out by the mobility gem.

    Then it becomes possible to define which locale(s) need to be validated by adjusting the above to something like:

      [:de, :es].each do |locale|
        validates :"name_#{locale}", presence: true, custom: true
      end