2010/10/07

nested_attributes で error_messages_for のエラーメッセージがうまくローカライズされない。

Just trying to enable correct i18n for error_messages for using nested_attributes. Used this patch but moved to an initializer instead.

Rails 3.0.0.beta4 をいじっているときのこと。。。

nested_attributes を使って親モデルと子モデルを同時に編集する際、error_messages_for を使ってバリデーションのエラーメッセージを吐き出してるんですが、なぜか子モデルのエラーだけがローカライズされない。
例:
class User < ActiveRecord::Base
  has_many :posts
  accepts_nested_attributes_for :posts

  validates_presence_of :name
end

class User < ActiveRecord::Base
  belongs_to :user

  validates_presence_of :title

end
で、
Posts title は必須です
名前は必須です
みたいに出力されてしまう。
運よくAnton Bangratzさんがパッチを書いてくれていた。Anton さんありがとうー!!
でも、パッチするのは嫌だったので、config/initializer/errors_i18n.rb と適当なファイルを作って、下記のように。。。
ActiveModel::Errors.module_eval do

  def full_messages
    full_messages = []

    each do |attribute, messages|
      messages = Array.wrap(messages)
      next if messages.empty?

      if attribute == :base
        messages.each {|m| full_messages << m }
      else
        # attr_name = attribute.to_s.gsub('.', '_').humanize
        attr_name = convert_name(attribute.to_s) 
        attr_name ||= attribute.to_s.gsub('.', '_').humanize        
        attr_name = @base.class.human_attribute_name(attribute, :default => attr_name)
        options = { :default => "%{attribute} %{message}", :attribute => attr_name }

        messages.each do |m|
          full_messages << I18n.t(:"errors.format", options.merge(:message => m))
        end
      end
    end

    full_messages
  end

  def convert_name(name)
    default = nil
    if name =~ /(.+)\.(.+)/
      base_name = $1
      attribute = $2
      base = ActiveSupport::Dependencies.constantize(base_name.camelize)
      if (base.respond_to? :model_name)
        default = "#{base.model_name.human} #{base.human_attribute_name(attribute.to_sym, :default => attribute.humanize)}"
      end
    end
    default 
  end  
  
end
因みに、ActiveModel::Errors::ClassMethods.module_eval do では Name Error になった。なぜだ?