[Rails]よく作る、基本的な機能まとめ

## はじめに

WEBエンジニアとして勉強していて、「[Progate](https://prog-8.com/)や[ドットインストール](https://dotinstall.com/)は終わったけど、これで仕事ができるようになるの？」と疑問に思っている人向けに、個人的に**よく作る、基本的な機能**をまとめてみました。

ここでまとめている機能を一人で作れるようになれば、そのスキルを応用してより発展的な機能を作ることもできるのではないでしょうか。

また、この記事で書いている機能は、単体で完結する1つの機能というよりは、他の機能と連携させて機能するといった場合もあります。

タイトルにRailsと書いてますが、この記事で書いている機能については大体のWEBサービスでよく作るものだと思います。

## 対象となる方

- これから仕事でRailsを書いていく予定の人 :muscle: 
- WEBサービスってどんな機能があるのか知りたい人 :thinking: 

## 注意事項

この記事では以下のことは詳しく扱いません。

- 具体的な実装方法(他に多くの参考情報があるため)
- Ajax

サンプルコードとして、ブログアプリを想定したコードを書いています

## 目次

個人的によく作る、基本的な機能を10個あげました。

- CRUD機能
- 検索機能
- パスワード認証機能
- SNS認証機能
- メール送信機能
- ファイルアップロード機能
- 管理者機能
- 権限機能
- 論理削除機能
- API機能

それぞれの機能の概要と主に連携する機能、そして機能を提供するgemについて説明していきます。

それでは順番にいきましょう！

## CRUD機能

#### 概要

CRUD機能は、最も基本となる機能です。CRUDは「クラッド」と呼びます。
以下の4つの機能で構成されています。

1. 登録機能（Create）
2. 参照機能（Read）
3. 変更機能（Update）
4. 削除機能（Delete）

4つの頭文字をとってCRUDと言われています。

それぞれ簡単に解説します。

1. 登録機能（Create）

データベースに情報を登録するための機能です。
SQLだと`INSERT`が実行されます。
基本的には情報を入力するフォームと登録するためのボタンがあり、ボタンを押すことで入力された情報をデータベースに保存するといった形が多いです。

注意点として、特定のページにアクセスしたときにPV数を記録する、といった仕様のときはフォームはないので、データを表示する処理の中でデータベースに保存するといった必要があります。

```rb:posts_controller.rb
def create
  @post = Post.new(post_params)
  if @post.save
    redirect_to @post, notice: 'ブログを投稿しました'
  else
    render :new
  end
end
```

2. 参照機能（Read）

データベースから情報を取り出すための機能です。
SQLだと`SELECT`が実行されます。
基本的には情報を表示するページで使います。

注意点として、情報は何度も表示されることが多いので、表示すると同時に他の情報の登録や変更をするようなコードを書いた場合は、データが増えても本当に問題ないか検討したほうがいいと思います。

```rb:posts_controller.rb
def index
  @posts = Post.all
end

def show
  @post = Post.find(params[:id])
end
```

3. 変更機能（Update）

データベースにある情報を変更するための機能です。
SQLだと`UPDATE`が実行されます。
データベースに既にある情報に対して、情報を入力するフォームと変更するためのボタンがあり、ボタンを押すことで入力された情報で上書きします。
登録機能（Create）と似たようなコードになることがあります。

```rb:posts_controller.rb
def update
  @post = Post.find(params[:id])
  if @post.update(post_params)
    redirect_to @post, notice: 'ブログを更新しました'
  else
    render :edit
  end
end
```

4. 削除機能（Delete）

データベースにある情報を削除するための機能です。
SQLだと`DELETE`が実行されます。
データベースに既にある情報に対して、削除したいときに使います。

注意点として、削除するときに関連する他の情報を消したほうが良いときがあります。
Railsだとdependentオプションを追加することで対応できます。

```rb:posts_controller.rb
def destroy
  @post = Post.find(params[:id])
  @post.destroy
  redirect_to posts_url, notice: 'ブログを削除しました'
end
```

```rb:post.rb
has_many :comments, dependent: :destroy
#=> 'dependent: :destroy'を追加すると、postを削除したときに関連するcommentsも全て削除される
```

#### 主に連携する機能

- ほとんど全部の機能

#### gem

- 特になし
- RailsのScaffoldコマンドなら自動的にCRUD機能が作られます

## 検索機能

![無題のスプレッドシート_-_Google_スプレッドシート.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100766/32cea77c-09ba-c0f2-8ac7-a7e687779a0c.png)

#### 概要

検索機能はデータベースに保存されている情報の中から、特定の条件に一致するデータを取得するときに使います。
CRUDの参照機能（Read）と合わせて作ることが多いです。
SQLだと`WHERE`を指定して`SELECT`が実行されます。

Railsだと一覧画面に検索条件を入力するフォームがあることが多いです。
あと個人的には、検索条件をリセットするボタンをつけたほうが良いと思います。
これは単純に一覧画面へのリンクにして、ボタンの名前を「検索条件をリセット」でいいと思います。

```erb:index.html.erb
<%= link_to '検索条件をリセット', posts_path %>
```

#### 主に連携する機能

- [CRUD機能](#CRUD機能)

#### gem

- [ransack](https://github.com/activerecord-hackery/ransack)

## パスワード認証機能
![無題のスプレッドシート_-_Google_スプレッドシート.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100766/b1c2b752-293c-38b5-804c-4a7711b6f257.png)

#### 概要
パスワード認証機能は、メールアドレスとパスワードの２つを入力してデータベースに保存されているユーザーと一致したらログインさせるといった機能になります。
SQLだと`WHERE`を指定して`SELECT`が実行されます。
具体的には、まず入力されたメールアドレスに一致するユーザーを取得して、入力されたパスワードがあっているかを判定します。
パスワードはハッシュ化してデータベースに保存します。

Railsだと`ログイン状態`にするには、sessionにユーザー情報を保存することが多いです。

```rb:sessions_controller.rb
def create
  user = User.find_by(email: params[:user][:email].downcase)
  if user && user.authenticate(params[:user][:password])
    session[:user_id] = user.id
    redirect_to root_url
  else
    render :new
  end
end
```

#### 主に連携する機能
- [CRUD機能](#CRUD機能)

#### gem
- [bcrypt](https://github.com/codahale/bcrypt-ruby)
- [devise](https://github.com/heartcombo/devise)

## SNS認証機能
![無題のスプレッドシート_-_Google_スプレッドシート.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100766/225e43fe-12a6-3602-1019-b68856c896b6.png)

#### 概要
SNS認証機能は、FacebookやGoogle、TwitterなどのSNSに登録されているユーザー情報を取得して、自分で作ったアプリにログインさせるといった機能になります。
各SNSでは、アプリケーションの登録作業が必要です。
例えば、Facebookでは、開発者登録をしてアプリ登録を行うことでSNS認証に必要なアプリIDとSecretIDを取得できます。それらを環境変数で読み込むといったことが多いです。
また、SNSから取得できるユーザー情報は、SNSによって形式が異なることがほとんどです。

Railsでは、omniauthを使うことでそういった異なる形式を一つの統一された形式に変換してくれます。

#### 主に連携する機能

- [パスワード認証機能](#パスワード認証機能)
- [CRUD機能](#CRUD機能)

#### gem

- [devise](https://github.com/heartcombo/devise)
- [omniauth](https://github.com/omniauth/omniauth)
- [omniauth-facebook](https://github.com/simi/omniauth-facebook)
- [omniauth-google-oauth2](https://github.com/zquestz/omniauth-google-oauth2)
- [omniauth-twitter](https://github.com/arunagw/omniauth-twitter)

## メール送信機能
![sozai_cman_jp_20200801150437.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100766/5287abde-4355-120f-e5bc-b87b7e14fa1e.png)


#### 概要
メール送信機能は、何らかのアクションがあった時にユーザーに通知するためにメールを送信といった機能になります。
例えば、会員登録したユーザーにメールを送ったり、重要な情報をリマインドするためにメールを送ったりします。
メールを送る前にテンプレートを用意しておき、テキスト形式またはHTML形式でメールを送信します。
HTML形式ではCSSを使ってリッチなコンテンツを送信することができますが、CSSはインラインで書いたり、テーブルレイアウトを使ったほうが良い等、いくつかポイントがあります。

Railsでは、メール送信をするためにはSMTPの設定をする必要があり、個人的には[Sendgrid](https://sendgrid.kke.co.jp/)を使うことが多いです。
開発環境では実際にメールを送信しなくても、本文を確認することができる便利なgemもあります。

#### 主に連携する機能

- [CRUD機能](#CRUD機能)
- [パスワード認証機能](#パスワード認証機能)
- [SNS認証機能](#SNS認証機能)

#### gem

- [letter_opener](https://github.com/ryanb/letter_opener)
- [sendgrid-ruby](https://github.com/sendgrid/sendgrid-ruby)
- [premailer-rails](https://github.com/fphilipe/premailer-rails)

## ファイルアップロード機能
![無題のスプレッドシート_-_Google_スプレッドシート.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100766/cc127067-8568-7d64-07a8-744bd98a757d.png)

#### 概要
ファイルアップロード機能は、ユーザーが選択した画像ファイル等をアップロードできる機能になります。
例えば、プロフィール画像を変更したり、サムネイル画像を変更したり、またはPDFファイルを添付するといった使い方があります。
基本的にはアップロードしたファイルは、S3などのクラウドストレージに保存するようにして、アプリ内では保持しないようにします。
また、ファイルを選択した時にJavascriptでプレビュー表示をすることも多いです。

Railsでは標準でActiveStorageを使ったシンプルなアップロード機能が提供されています。
より細かいカスタマイズが必要な場合は、carrierwaveなどのgemを使うこともあります。

#### 主に連携する機能

- [CRUD機能](#CRUD機能)

#### gem

- [carrierwave](https://github.com/carrierwaveuploader/carrierwave)

## 管理者機能
![Dashboard___Active_Admin_Depot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100766/625fd63e-ac65-f7ea-8ce5-c21132a16325.png)

#### 概要
管理者機能は、CMSなどのように、アプリ内の情報を管理するために管理者を用意する機能です。
ユーザーが見る画面と、管理画面といった形で分けて実装することがあります。
基本的には、管理者アカウントを作成して、各データをCRUDで操作したり、メール送信を行ったりしますが、管理するための多くの機能が含まれていることが多いです。

Railsでは、gemを使ったりnamespaceを使ってユーザーと管理者を分けるといった方法があります。

```rb:routes.rb
# 管理者のルーティング(全ての操作ができる)
namespace :admin do
  resources :posts
end

# ユーザーのルーティング(閲覧のみできる)
resources :posts, only: %i[index show]
```

#### 主に連携する機能

- [CRUD機能](#CRUD機能)
- [パスワード認証機能](#パスワード認証機能)
- [メール送信機能](#メール送信機能)
- [ファイルアップロード機能](#ファイルアップロード機能)
- [権限機能](#権限機能)
- [API機能](#api機能)

#### gem

- [activeadmin](https://github.com/activeadmin/activeadmin)
- [devise](https://github.com/heartcombo/devise)

## 権限機能
![無題のスプレッドシート_-_Google_スプレッドシート.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100766/4f0a928d-6a1a-896f-3f3c-456c5103bd28.png)

#### 概要
権限管理は、ユーザーによって出来ること、出来ないことを管理するための機能です。
例えば、管理者はデータの削除ができるけど、一般は削除できないといった感じです。
また、管理者には削除ボタンを表示するけど、一般には表示しないというように見た目も気にする必要があります。
よくあるのが、ユーザーに管理者フラグのようなカラムを追加して判断するといったものがあります。

Railsでは、自分で実装するかgemを使った方法があります。
個人的には権限が1つくらいなら自前で実装したほうが楽ですが、複数の権限がある場合にはgemを使ったほうがシンプルに実装できると思います。

```rb:posts_controller.rb
# 管理者のみ削除できる
def destroy
  return redirect_to root_path unless current_user.is_admin?

  @post = Post.find(params[:id])
  @post.destroy
  redirect_to posts_url, notice: 'ブログを削除しました'
end
```

#### 主に連携する機能

- [CRUD機能](#CRUD機能)
- [管理者機能](#管理者機能)

#### gem

- [pundit](https://github.com/varvet/pundit)
- [cancancan](https://github.com/CanCanCommunity/cancancan)

## 論理削除機能
![無題のスプレッドシート_-_Google_スプレッドシート.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100766/c8eaf50a-c3cc-71fb-7d3a-ce1402e0e2d3.png)

#### 概要
論理削除機能は、削除機能と違って、データを削除するのではなく、削除フラグなどを使って残しておく機能です。
CRUD機能の削除は物理削除といって、SQLだと`DELETE`でしたが、論理削除では`UPDATE`を実行します。
削除フラグをUPDATEしてONにする感じです。

Railsでは、自分で実装するかgemを使った方法があります。
どちらにも共通して、多いのは`deleted_at`のようなカラムを用意して削除した日付を記録するといった方法です。

#### 主に連携する機能

- [CRUD機能](#CRUD機能)

#### gem

- [paranoia](https://github.com/rubysherpas/paranoia)
- [discard](https://github.com/jhawthorn/discard)

## API機能
![Json_-_Free_interface_icons.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100766/0c18ef85-4f0d-895a-85b6-4d0224b8b330.png)

#### 概要
API機能は、アプリ内の情報を他のアプリに連携できるようにする機能です。
連携するときのフォーマットは`JSON`が多いです。
例えば、カレンダーアプリとタスク管理アプリを作ったとして、カレンダーの予定が登録されたらタスク管理アプリに新規でタスクを追加したい、といった時にAPIで情報を連携するといった使い方があります。
他にも、データを管理するAPIサーバーと、データを表示するフロントエンドアプリケーションの2つを連携しながら開発することもあります。

Railsでは標準でAPIモードという機能があり、これを利用することでAPI専用のアプリを作ることができます。
もちろん、通常のRailsアプリを作っていて、あとからAPI機能を追加するといったことも可能です。

```rb:posts_controller.rb
def index
  posts = Post.all
  render json: posts
end
```

#### 主に連携する機能

- [CRUD機能](#CRUD機能)

#### gem

- [ActiveModelSerializers](https://github.com/rails-api/active_model_serializers)
- [fast_jsonapi](https://github.com/Netflix/fast_jsonapi)

## まとめ

以上、いかがでしょうか？

今回は個人的によく作る、基本的な機能を10個あげました。

- CRUD機能
- 検索機能
- パスワード認証機能
- SNS認証機能
- メール送信機能
- ファイルアップロード機能
- 管理者機能
- 権限機能
- 論理削除機能
- API機能

特に`CRUD機能`は必ずといってもいいほど、よく作ります。
実際に、Railsアプリを開発するときも、CRUD機能を中心にして、他の機能を作っていくことが多いです。

これらを一人で実装できれば、ある程度のスキルはあるのではないでしょうか。
また、初めて参加したプロジェクトでコードを読む時にも役に立つと思います。


この記事について、何かありましたらお気軽にコメントください :smiley: