背景
自分は現在院生2回生で, 4回生のころから京都のゲーム・Web会社で働いている. 今も細々と続けている中で, Ruby on Railsに触れる機会があったのでその知見を貯めておく.
また, Ruby on Railsは型が決まった書き方があるので, 少ない行数に多くの情報を詰め込むことができて, 書き終わった後の見通しがとてもいいと思う. そんなオシャレな書き方を少し紹介したい.
使用するデータのスキーマとモデル
今回紹介するのは, SNSアプリのAPIの中身の一部である.
以下に, 端末の情報を持つdevice
テーブルと, ユーザーの情報をもつuser
テーブルを定義する.
ActiveRecord::Schema.define(version: 20_190_219_052_352) do
create_table "devices", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
t.bigint "user_id"
t.string "uuid"
t.integer "user_agent"
end
create_table "users", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
t.string "email", null: false
t.string "password_digest", null: false
end
end
user
とdevice
の関係は1対多であり, belongs_to
とhas_many
で関連付けされている. 以下にそれぞれもモデルを示す.
class User < ApplicationRecord
has_many :devices, dependent: :nullify
end
class Device < ApplicationRecord
belongs_to :user, optional: true
# deviceとuser_idを紐づける
def update_user_id(user)
user.devices << self
end
def shape_response
{ uuid: uuid }
end
end
オシャレな文法たち
上記データ構造をもとにおしゃれな文法たちを紹介する.
エラー処理が1行でかけちゃう
# deviceが存在しない または deviceがuser_idと紐づいている
device = Device.find_by(uuid: params[:device][:uuid])
error_response(404, "device is not found") && return if device.blank? || device.user.present?
ifのあと処理が1つしかないのであれば&&
でつないで1行で書いてしまう. これは, コードを解析してくれるrubocop
によって自動的にこの文法にしてくれる. また, error_response
の中身は以下のようになっている.
def error_response(code, message = nil)
render json: {
status: code,
message: message
}
end
余談
nil?
+ empty?
= blank?
↔︎ present?
空白文字列に対してはblank?
が真になるので厳密には違う. 参考
また,blank?
,とpresent?
はrubyではなくrailsのメソッドで,レコードに対する処理の話である.
変数のように関数を使う
# userのバリデーションを確認
user = User.new(user_params)
# 色々処理
end
private
def user_params
params.require(:user).permit(:name, :mail, :password, :password_confirmation)
end
rubyでは最後の返り値をreturnしなくでいいので, user_params
をこんな感じで定義して, こんな感じでぶっこめば動く. オブジェクト指向にあまり慣れていなくて, なんかスネイクで書かれると変数, キャメルだと関数みたいな感覚があるのでこれをみると気持ち悪く感じる.
追記
オブジェクト指向の定義をちゃんと理解しきれていないのかもしれませんが, 変数とメソッドの違いを意識しないところにオブジェクト指向を感じました.
リレーションを最大限に活用する
# deviceとuserを紐付ける
device.user = user
device.save
これぞrubyというような書き方. 他の言語だと, device
のuser_id
カラムにuser
のid
カラムの値をいれないと...みたいなことを考え始める必要があるが, 正しく関連づけができているrubyでは"紐づける"という文字通りに書ける.
rescue
はbegin
しなくてよい
def create
# 色々処理
rescue Exception::StandardError => e
error_response(500, e.message)
end
scaffoldとかでgenerateするときはbegin
~resucue
~end
が律儀に書かれているが, begin
はrescue
に飛ぶ範囲をしていするためだけのものであるので, 関数内のStandardError
のみを返す場合は最後にちょこっとかいておけばOK.
値がなかったらとってくる
def current_user
@current_user ||= @authorization.user
end
これは@current_user
が存在していたらそのまま@current_user
を返して, 存在していなかったら@authorization.user
を取ってきて@current_user
に代入して返す関数である. 初めてみるとわけわからん. 自己代入の考え方.
感想
rubyの書き方は型がかちっとしていて, 最初びくびくしながら書いて, 案の定間違った書き方みたいなことが多々ある. 慣れればどうやってもきれいなコードになりそうなので, ルールをしっかり覚えたい.