平々凡々エンジニア

平凡で難しい悩みを解決

リプライ完成 勉強したことまとめ

f:id:ceratophrysgerogero:20200309144916p:plain

フォローしてなくてリプライしたきたユーザーのつぶやきが見れるようになった。

今回はかなり苦戦したので使った技術をまとめる。

仕様

  • 呟きに対して呟きで返信することをリプライということにする
  • 自分以外の有効なユーザーにリプライする事ができる
  • リプライした呟きはリプライ先のユーザーの呟き一覧に表示される(フォローは関係ない)
  • リプライの仕方は@ユーザーID_ユーザー名前半角スペースを文頭に追加する
  • リプライは1ユーザーにつき1つ

新しく学んだ事

単語

エンティティ IDでしか同一性を判断できないものオブジェクト 同姓同名同年齢同性別でも必ずしも本人であるかはデータ上からはわからない

値オブジェクト IDじゃなくても判断できるオブジェクト 同国同市同区であればその属性が一致しているので同一の場所

技術

composed_ofの使い方

値オブジェクトをエンティティに含ませると同時に値オブジェクトをクラスにして抜き出す時に使用する

例えば

class User
  attr_accessor :city_address, :town_address, :building_address
  def address
    city_address + town_address + building_address
  end
end

問題点

  • addressのような整形用メソッドがモデルを汚してしまう
  • 本来意味を持つのはaddressなのに、メソッドで返ってくるのは単なる文字列
  • 一旦addressを取得しても、そこからcity_addressを取り出すのは容易ではない

というデメリットを持ち込んでいる。根本的にな問題はDBのUserにaddressを内包した為に起きた事であると考えられる。これを改善するためaddresをクラスに分ける。

class User
  attr_accessor :city_address, :town_address, :building_address
  def address
    Address.new(city_address, town_address, building_address)
  end
end

class Address
  attr_reader :city, :town, :building
  def initialize(city, town, building)
    @city, @town, @building = city, town, building
  end
end

改善点

  • addressメソッドが使いやすくなった
  • cityなどの情報も取りやすくなった

問題点

  • Addressクラスを作るためにaddressメソッドを宣言しているのは単純すぎてわかりにくい

そこでcomposed_ofを使用してリファクタリングしてみる。

class User
  attr_accessor :city_address, :town_address, :building_address
  composed_of :address, mapping: [%w(city_address city), %w(town_address town), %w(building_address building)]
end

class Address
  attr_reader :city, :town, :building
  def initialize(city, town, building)
    @city, @town, @building = city, town, building
  end
end

mappingはモデルの仮想カラムを呼び出すためです。第一引数がエンティティクラス、第二引数は値クラスになります。これによりuser.city_addressuser.address.cityマッピングされるようになります。

雑談

composed_ofの使い方を学べたのは大きかったです。他の技術はバリデーションをクラスとして分離することやgem 'active_decorator'の使い方、正規表現の書き方(ruby)です。次はマークダウン で投稿する機能を作ります。まだできるかどうかもわかってないので(なんで技術調査しなかったのかは今になって思います。)gemがあるか調べてみようと思います。