2

我有一个带有翻译字段的模型,它使用globalize gem 和globalize-accessors gem 来提供本地化属性,例如name_en,name_zh_hk用于本地化名称字段。

例如:

class Person < ActiveRecord::Base
  translates :name
  globalize_accessors: locales: [:en, :"zh-HK"], attributes: [:name]

  # problem is:
  validates :name, presence: true, uniqueness: true
end

所以现在 name_en 和 name_zh_hk 可以正确获取和设置相应语言环境中的值。

但是,validates :name仅验证 Person 模型中的 name 字段。我还想验证中文输入的唯一性。

简而言之,想要一种(简单的)方法来验证 name_en 和 name_zh_hk 的唯一性

** 我有一个表格可以同时提交 name_en 和 name_hk。

4

4 回答 4

2

person.rb模型文件的末尾(在 之外class Person ... end,添加:

Person::Translation.class_eval do
  validates_presence_of :name
  validates_uniqueness_of :name
end
于 2014-08-15T16:00:57.607 回答
2

你必须这样做

class Person < ActiveRecord::Base
  translates :name

  class Translation
    validates :name, presence: true, uniqueness: true
  end
end
于 2019-01-20T15:29:45.610 回答
0

我可能会对您对独特范围的要求感到困惑:

 validates :name, uniqueness: {scope: :blah}

具体来说,您可能想要一个“PersonName”模型。

人名

姓名 | 本地 | person_id

has_many :names

然后有:

validates :name, uniqueness: { scope: :person_id }

这样,如果他们为 HK 输入的名称与 :en 的名称相同,它将无效。

于 2014-08-15T16:11:04.363 回答
0

用下面的代码解决。

模型

# /app/models/category.rb

...
I18n.available_locales.each do |locale|
    validates :"name_#{locale}", presence: true, length: { maximum: 5 }, uniqueness: true
end

验证器

# config/initializers/associated_translations_uniqueness_validator.rb

require 'active_record'
require 'active_record/validations/uniqueness.rb'

ActiveRecord::Validations::UniquenessValidator.class_eval do
  def validate_each_with_associated_translations(record, attribute, value)
    klass = record.class
    if klass.translates? && !klass.translated?(attribute) && klass.globalize_attribute_names.include?(attribute)
      attribute_parts = attribute.to_s.rpartition('_')
      raw_attribute = attribute_parts.first.to_sym
      locale = attribute_parts.last.to_sym

      finder_class = klass.translation_class
      table = finder_class.arel_table

      relation = build_relation(finder_class, table, raw_attribute, value).and(table[:locale].eq(locale))
      relation = relation.and(table[klass.reflect_on_association(:translations).foreign_key].not_eq(record.send(:id))) if record.persisted?

      translated_scopes = Array(options[:scope]) & klass.translated_attribute_names
      untranslated_scopes = Array(options[:scope]) - translated_scopes

      untranslated_scopes.each do |scope_item|
        scope_value = record.send(scope_item)
        reflection = klass.reflect_on_association(scope_item)
        if reflection
          scope_value = record.send(reflection.foreign_key)
          scope_item = reflection.foreign_key
        end
        relation = relation.and(find_finder_class_for(record).arel_table[scope_item].eq(scope_value))
      end

      translated_scopes.each do |scope_item|
        scope_value = record.send(scope_item)
        relation = relation.and(table[scope_item].eq(scope_value))
      end

      if klass.unscoped.with_translations.where(relation).exists?
        record.errors.add(attribute, :taken, options.except(:case_sensitive, :scope).merge(:value => value))
      end
    else
      validate_each_without_associated_translations(record, attribute, value)
    end
  end
  alias_method_chain :validate_each, :associated_translations
end
于 2016-02-05T21:56:11.583 回答