Ruby on Railsで認証付きの基本的なブログを作る

こんにちは！エンジェルと申します。
# はじめに
最近私はRuby on Railsについて勉強しています。 言語に関する基本的な機能をいくつか共有したいと思います。

このリンクにWindowsのためにRuby on Railsをダウンロードすることができます。 
https://rubyinstaller.org/

各モジュールのバージョンは下記のとおりです。

```
$ ruby -v
ruby 2.5.3p105 (2018-10-18 revision 65156) [x64-mingw32]
$ rails -v
Rails 5.2.3
```
# 概要
**Railsにこれから初めて触れる方を対象にしたチュートリアルです。**
- データベースとしてmysqlを使用する
- ScaffoldでCRUDを作成。(Create, Read, Update, Delete)
- Deviceを介して認証を追加する
     - ログインユーザーだけがポストを見られる
     - 自分のポストの編集と削除ができる

# Railsアプリのひな形まで作成
```
rails new blog -d mysql
```

`-d mysql`の意味はブログのデータベースとしてmysqlを使うことです。
データベースを構成する:

```ruby:config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: 5
  username: root
  password: 
  host: localhost
development:
  <<: *default
  database: ruby_blog
  charset: utf8mb4
  collation: utf8mb4_bin
  encoding: utf8mb4
```

次ステップは：

```
$ cd blog
$ rake db：create
```

`$ rake db：create`を使てデータベースを作成することができます。

# ScaffoldでCRUDを作成
```
$ rails g scaffold post title:string content:text
```
`post`はMVCの名前になります。
この`title:string`と`content:text`はMigrationに追加します。

```ruby:db/migrate/20190402141912_create_posts.rb
class CreatePosts < ActiveRecord::Migration[5.2]
  def change
    create_table :posts do |t|
      t.string :title
      t.text :content

      t.timestamps
    end
  end
end
```

その後、マイグレーションを行います。

```
$ rails db:migrate
```

サーバを動かすには `$ rails s`を使用することができます。
これで `localhost：3000 / posts`を開くことができます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/326049/5ac9e330-57cc-21de-0599-e1d6403bd4c2.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/326049/6e343015-ad8f-f339-479c-4efddc75cd33.png)


この時点で、CRUD機能を使用することができます。

# deviseのインストール



でも、ポストの許可を指定しなければなりません。
- ログインしている人だけがポストを見ることができます。
- ポストのオーナーだけが自分のポストを編集と削除できます。

Deviseを使てこれを作成することができます。


```ruby:GemFile
gem 'devise'
```
Gemをインストールです。

```
$ bundle install
Using devise 4.6.2
```
それから、Deviseをインストールです。

```
$ rails g devise:install
      create  config/initializers/devise.rb
      create  config/locales/devise.en.yml
===============================================================================

Some setup you must do manually if you haven't yet:

  1. Ensure you have defined default url options in your environments files. Here
     is an example of default_url_options appropriate for a development environment
     in config/environments/development.rb:

       config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

     In production, :host should be set to the actual host of your application.

  2. Ensure you have defined root_url to *something* in your config/routes.rb.
     For example:

       root to: "home#index"

  3. Ensure you have flash messages in app/views/layouts/application.html.erb.
     For example:

       <p class="notice"><%= notice %></p>
       <p class="alert"><%= alert %></p>

  4. You can copy Devise views (for customization) to your app by running:

       rails g devise:views

===============================================================================
```

基本的なブログを作成しているだけなので、今のところ設定しなくても大丈夫です。

# deviseのユーザモデル

```
$ rails g devise User
      invoke  active_record
      create    db/migrate/20190403022115_devise_create_users.rb
      create    app/models/user.rb
      invoke    test_unit
      create      test/models/user_test.rb
      create      test/fixtures/users.yml
      insert    app/models/user.rb
       route  devise_for :users
```

マイグレーションを直します。

