ruby-on-railsinternationalizationmobility

How to use validations with mobility gem?


I'm trying to add validations to my mobility-powered application and i'm confused a little.Earlier I've used code like this

I18n.available_locales.each do |locale|
    validates :"name_#{locale}", presence: true, uniqueness: {scope: :animal_type}
end

And it worked fine. But in my last project it doesn't work at all. Any ideas how to perform validations? My config is below:

Mobility.configure do
  plugins do
    backend :container
    active_record
    reader
    writer
    backend_reader
    query
    cache
    presence
    locale_accessors
  end
end

UPD: I've identified my problem - it is because of , uniqueness: {scope: :animal_type}. Is it possible to use mobility with similar type of validations?


Solution

  • When you use uniqueness validator it uses query to the database to ensure that record haven't already taken and you get this query:

    Let's assume you have Animal model

    SELECT 1 AS one FROM "animals" WHERE "animals"."name_en" = "Cat" AND "animals"."animal_type" = "some_type" LIMIT 1
    

    And of course there is no name_en field in the animals table that is why you have an error

    To archive this you have to write your own 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 },
          animals: { animal_type: record.animal_type }
        )
      end
    end
    
    

    And then in your model do next:

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