【rails】通知機能

# 開発環境
* ruby 2.6.3　　
* rails 6.0.2

# あらすじ
* 【オプション課題1: 終了間近や期限の過ぎたタスクがあった場合、アラートを出したいという課題】を通して。
* 終了期限が切れたり、期限間際で通知するような仕組みを導入します。

# 通知モデルを作成
```ruby:ターミナル
rails g model notification user:references task:references action:integer checked:boolean
```

```ruby:db/migrate
class CreateNotifications < ActiveRecord::Migration[6.0]
  def change
    create_table :notifications do |t|
      t.references :task, null: false, foreign_key: true
      t.references :user, null: false, foreign_key: true
      t.integer :action
      t.boolean :checked, default: false, null: false

      t.timestamps
    end
  end
end

```

* actionで通知の種類を分類し、checkedで未読、既読を識別する。

```ruby:ターミナル
rails db:migrate
```
# モデル各種
* taskの期限が近づいたり、過ぎたりで通知を出すのでtaskとnotificationは`1対1`です。

#　Userモデル
```ruby:app/models/user.rb
class User < ApplicationRecord
  has_many :notifications, dependent: :destroy
end
```

# Taskモデル
```ruby:app/models/task.rb
class Task < ApplicationRecord
  belongs_to :user
  has_one :notification, dependent: :destroy
end
```
# Notificationモデル
```ruby:app/models/ntification.rb
class Notification < ApplicationRecord
  default_scope->{order(created_at: :desc)}

  belongs_to :task
  belongs_to :user

  enum action: { warning: 1, expired: 2}
end
```
### enumとは
* [【Rails】Enumってどんな子？使えるの？](https://qiita.com/ozackiee/items/17b91e26fad58e147f2e)


```
enum カラム名: {名前定義:数値}
列挙型であり実際に登録するときは名前定義の方をsaveします。
```

# view側
* 一覧が確認できればいいのでindexのみです。

```ruby:
rails g controller notifications index
```
```ruby:config/routes.rb
Rails.application.routes.draw do
  resources :notifications,only: [:index]
end
```
```ruby:app/controllers/notifications_controller.rb
class NotificationsController < ApplicationController
  def index
    @notifications = current_user.notifications
    @notifications.where(checked: false).each do |notification|
      notification.update(checked: true)
    end
  end
end
```
* indexにアクセスすると既読にさせます。

# 通知の未読、既読を知らせる
```ruby:app/views/layouts/_header.html.slim
- if unchecked_notifications.any?
  p.text-danger ★
= link_to "通知",notifications_path, class: 'nav-link'
```
```ruby:app/helpers/notifications_heler.rb
module NotificationsHelper
  def unchecked_notifications
    @notifications = current_user.notifications.where(checked: false)
  end
end
```
```ruby:app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  include NotificationsHelper
end
```

# 定期実行させるためにrakeタスクを作成
* [【Ruby on Rails】Rakeタスクを使えば様々な処理が自動化出来る？（初心者向け）](https://opiyotan.hatenablog.com/entry/rails-rake-task)

```
Rakeとは
そもそもRakeですが、Rubyで書かれたコードをタスクとして作成しておき必要に応じて呼び出し実行する事が出来る機能です。

rakeタスクを利用する場面としては、こんなのが有ります。

何かしらのデータの連携
データベースのバックアップ
定期的にデータを更新、削除する
```
`オートロード対象となるパスの追加`についてはうまく行かなかったので直接rakeファイルに書きます。

* [RailsでRakeタスクの作成](https://qiita.com/suzuki-koya/items/787b5562d2ae1a215d94)

```ruby:
rails g task notification
rails g task ファイル名
```
* 今日の日付からそれぞれの期限でDBをcreateさせていく。

```ruby:lib/tasks/notification.rake
namespace :task do
  desc "notification/一日に一回動かす。"
  task :notification => :environment do
    today = Date.today
    tasks = Task.all
    n = tasks.count
    today = Date.today
    tasks.each do |task|
      user = task.user
      if today + 1 == task.deadline.to_date
        Notification.create(task_id: task.id, user_id: user.id, action: "warning")
      end
      if task.notification.nil? && today > task.deadline.to_date
        Notification.create(task_id: task.id, user_id: user.id, action: "expired")
      elsif task.notification.present? && today > task.deadline.to_date
        task.notification.update(action: "expired")
      end
      n -= 1
      puts "残り#{n}/#{tasks.count}"
    end
  end
end
```
## 実行
```
rake tasks:notification
rake [namespeceの名前]:[taskの名前]
```

# 本番環境に向けて
私の場合はherokuなので`heroku scheduler`を使うようです。
またまとめます。  
`gem:whenever`はcrontabに追記/書き換えしてくれてるgemです。
*[WHENEVER勘違いしてたからHEROKUで動くわけなかった](https://sanematsu.wordpress.com/2012/11/25/whenever/)
# 【追記】heroku scheduler導入
* [Heroku Scheduler](https://haayaaa.hatenablog.com/entry/2019/03/01/222221)  
1.`heroku addons:add scheduler:standard`  
2.`Heroku Scheduler上で実行したい時間とタスクを設定`  

```herokuでのrakeコマンド
heroku run rake task:notification
```