```ruby:db/migrate/20190403022115_devise_create_users.rb
class DeviseCreateUsers < ActiveRecord::Migration[5.2]
  def change
    create_table :users do |t|
      ## Database authenticatable
      t.string :email,              null: false, default: ""
      t.string :encrypted_password, null: false, default: ""

      ## Recoverable
      t.string   :reset_password_token
      t.datetime :reset_password_sent_at

      ## Rememberable
      t.datetime :remember_created_at

      t.timestamps null: false
    end
  end
end
```

これが基本的なブログに必要な唯一のAuthenticationです。

# ScaffoldとDeviseを結ぶ
まず、ポストテーブルに `user_id`を追加して。

```
$ rails generate migration add_user_id_to_posts user_id:integer
      invoke  active_record
      create    db/migrate/20190403022836_add_user_id_to_posts.rb
```

このコマンドは機能的なMigrationファイルを生成します。 これに関しては、編集する必要はありません。


```ruby:db/migrate/20190403022836_add_user_id_to_posts.rb
class AddUserIdToPosts < ActiveRecord::Migration[5.2]
  def change
    add_column :posts, :user_id, :integer
  end
end
```
マイグレーションを実行するには `$ rails db：migrate`を使います。
Post Controllerを直します。

```ruby:app/controllers/post_controller.rb
class PostsController < ApplicationController
  before_action :authenticate_user!
  before_action :set_post, only: [:show, :edit, :update, :destroy]

  def index
    @posts = Post.all
  end

  def show
  end

  # GET /posts/new
  def new
    @post = Post.new
  end

  # GET /posts/1/edit
  def edit
  end

  def create
    @post = Post.new(post_params)
    @post.user_id = current_user.id

    respond_to do |format|
      if @post.save
        format.html { redirect_to @post, notice: 'Post was successfully created.' }
        format.json { render :show, status: :created, location: @post }
      else
        format.html { render :new }
        format.json { render json: @post.errors, status: :unprocessable_entity }
      end
    end
  end

  def update
    respond_to do |format|
      if @post.update(post_params)
        format.html { redirect_to @post, notice: 'Post was successfully updated.' }
        format.json { render :show, status: :ok, location: @post }
      else
        format.html { render :edit }
        format.json { render json: @post.errors, status: :unprocessable_entity }
      end
    end
  end

  def destroy
    @post.destroy
    respond_to do |format|
      format.html { redirect_to posts_url, notice: 'Post was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_post
      @post = Post.find(params[:id])
    end

    def post_params
      params.require(:post).permit(:title, :content)
    end
end
```


`before_action：authenticate_user！`を追加することで、ユーザーはポストにアクセスする前に最初にログインしなければなりません。
createクラス内に "@ post.user_id = current_user.id"を追加すると、ポストした現在のユーザーのIDを取得できます。

Viewを直します。

```ruby:app/views/posts/index.erb
<h1>Posts</h1>

<table>
  <thead>
    <tr>
      <th>Title</th>
      <th>Content</th>
      <th colspan="3"></th>
    </tr>
  </thead>

  <tbody>
    <% @posts.each do |post| %>
      <tr>
        <td><%= post.title %></td>
        <td><%= post.content %></td>
        <td><%= link_to 'Show', post %></td>
        <% if post.user_id == current_user.id %>
          <td><%= link_to 'Edit', edit_post_path(post) %></td>
          <td><%= link_to 'Destroy', post, method: :delete, data: { confirm: 'Are you sure?' } %></td>
        <% end %>      
      </tr>
    <% end %>
  </tbody>
</table>

<br>

<%= link_to 'New Post', new_post_path %>
```

ほとんどのファイルは既にScaffoldのコマンドによって生成されています。だからいくつかの部分を編集するだけがあります。

ブラウザから「http://localhost:3000/users」
にアクセスすることができます。


しかし、ログインページにリダイレクトされます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/326049/ce5bfc18-e6ab-8124-df53-88e4442ed0f0.png)

だから、Sign-upをクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/326049/e7d68330-5d0b-5e2b-ea5b-fe268b6a3091.png)

その後、ポストことができます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/326049/bfc7bef4-c7aa-67cf-0aab-7623856175e6.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/326049/f1facb60-d2e8-56d0-e06a-77939540c84f.png)


以上です。ありがとうございました。