先日、と言ってももう1カ月くらいは前だった気がしますが、Ruby on Rails 4.2.0がリリースされました。
⇒ リリースノート
⇒ リリースノート(日本語)
主要な修正は以下の5つのようです。
- ActiveJob
- メールの非同期処理
- Adequate Record
- Web Console
- 外部キーのサポート
以下のコミットで導入されました。
⇒ Introduce Concern#class_methods and Kernel#concern
いままでconcernはこんな感じのモジュールを用意していました。
# 4.1まで module Hoge extend ActiveSupport::Concern included do end module ClassMethods end end class Fuga < ActiveRecord::Base include Hoge end
それが4.2以降はConcern#class_methodsを使用して以下のように書けるようになります。
# 4.2以降(Concern#class_methods) module Hoge extend ActiveSupport::Concern included do end class_methods do end end class Fuga < ActiveRecord::Base include Hoge end
さらにKernel#concernを使えば以下のようにmoduleである必要すらなくり、ActiveSupport#Concernをextendする必要がなくなります。
# 4.2以降(Kernel#class_methods) concern :Hoge included do end class_methods do end end class Fuga < ActiveRecord::Base include Hoge end
module ClassMethodsとConcern#class_methodsではクラス変数の扱いが微妙に異なるようです。
# app/models/concerns/hoge_old.rb module HogeOld extend ActiveSupport::Concern included do end module ClassMethods def func_old @@val_old ||= 'old style' end end end # app/models/concerns/hoge_new.rb module HogeNew extend ActiveSupport::Concern included do end class_methods do def func_new @@val_new ||= 'new style' end end end # app/models/concerns/user.rb class User < ActiveRecord::Base include HogeOld include HogeNew end上記のようなコードがあるとして、実行すると以下のような結果になります。
[1] pry(main)> User.class_variable_defined?(:@@val_old) => false [2] pry(main)> HogeOld::ClassMethods.class_variable_defined?(:@@val_old) => false [3] pry(main)> User.func_old => "old style" [4] pry(main)> User.class_variable_defined?(:@@val_old) => false [5] pry(main)> HogeOld::ClassMethods.class_variable_defined?(:@@val_old) => true [6] pry(main)> User.class_variable_defined?(:@@val_new) => false [7] pry(main)> HogeNew::ClassMethods.class_variable_defined?(:@@val_new) => false [8] pry(main)> User.func_new => "new style" [9] pry(main)> User.class_variable_defined?(:@@val_new) => true [10] pry(main)> HogeNew::ClassMethods.class_variable_defined?(:@@val_new) => false [11] pry(main)>module ClassMethodsでクラス変数を定義するとincludeしたクラスのクラス変数とはならず、ClassMethodsのクラス変数(モジュール変数)になってしまします。しかし、Concern#class_methodsを利用するとincludeしたクラスのクラス変数になります。
通常、concernでクラス変数を利用する際は後者の挙動を期待するように思います。
ちなみにKernel#concernでclass_methodsを使った時はクラス変数を使用するべきではありません。
「warning: class variable access from toplevel」みたいな警告が出ます。
これが意図した挙動かまでは追ってませんが、どうなんでしょうね?
いずれにしてもmodule ClassMethodsはやめてclass_methodsを使用したほうが見通しは良くなりそうです。
0 件のコメント:
コメントを投稿