こんにちは、冗長コード量産検定1級所持の嶋村です。
これは active?
メソッドを満たす Hoge オブジェクトを配列で返してくれるメソッド。
def active_hoges hoges = Hoge.all hoges.map do |hoge| next if hoge.active? hoges.delete(hoge) end hoges.to_a end
全件取得してから非activeを削除してる。長いね。プログラミング始めたてかな。
each
each で頑張れるのでは。
最初から配列用意してそれ返せば to_a もなくて楽ね。
def active_hoges actives = [] Hoge.all.each { |hoge| actives.push(hoge) if hoge.active? } actives end
3行。ふむ。
inject
inject とかあったなぁ。
def active_hoges Hoge.all.inject([]) { |actives, hoge| actives.push(hoge) if hoge.active? } end
1行。行数は素晴らしいけど可読性はどうなんでしょう。横に長えし。
と思ったら無効な Hoge が存在するとnilで返ってきた。詰み。
reject
条件を満たす要素を配列から削除
def active_hoges Hoge.all.reject { |hoge| hoge.active? } end
いやこれ逆ーーーーー
def active_hoges Hoge.all.reject { |hoge| !hoge.active? } end
これか
と思ったら Rubocop に select 使えと怒られた
select
Hash#select は自身の要素から特定の条件を満たす要素だけを採用した新たなハッシュを生成して返すもの。Hash#rejectはその論理反転であり,自身の要素から特定の条件を満たす要素だけを取り除いた新たなハッシュを生成して返すもの。
これじゃん…
def active_hoges Hoge.all.select { |hoge| hoge.active? } end
したらまだ冗長と怒れれる
def active_hoges Hoge.all.select { :active? } end
でもこれだと結果がおかしい
これだと ActiveRecord_Relation#select になるのでは?やりたいのは Enumerable#select の方だな…
と思って調べると ActiveRecordのRelation は Enumerable をインクルードしてるらしい
selectもfindと同じように、引数を渡すかコードブロックを渡すか挙動が変わります。引数(カラム名)を渡した時のselectは、引数のカラムの値だけを取ってきて、その値のみが入ったオブジェクトを返すものです。( SQLクエリは “SELECT `args` FROM table_name …” のようになります)。コードブロックを渡した時のselectは、Arrayのselectです。コードブロックに渡したときtrueを返すものの配列を返します。
コードブロックを渡すと Array の select として動くらしい。
Hoge.all.select { |hoge| hoge.active? }
の挙動がまさにそう。
いやまった
def active_hoges Hoge.all.select(&:active?) end
これで動いた
& 使うときはコードブロックじゃなく普通の()
ちなみにこの & については下記記事参照
before
def active_hoges hoges = Hoge.all hoges.map do |hoge| next if hoge.active? hoges.delete(hoge) end hoges.to_a end
after
def active_hoges Hoge.all.select(&:active?) end
う〜ん、短い。嬉しい。
追記
ActiveRelation を返してくれる scope 用意すればいいのでは。
配列にしたい用事があるなら to_a
すればいいし。
scope :active, -> { where(...) }