2020/01/09 実務で学んだこと

【実務で学んだこと】 Diary

その日に覚えたこと、学んだこと、知ったこと、気になったこと等を日記のように書いていきます。

今回は 2020/01/08(水)に学んだことを書いていきます。

【Rails】

条件によってvalidationをかける

ある条件によってバリデーションを実行したい時に :if:unless オプションを使用することで条件を指定することができます。

:if:unlessオプションにメソッド名をシンボルで指定することで、条件を満たした時だけバリデーションの直前に呼び出されます。

# 以下のコードは「Railsガイド Active Record バリデーション 5.1」からの引用です

class Order < ApplicationRecord
  validates :card_number, presence: true, if: :paid_with_card?
 
  def paid_with_card?
    payment_type == "card"
  end
end

条件付きのvalidationをグループ分けする

ある条件で複数のバリデーションを実行したい時は、バリデーションごとに:if:unless オプションで同じメソッドを指定しなくても条件を共有することができます。

1つの条件を複数のバリデーションで共用できると便利なことがあります。これはwith_optionsを使うことで簡単に実現できます。

以下のようにwith_optionsを使用します。

# 以下のコードは「Railsガイド Active Record バリデーション 5.3」からの引用です

class User < ApplicationRecord
  with_options if: :is_admin? do |admin|
    admin.validates :password, length: { minimum: 10 }
    admin.validates :email, presence: true
  end
end

ブロックの内にある全てのバリデーションには、if: :is_admin?という条件が共有されます。

参考記事

Dirtyモジュール

データの更新があった時に変更したことの検知や、変更前と変更後のデータを取得したいという場面がありました。

ActiveModel::Dirtyモジュールを使うと、オブジェクトで変更があったかどうかを検出でき、また変更前と変更後のデータも取得できます。

user = User.new
user.changed? # => false 

user.name = "Tom"
user.name # => "Tom"
 
# 属性が1つ以上変更されている場合にtrueを返す
user.changed? # => true
 
# 保存前に変更された属性のリストを返す
user.changed # => ["Tom"]
 
# 元の値から変更された属性のハッシュを返す
user.changed_attributes # => {"Tom"=>nil}
 
# 変更のハッシュを返す (ハッシュのキーは属性名、ハッシュの値はフィールドの新旧の値の配列
user.changes # => {"name"=>[nil, "Tom"]}

# 特定の属性が変更されている場合にtrueを返す
user.name_changed? # => true
user.age_changed? # => false

# 特定の属性の変更前の値を返す
user.name_was # => nil
user.name = "Jun"
user.name_was # => "Tom"

# 変更された属性の、変更前と変更後の値を配列で返す。変更が無い場合はnilを返す
user.name_change # => ["Tom", "Jun"]
user.age_change # => nil
注意

Dirtyモジュールのいくつかのメソッド名が非推奨になったようです。Railsガイドやその他記事を見て使用する際は、以下の記事を確認してから使用してみてください。

参考:Rails 5.1 で attribute_was, attribute_change, attribute_changed?, changed?, changed 等が DEPRECATION WARNING – Qiita

参考記事

翻訳したモデルのattributeを取得する方法

config/locales/ja.yml で翻訳したモデルの属性名等を取得する方法です。

指定された階層に置くことで、Model.model_name.humanでモデル名を、Model.human_attribute_name(attribute)で属性名を取得できます。

以下のコードはあなたはいくつ知っている?Rails I18nの便利機能大全! – Qiita からの引用です

config/locales/ja.yml
ja:
  activerecord:
    # モデル名
    models:
      user: 顧客
    # モデルごとのアトリビュート名
    attributes:
      user:
        name: 名前
        address: 住所
  # 全モデル共通のアトリビュート名
  attributes:
    created_at: 作成日時
    updated_at: 更新日時
> User.model_name.human
=> "顧客"
> User.human_attribute_name(:name)
=> "名前"
> User.human_attribute_name(:created_at)
=> "作成日時"

参考記事

inspectでインスタンスをわかりやすく表示する

inspectはオブジェクトや配列をわかりやすい文字列にして返すメソッドです。

class User
    def initialize(name, age)
      @name = name
      @age = age
    end
end
[1] pry(main)> user = User.new("Tom", 23)
=> #<User:0x0000558f92cc5d90 @age=23, @name="Tom">
[2] pry(main)> puts user
#<User:0x0000558f92cc5d90>
=> nil
[3] pry(main)> puts user.inspect
#<User:0x0000558f92cc5d90 @name="Tom", @age=23>
=> nil

デバッグでよく利用されるpメソッド(標準出力するメソッド)は、このinspectメソッドが使われています。

【Ruby超入門】print、puts、pの違い

【Ruby超入門】print、puts、pの違い

2019年11月17日

参考記事

StrongParametersで配列データを扱う時は最後に記述する

Strong Parametersに新たにデータを追加したらエラーとなりました。

def user_params
    params[:user].permit(
        :name,
        :age,
        hoge: [:hogehoge, :fugafuga],
        :email  # emailを追加したらエラー
    )
end

どうやらStrong Parametersの最後は配列を一番最後に記述しないといけないそうです。

以下のように修正したらエラーが解消されました。

def user_params
    params[:user].permit(
        :name,
        :age,
        :email,
        hoge: [:hogehoge, :fugafuga]
    )
end

参考記事