実際の開発で知ったことやレビューでよく指摘を受ける事を備忘録を兼ねてメモ。
動作はRuby2.3.1とRails4.2.6で確認。
tryメソッド (ActiveSupport)
みんな大好き(なハズ)tryメソッド。
Rails開発では、viewでモデルインスタンスの値を返す場面などで大活躍します。
[1] pry(main)> user = User.find_by(id: 9999)
=> nil
[2] pry(main)> user.try(:name)
=> nil
[3] pry(main)> user.name
NoMethodError: undefined method `name' for nil:NilClass
viewでNoMethodErrorが発生すると500エラーページが出てしまうので、それを予防するためによく使います。
mapメソッドの&修飾詞
配列の値全部に処理を入れたい場合など、業務のちょっとしたかゆい場面で活躍します。
# 数値配列の中身を文字列に変換したい場合
[1] pry(main)> [2, 4, 6, 8].map(&:to_s)
=> ["2", "4", "6", "8"]
# 複数のUserインスタンスからnameのみを抽出する
[2] pry(main)> users = User.where(id: [1,2,3])
[3] pry(main)> users.map(&:name)
=> ["ほげ1", "ほげ2", "ほげ3"]
pluckメソッド (ActiveRecored)
今年になってから知ったメソッド。
map(&:hoge)とかで抽出していたけど、どう考えてもこっちの方が良かった。
[1] pry(main)> User.where(id: [1,2,3]).pluck(:name)
=> ["ほげ1", "ほげ2", "ほげ3"]
# 複数項目も可能
[2] pry(main)> User.where(id: [1,2,3]).pluck(:id, :name)
=> [[1, "ほげ1"], [2, "ほげ2"], [3, "ほげ3"]]
transposeメソッド
このメソッドは配列を行列に見立てて、行と列を入れ替える動きをする。
応用する事で2つの配列の1つをkey、もう1つをvalueとしたHashを作れる。
[1] pry(main)> hash_keys = %w(2 4 6)
=> ["2", "4", "6"]
[2] pry(main)> hash_values = %w(a b c)
=> ["a", "b", "c"]
[3] pry(main)> hash = Hash[ [hash_keys, hash_values].transpose ]
=> {"2"=>"a", "4"=>"b", "6"=>"c"}
# valuesをModelインスタンスにすると任意のkeyを持ったhashを作れる
[1] pry(main)> hash_keys = %w(a b c).map(&:to_sym)
=> [:a, :b, :c]
[2] pry(main)> hash_values = User.where(id: [1,2,3])
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" IN (1, 2, 3)
=> [#<User:0x007f9dcf9a99c0 id: 1, name: "ほげ1">, #<User:0x007f9dcf9a9538 id: 2, name: "ほげ2">, #<User:0x007f9dcf9a90b0 id: 3, name: "ほげ3">]
[3] pry(main)> hash = Hash[ [hash_keys, hash_values].transpose ]
=> {:a=>#<User:0x007f9dcf9a99c0 id: 1, name: "ほげ1">, :b=>#<User:0x007f9dcf9a9538 id: 2, name: "ほげ2">, :c=>#<User:0x007f9dcf9a90b0 id: 3, name: "ほげ3">}
[4] pry(main)> hash[:b]
=> #<User:0x007f9dcf9a9538 id: 2, name: "ほげ2">
split(//)メソッド
splitメソッド自体は普通に使われると思うが、引数に//
を渡すと文字列を1文字区切りの配列にしてくれる。
[1] pry(main)> "abcde".split(//)
=> ["a", "b", "c", "d", "e"]
# マルチバイト文字にも対応
[2] pry(main)> 'あいうえお'.split(//)
=> ["あ", "い", "う", "え", "お"]
### 別件になるけど、この記事のためにsplit関数を調べていた気づいた事
# 1. 区切り文字に半角スペースを渡すとタブ文字や改行でも区切ってくれる
[3] pry(main)> "ab cd\tef\ngh".split(' ')
=> ["ab", "cd", "ef", "gh"]
# 2. 恥ずかしながらsplitに第二引数があることを知らなかった
[4] pry(main)> "abcde".split(//, 3)
=> ["a", "b", "cde"]
group_byメソッド
便利なのに自分の周りではイマイチ使われない気がするメソッド。
抽出したデータをさらに区分けしたい場合などに便利です。
# 抽出したユーザ情報を性別で分ける
[1] pry(main)> User.where(id: [1,2,3]).group_by{|u| u.sex == 1 ? :male : :female}
=> {:male=>[#<User...(以下略)>], :female=>[#<User...(以下略)>]}
# with_indexを利用して配列のindexをkeyとしたhash化も
[2] pry(main)> %w(a b c d).group_by.with_index{|v,i| i}
=> {0=>["a"], 1=>["b"], 2=>["c"], 3=>["d"]}
# Modelから抽出した際の順番を保持したい場合などにも便利
[3] pry(main)> users = User.where(id: [1,2,3])
[4] pry(main)> users.map(&:id).group_by.with_index{|v,i| i}
=> {0=>["ほげ1"], 1=>["ほげ2"], 2=>["ほげ3"]}
使いドコロが難しいけど、上手く使うと余計なループや分岐が減らせます。
grepメソッド、grep_vメソッド (grep_vはRuby2.3〜)
Ruby2.3で追加されたgrep_vメソッドをキッカケに知ったメソッド。
これを使ってリファクタリング出来そうな箇所が結構あるな。。。
# 配列の各要素に対し、正規表現で一致する要素を配列で返す
[1] pry(main)> %w(hoge piyo hogege bar hogegege).grep(/\Ahoge/)
=> ["hoge", "hogege", "hogegege"]
# ブロックを渡すと、正規表現に一致する要素に対し実行した結果を返す
[2] pry(main)> %w(hoge piyo hogege bar hogegege).grep(/\Ahoge/){|r| r.to_sym}
=> [:hoge, :hogege, :hogegege]
# Ruby2.3で追加されたgrep_vは、正規表現に一致しない要素を返す
[3] pry(main)> %w(hoge piyo hogege bar hogegege).grep_v(/\Ahoge/)
=> ["piyo", "bar"]
between?メソッド (Comparable module)
日付や数値などで範囲判定したい場合に使うと楽できる・・かもしれない。
仕事ではGWや年末年始などの日付判定に使っています。
# GWの判定ロジック(2016/04/29〜2016/05/08)
[1] pry(main)> Time.now.between?(Time.parse('2016/04/29 00:00:00'), Time.parse('2016/05/08 23:59:59'))
SQLの直接実行
便利というかみんな知ってるやり方かと思いきや、意外と若手の子が知らなかったので。
[1] pry(main)> users = ActiveRecord::Base.connection.select_all('SELECT id,name FROM users WHERE id IN (1,2,3)')
(0.2ms) SELECT id,name FROM users WHERE id IN (1,2,3)
=> #<ActiveRecord::Result:0x007f9dcf91b7...
# 戻りがActiveRecord::Resultのため扱いが違うので注意
[2] pry(main)> users.each{|u| p u['name']}
"ほげ1"
"ほげ2"
"ほげ3"