何についての記事か
当たり前のことをタイトルにしましたが、意外と盲点だったので、記事にまとめます。
RailsのActiveModelでattr_accessor
を利用することで得られるメリットについて考えられたらなと思ってます。
一応attr_accessor
について知らない方向けに軽い説明も末尾に記載いたします。
使い方
ActiveModelでattr_accessor
はこんな感じで、普通に使えます。
ActiveModelがクラスなので、当然なんですが。。。
class User < ApplicationRecord
attr_accessor :name
end
この例のようにname
などの変数はテーブルにカラムとして用意することが多いため、attr_accessor
を使うことはないと思います。
なので、ActiveModelでattr_accessor
を使うべきケースを考えてみたいと思います。
ActiveModelでattr_accessorを使うべき状況
フラグとして
1つ目はフラグとしての用途です。
例えば、1度だけ実行すれば良い処理があるとして、その処理が実行済みであることを保存しておく用途です。
例えば、以下のコードのようにUserクラスにパスワードを初期化するメソッドが複数箇所存在しているとします。
すでに他のメソッドでパスワードリセットが済んでいる場合、2回目は実施しないということがフラグを用いて実現できています。
その処理中にパスワードをリセットしたかという情報はわざわざテーブルに残さないので、フラグとして管理するのが適切だと思います。
class User < ApplicationRecord
attr_accessor :is_completed_password_reset
def reset_auth
self.password = "initial_password" unless @is_completed_reset_password
self.login_id = "initial_login_id"
@is_completed_password_reset = true
end
def reset_password
self.password = "initial_password" unless @is_completed_reset_password
@is_completed_reset_password = true
end
end
同じ処理ならメソッドを使いまわせばいいですし、値代入くらいなら複数回実施しても問題ないですが、
これはただ例が悪いだけです。思いつきませんでした。。
メモ化として
重い演算があったとして、実行結果のメモ化用変数としても十分適切だと思います。
以下の例では、very_very_long_task
は呼び出すたびに演算を実施するのではなく、2度目以降は1度目の結果を使いまわしています。
class User < ApplicationRecord
attr_accessor :results
def very_very_long_task
return results if results.exists?
# めちゃくちゃ時間がかかる処理
@results = xxxxx
return @results
end
end
メソッドに呼び出す順序を指定したい時
メソッドを定義する際に、このメソッドはあのメソッドを実施していること前提なんだよなって時に使えます。
class User < ApplicationRecord
attr_accessor :is_processed
def pre_processor
# 事前にこの関数を読んでおきたい
@is_processed = true
end
def main_processor
pre_processor unless @is_processed
# 処理
end
end
注意点
attr_accessorはインスタンス変数を宣言する関数です。
そのため、異なるインスタンス間では値が共有されないことに注意が必要です。
もし異なるインスタンス間や、タスク間で値を共有したい場合は、テーブルにカラムを追加するや、redisなどのストレージを検討する必要があります。
attr_accessorとは
まず、attr_accessor
についてです。attr_accessor
はクラスにフィールドを追加するメソッドです。
以下のように使用することができます。
class User
attr_accessor :name
end
hanako = User.new
hanako.name = "hanako"
puts hanako.name
# => hanako
このような感じでUser
クラスにname
というフィールドを追加し、name=
や.name
という感じで利用することができるようになります。
rubyは動的型付け言語なので、変数を宣言しなくても例えば以下のように@
を接頭辞とすることで、変数に値を格納・取得することは可能です。
class User
def set_name(str)
@name = str
end
def name
@name
end
end
hanako = User.new
hanako.set_name("hanako")
puts hanako.name
# => hanako
しかしながら、クラスが長くなると、そのクラスがどんな変数を持っているのか一目で分かりづらくなってしまいます。また、全ての変数について格納用関数(セッター)と取得用変数(ゲッター)を作成するのは面倒です。
そこで、attr_accessor
を使えば一箇所で変数一覧を記述することができ、便利だねって感じです。
attr_accessor
には他にも類似メソッドがあります。
メソッド | 外部から書き込み可能 | 外部から読み取り可能 |
attr_accessor | ○ | ○ |
attr_writer | ○ | × |
attr_reader | × | ○ |