接頭辞、接尾辞を設定し、それに繋げるメソッド名を設定するメソッド
# = Active \Model \Attribute \Methods
+テーブル名+などのクラスメソッドのようなActiveRecord::Base
の作成を処理するだけでなく接頭辞と接尾辞をあなたのメソッドに追加する方法を提供します
# Provides a way to add prefixes and suffixes to your methods as
# well as handling the creation of ActiveRecord::Base - like
# class methods such as +table_name+.
である+ActiveModel::AttributeMethods+
を実行するための要件
# The requirements to implement +ActiveModel::AttributeMethods+ are to:
あなたのクラス内のinclude ActiveModel::AttributeMethods
-
+attribute_method_suffix+
、+attribute_method_prefix+
のようなあなたが追加したいそのメソッドのそれぞれを呼び出す - 他のメソッドが呼び出された後
+define_attribute_methods+
を呼び出す - あなたが宣言した様々な汎用
+_attribute+
メソッドを定義する - ハッシュのキーとして各モデルの属性名そしてハッシュ値として属性値を返す
+attributes+
メソッドを定義して下さい。ハッシュのキーは文字列でなければならない
# * <tt>include ActiveModel::AttributeMethods</tt> in your class.
# * Call each of its methods you want to add, such as +attribute_method_suffix+
# or +attribute_method_prefix+.
# * Call +define_attribute_methods+ after the other methods are called.
# * Define the various generic +_attribute+ methods that you have declared.
# * Define an +attributes+ method which returns a hash with each
# attribute name in your model as hash key and the attribute value as hash value.
# Hash keys must be strings.
#
irb(main):001:1* class Person
irb(main):002:1* include ActiveModel::AttributeMethods
irb(main):003:1*
irb(main):004:1* attribute_method_affix prefix: 'reset_', suffix: '_to_default!'
irb(main):005:1* attribute_method_suffix '_contrived?'
irb(main):006:1* attribute_method_prefix 'clear_'
irb(main):007:1* define_attribute_methods :name
irb(main):008:1*
irb(main):009:1* attr_accessor :name
irb(main):010:1*
irb(main):011:2* def attributes
irb(main):012:2* { 'name' => @name }
irb(main):013:1* end
irb(main):014:1*
irb(main):015:1*
irb(main):016:1* private
irb(main):017:2* def attribute_contrived?(attr)
irb(main):018:2* true
irb(main):019:1* end
irb(main):020:1*
irb(main):021:2* def clear_attribute(attr)
irb(main):022:2* send("#{attr}=", nil)
irb(main):023:1* end
irb(main):024:1*
irb(main):025:2* def reset_attribute_to_default!(attr)
irb(main):026:2* send("#{attr}=", 'Default Name')
irb(main):027:1* end
irb(main):028:0> end
=> :reset_attribute_to_default!
irb(main):029:0>
irb(main):030:0> Person.new(name: "fafa").name
(irb):30:in `initialize': wrong number of arguments (given 1, expected 0) (ArgumentError)
irb(main):031:0> Person.new(name: "fafa")
(irb):31:in `initialize': wrong number of arguments (given 1, expected 0) (ArgumentError)
irb(main):032:0> Person.new
=> #<Person:0x000000010e5cab98>
irb(main):033:0> a = Person.new
=> #<Person:0x000000010e6dae48>
irb(main):034:0> a.attributes
=> {"name"=>nil}
irb(main):035:0> a.name
=> nil
irb(main):036:0> a.name = "fafa"
=> "fafa"
irb(main):037:0> a
=> #<Person:0x000000010e6dae48 @name="fafa">
irb(main):038:0> a.name
=> "fafa"
define_attribute_methods(*attr_names)
ActiveModel::AttributeMethods
によって接頭辞と接尾辞がついた属性を宣言する
Declares the attributes that should be prefixed and suffixed by ActiveModel::AttributeMethods.
使用するには、(文字列またはシンボルとして)属性名を渡す。接頭辞、接尾辞または接辞メソッドを定義した後必ずdefine_attribute_methods
を宣言する。でなければ引っかからないだろう。
To use, pass attribute names (as strings or symbols). Be sure to declare define_attribute_methods after you define any prefix, suffix, or affix methods, or they will not hook in.
irb(main):001:1* class Person
irb(main):002:1* include ActiveModel::AttributeMethods
irb(main):003:1*
irb(main):004:1* attr_accessor :name, :age, :address
irb(main):005:1* attribute_method_prefix 'clear_'
irb(main):006:1*
irb(main):007:1* # Call to define_attribute_methods must appear after the
irb(main):008:1* # attribute_method_prefix, attribute_method_suffix or
irb(main):009:1* # attribute_method_affix declarations.
irb(main):010:1* define_attribute_methods :name, :age, :address
irb(main):011:1*
irb(main):012:1* private
irb(main):013:2* def clear_attribute(attr)
irb(main):014:2* send("#{attr}=", nil)
irb(main):015:1* end
irb(main):016:0> end
=> :clear_attribute
...
irb(main):022:0> a.name = "faaf"
=> "faaf"
irb(main):023:0> a.age = "ffafa"
=> "ffafa"
irb(main):024:0> a.address = "fafa"
=> "fafa"
irb(main):025:0> a.name
=> "faaf"
irb(main):026:0> a.age
=> "ffafa"
irb(main):027:0> a.address
=> "fafa"
1.5 AttributeMethodsモジュール
ActiveModel::AttributeMethodsモジュールは、モデルの属性メソッドを動的に定義する方法を提供します。このモジュールは、属性へのアクセスと操作をシンプルにするうえで特に有用であり、クラスのメソッドにカスタムのプレフィックスやサフィックスを追加することも可能です。プレフィックスとサフィックス、およびそれらをオブジェクトのどのメソッドで利用するかを定義するには、次の手順で実装できます。
クラスにActiveModel::AttributeMethodsをincludeします。
追加したいメソッド(attribute_method_suffix、attribute_method_prefix、attribute_method_affixなど)を呼び出します。
他のメソッドに続けてdefine_attribute_methodsを呼び出して、プレフィックスやサフィックスを付ける必要がある属性を宣言します。
宣言した属性にさまざまな汎用_attributeメソッドを定義します。これらのメソッドのattributeパラメータは、define_attribute_methodsで渡される引数に置き換えられます(以下の例ではname)。
irb(main):001:1* class Person
irb(main):002:1* include ActiveModel::AttributeMethods
irb(main):003:1*
irb(main):004:1* attribute_method_affix prefix: "reset_", suffix: "_to_default!"
irb(main):005:1* attribute_method_prefix "first_", "last_"
irb(main):006:1* attribute_method_suffix "_short?"
irb(main):007:1*
irb(main):008:1* define_attribute_methods "name"
irb(main):009:1*
irb(main):010:1* attr_accessor :name
irb(main):011:1*
irb(main):012:1* private
irb(main):013:1* # 'first_name'用の属性メソッド呼び出し
irb(main):014:2* def first_attribute(attribute)
irb(main):015:2* public_send(attribute).split.first
irb(main):016:1* end
irb(main):017:1*
irb(main):018:1* # 'last_name'用の属性メソッド呼び出し
irb(main):019:2* def last_attribute(attribute)
irb(main):020:2* public_send(attribute).split.last
irb(main):021:1* end
irb(main):022:1*
irb(main):023:1* # 'name_short?'用の属性メソッド呼び出し
irb(main):024:2* def attribute_short?(attribute)
irb(main):025:2* public_send(attribute).length < 5
irb(main):026:1* end
irb(main):027:1*
irb(main):028:1* # 'reset_name_to_default!'用の属性メソッド呼び出し
irb(main):029:2* def reset_attribute_to_default!(attribute)
irb(main):030:2* public_send("#{attribute}=", "Default Name")
irb(main):031:1* end
irb(main):032:0> end
=> :reset_attribute_to_default!
irb(main):033:0> person = Person.new
=> #<Person:0x00000001064d47c8>
irb(main):034:0> person.name = "Jane Doe"
=> "Jane Doe"
irb(main):035:0> person.first_name
=> "Jane"
irb(main):036:0> person.last_name
=> "Doe"
irb(main):037:0> person.name_short?
=> false
irb(main):038:0> person.reset_name_to_default!
=> "Default Name"
指定した属性でないとundefined methodになる
irb(main):001:1* class Person
irb(main):002:1* include ActiveModel::AttributeMethods
irb(main):003:1*
irb(main):004:1* attr_accessor :name, :age, :address
irb(main):005:1* attribute_method_prefix 'clear_'
irb(main):006:1*
irb(main):007:1* # Call to define_attribute_methods must appear after the
irb(main):008:1* # attribute_method_prefix, attribute_method_suffix or
irb(main):009:1* # attribute_method_affix declarations.
irb(main):010:1* define_attribute_methods :age
irb(main):011:1*
irb(main):012:1* private
irb(main):013:2* def clear_attribute(attr)
irb(main):014:2* send("#{attr}=", nil)
irb(main):015:1* end
irb(main):016:0> end
=> :clear_attribute
irb(main):017:0> a = Person.new
=> #<Person:0x0000000116048d70>
irb(main):018:0> a.age = "fafa"
=> "fafa"
irb(main):019:0> a.name = "fafa"
=> "fafa"
irb(main):020:0> a.clear_age
=> nil
irb(main):021:0> a.clear_name
....
`method_missing': undefined method `clear_name' for #<Person:0x0000000116048d70 @age=nil, @name="fafa"> (NoMethodError)
Did you mean? clear_age
感想
+define_attribute_methods+
の表現は左右に接頭辞、接尾辞のどちらか、両方が繋がれると言う意味。
+define_attribute_methods+
のdefine_attribute_methodsの部分はハッシュで宣言した属性が入る。
+~+の表現は慣れが必要だ。