This page looks best with JavaScript enabled

【Ruby/Rails】シンプルに書ける小技メモ

 ·   ·  ☕ 4 分で読めます
✏️

自分がほえーと思った小技などをメモしておく。
全てがベストプラクティスというわけではないので、状況に応じて使い分けたい。

(4/18 追記)
コメントより、「もっと簡単な書き方がある」とご教示いただきましたので追加しました。ありがとうございました。

Safe Navigation Operator(ぼっち演算子)

1
articles = user.articles if user
1
articles = user&.articles

user.articlesだと、userがnilになる場合にNoMethodErrorエラーが出る。そのため、userがあるかどうかifで判定しようとするが、ぼっち演算子を使うとシンプルに表記できる。
userがnilの場合はuser&.articlesもnilになる。

user&.articles&.take&.tag&.nameのようにメソッドチェーンが長くなってもif文がネストすることがない。
ただし、user&.articles.take.tag.nameのようにすると、結局articles.takeのところでNoMethodErrorになるので注意。
NEWS for Ruby 2.3.0 (Ruby 2.7.0リファレンスマニュアル)

Hash#dig

1
2
3
data = { user: { name: '太郎',
                 tag: { id: 1,
                        name: "タグ" }}}
1
2
3
4
5
6
7
data[:user][:tag][:name]
=> "タグ"

data[:user][:article][:name] # :articleが存在しない=>nilの場合
Traceback (most recent call last):
        1: from (irb):9
NoMethodError (undefined method '[]' for nil:NilClass)
1
2
3
4
5
data.dig(:user, :tag, :name)
=> "タグ"

data.dig(:user, :article, :name)
=> nil

ネストされたハッシュやjsonからデータを取り出したいときに使える。途中のデータがnilのときに自動的にnilを返してくれる。
ぼっち演算子と少し似ている。
Hash#dig (Ruby 2.7.0リファレンスマニュアル)

render(objects) || message

1
2
3
4
5
<% if  @articles %>
  <%= render @articles %>
<% else  %>
  <%= "記事はありません" %>
<% end  %>
1
<%= render(@articles) || "記事はありません" %>

記事がないときのメッセージをifを使わず簡単に表示できる。
a = b || cの応用っぽい動き。

map(&:method)

1
2
3
4
5
numbers = ["1", "2", "3"]

numbers.map{ |n| n.to_i }

numbers.map(&:to_i)

mapeachのような配列のメソッドの書き方。(&:メソッド名)で中身のオブジェクトそれぞれにメソッドを実行できる。
&amp;演算子と、procと、Object#methodについて理解しなおす

if array.each do end.empty? end

1
2
3
4
5
6
7
if articles.empty?
  articles.each do |article|
    # ループ処理
  end
else
   # articlesに何も入っていない時の処理
end
1
2
3
4
5
if articles.each do |article|
  # ループ処理
end.empty?
  # articlesに何も入っていない時の処理
end

articles ... endを固まりとして、empty?メソッドで判定している。

これの是非については、rubyでeachをする際に、中身が空であれば別の処理をさせるのコメント欄で議論がされていました。あまりわかりやすい書き方ではないようです。

配列をフィルタリングする

元々nilが入っている配列からnilを除く場合はcompactを使う。

1
2
[1, 2, nil, 4, nil, 6].compact
=> [1, 2, 4, 6]

Array#compact (Ruby 2.7.0リファレンスマニュアル)

Enumerable#select/filter

filterはselectのエイリアス(Ruby2.6から)

1
tags.select{ |tag| tags.reload.include?(tag) }

条件などでフィルタリングしたい場合は、selectを使うと、{}内の条件に合うものだけを格納した配列として返す。
Enumerable#filter (Ruby 2.7.0リファレンスマニュアル)

Enumerable#filter_map(Ruby2.7から)

条件でフィルタリングした後で配列の中身に編集を加える場合はこのように書く。
(例は不適かもしれません)

1
2
3
tags.map do |tag|
  tag.user if tags.reload.include?(tag)
end.compact

Ruby2.7ではfilter_mapというメソッドが追加されたので、このように書くことができる。

1
tags.filter_map { |tag| tag.user if tags.reload.include?(tag) }

Module: Enumerable (Ruby 2.7.0)
Ruby 2.7がEnumerable#filter_mapを追加| Saelounブログ

Share on

END
END
@aiandrox

目次