t11hi

hene

ActiveModel::Model を使って、initializer を消してみる

ActiveModel::Model を使って、initializer を消してみる

ActiveModel::Model を使うと Before -> After のように initializer を消せることを知りました。

Before

今まで、自分は initializer を使って実装していました。

class Before
  attr_accessor :attr

  def initialize(attr:)
    @attr = attr
  end
end
[1] pry(main)> before = Before.new(attr: 'before')
=> #<Before:0x00007f51c20d8ca0 @attr="before">
[2] pry(main)> before.attr
=> "before"

After

initializer を書かずに、シンプルにかけます。

class After
  include ActiveModel::Model

  attr_accessor :attr
end
[1] pry(main)> after = After.new(attr: 'after')
=> #<After:0x00007f51c0324ee8 @attr="after">
[2] pry(main)> after.attr
=> "after"

ActiveModel::Model について

調査して、いろいろ試してみました。

ActiveModel::Model を追加すると?

ActiveModel::Model を追加すると、Action PackAction View と連携する機能をすぐに使えるようになります。

Active Model の基礎 - Rails ガイド

include ActiveModel::Model なし

まず、ActiveModel::Model を使わない場合、どういうふうに実装できるか試してみました。

initializer を使う

class A
  attr_accessor :attr

  def initialize(attr:)
    @attr = attr
  end
end
[1] pry(main)> a = A.new(attr: 'a')
=> #<A:0x0000000009b53ed0 @attr="a">
[2] pry(main)> a.attr
=> "a"

ActiveModel::Model の実装を参考にして動かしてみる

下記の ActiveModel::Model の実装をそのまま持ってきて、動かしてみました。

class B
  include ActiveModel::AttributeAssignment

  attr_accessor :attr

  def initialize(attributes = {})
    assign_attributes(attributes) if attributes
  end
end
[2] pry(main)> b = B.new(attr: 'b')
=> #<B:0x00007f9f6808def0 @attr="b">
[3] pry(main)> b.attr
=> "b"

ActiveModel::Model を使ってみる

attr_accessor

attr_accessor を使うと、書き込みも読み取りもできます。

class C
  include ActiveModel::Model

  attr_accessor :attr
end
[1] pry(main)> c = C.new(attr: 'c')
=> #<C:0x00007ff4935dd0b0 @attr="a">
[2] pry(main)> c.attr
=> "c"

include ActiveModel::Model なし

ActiveModel::Modelinclude しない場合、initializer が定義されていないため、引数が渡せず ArgumentError で落ちます。

class D
  attr_accessor :attr
end
[1] pry(main)> d = D.new(attr: 'd')
ArgumentError: wrong number of arguments (given 1, expected 0)
from (pry):1:in `initialize'
[2] pry(main)> d = D.new
=> #<A:0x00007f9f5e52f5a8>
[3] pry(main)> d.attr
=> nil

attr_reader

attr_reader だと、書き込めないため ActiveModel::UnknownAttributeError で落ちます。

class E
  include ActiveModel::Model

  attr_reader :attr
end
[1] pry(main)> e = E.new(attr: 'e')
ActiveModel::UnknownAttributeError: unknown attribute 'attr' for E.
from /Users/user_name/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/activemodel-5.2.3/lib/active_model/attribute_assignment.rb:53:in `_assign_attribute'

attr_writer

attr_writer だと、読み込めないため NoMethodError で落ちます。

class F
  include ActiveModel::Model

  attr_writer :attr
end
[1] pry(main)> f = F.new(attr: 'f')
=> #<F:0x00007ff49df74678 @attr="f">
[2] pry(main)> f.attr
NoMethodError: undefined method `attr' for #<F:0x00007ff49df74678 @attr="f">
from (pry):1:in `<main>'

参考