Rails

Railsのいろんなメソッド

More than 3 years have passed since last update.

社内勉強会用にいくつかまとめたやつ。


ActionView


distance_of_time_in_words_to_now(from_time, include_seconds = false, options = {})

任意の時間からの差分を表示。(~分、~日)

"#{distance_of_time_in_words_to_now(article.updated_at)}前に更新"

# => "2日前に更新"


number_with_delimiter(number, options = {})

数字に区切り文字を入れてくれる。

"#{number_with_delimiter(12345678)}"

# => 12,345,678


highlight(text, phrases, *args)

textの中でphraseに一致するものがあれば、タグで囲ってくれる。

"#{highlight('You searched for: rails', 'rails')}"

# => "You searched for: <strong class='highlight'>rails</strong>"


ActiveRecord


ActiveRecord::Relation#first_or_create

そのクラスのテーブルの最初の要素があればそれを返し、無いならレコード作成。ブロックで使うと便利そう。

User.where(last_name: 'Elen').first_or_create

# 既にあった場合
# => <User id: 1, first_name: 'Jaeger', last_name: 'Elen'>

# 無かった場合
# => <User id: 2, first_name: nil, last_name: 'Elen'>


ActiveRecord::Relation#first_or_initialize

first_or_createメソッドと異なり、まだcreateしたくない場合はこっち。


ActiveRecord::Scoping::Named::ClassMethods#scoped

あるクラスの持つ全てのレコードを表したActiveRecord::Relationが欲しい時に使う。allだとArrayになっちゃうので。

※追記:Rails4.0からは、allメソッドでActiveRecord::Relationが返るようです。scopedはdeprecated?

User.scoped.class # => ActiveRecord::Relation

User.all.class # => Array


ActiveRecord::Persistence#toggle

booleanなカラム名を渡すと、trueとfalse入れ替え。

p @user.mail_flg # => true

@user.toggle(:mail_flg)
p @user.mail_flg # => false


ActiveSupport::Concern#included(base = nil, &block)

includeされたら、呼び出し側のクラスのコンテキストで実行される処理をブロックで書ける。

module Hoge

included do
scope :is_hoge, ->{where(hoge: true)}
end
end


ActiveRecord::Batches#find_each(options = {})

あるテーブルの全データ更新バッチ処理など、大量のデータをまとめて処理する時には必ず使うべき。

例えば以下の書き方だと、全ユーザーのActiveRecordオブジェクトの配列がallメソッドで作られ、メモリ上に展開される

User.all.each do |user|

...
end

find_eachを使えば、デフォルトで1,000件ずつ数え上げを行うので、メモリの使用量を節約できる。

User.find_each do |user|

...
end

※似たメソッドに、find_in_batchesというのもある。


ActiveRecord::Calculation#pluck(column_name)

あるテーブルの特定のカラムを配列にしたいときに使う。

mapを利用するより高速に動作する。

下記のようなよくある書き方だと、内部的に10,000万件のActiveRecordオブジェクトが作られて遅い。

User.order('id DESC').limit(10000).map(&:name)

User.order('id DESC').limit(10000).select(:name).map(&:name)

pluckを使うことで、ActiveRecordオブジェクトの生成を経由せずに、配列が返る。

User.order('id DESC').limit(10000).pluck(:name)

こちらのブログ記事でパフォーマンス検証をやっているが、mapを使う時と比較してかなり高速になってるのが分かる

http://blog.livedoor.jp/sasata299/archives/51847390.html

※ただし、Rails 3.2以上でしか使えない。

※Rails 3.2では、一度にpluckできるのは単一のカラムのみ。

 => multipluckというgemで複数カラムいけるらしいです

※追記:Rails4.0からはデフォルトで複数カラムのpluckが可能(なぜ初めからその仕様にしなかったのか...)

※Web+DBのrails高速化の回に載っていたが、Rails 3.0, 3.1のアプリは、 activerecord-raw-dataというgemを使うことで、同等な効果を得ることができるそう


そのほか拡張など


Object#presence

present?メソッドの評価結果がtrueのときはselfを、falseの時はnilを返す。

'hoge'.presence # => 'hoge'

[].presence # => nil

# 1 => 2のように、書き方がまどろっこしくなくなる!

# 1
name = params[:name].present? ? params[:name] : 'no name'
# 2
name = params[:name].presence || 'no name'


Object#try

こちらもまどろっこしい書き方が減って良い

# 1

user.name ? user.name : 'no name'
# 2
user.try(:name) || 'no name'


Array#from(position)

positionに渡したインデックスから配列の最後までを返す。

%w( a b c d ).from(2)  # => %w( c d )


Array#forty_two

[1, 100].forty_two # => 42

人生、宇宙、すべての答えは「42」なのである。