2014/08/01

ActiveSupport::Concern の included と ClassMethods の順序

前置き

最初に書いておきます、Rails3.2系の記事です。
Rails4だと ActiveModel::Model を使うだろうから、サンプルコードはずいぶん変わると思います。

ActiveModel を利用したモデルで独自の i18n のセクションを利用したい

まあとある事情で、通常 activemodel.errors.messages.xxx な i18n のキーを my_model.errors.messages.xxx とかにしたかった。
そんな場合は i18n_scope をオーバーライドしてやるんだけど、全モデルクラスに書くのは嫌なので、インクルードするだけの共通モジュールを書くことに。

最初にこんなのを書いた

module MyModel
extend ActiveSupport::Concern
included do
__send__(:include, ActiveModel::Conversion)
__send__(:include, ActiveModel::Validations)
extend ActiveModel::Naming
extend ActiveModel::Translation
end
module ClassMethods
def i18n_scope
:my_model
end
end
def persisted?
false
end
end
しかし、これではうまくいかない。

問題点

ActiveSupport::ConcernClassMethods モジュールを反映させてから included のブロックを実行するので、再度デフォルトで上書きしてしまう。

解決策

こんな風に alias_method_chain を使うなどして extend ActiveModel::Translation の後にオーバーライドしてやればいい。
module MyModel
extend ActiveSupport::Concern
included do
__send__(:include, ActiveModel::Conversion)
__send__(:include, ActiveModel::Validations)
extend ActiveModel::Naming
extend ActiveModel::Translation
class << self
alias_method_chain :i18n_scope, :my_model
end
end
module ClassMethods
def i18n_scope_with_my_model
:my_model
end
end
def persisted?
false
end
end

0 件のコメント :

コメントを投稿