0
1

More than 3 years have passed since last update.

Rails入門5: deviseのユーザー情報を利用しよう

Posted at

Rails入門5: deviseのユーザー情報を利用しよう


#01:掲示板でユーザー情報を使おう
このレッスンでは、Scaffoldで作成した1行掲示板に、deviseを使ってユーザー認証機能を追加します。まずは、どのような機能を作るのか整理しましょう。

このレッスンで作る掲示板
- deviseで作成したユーザー認証に、1行掲示板を組み合わせる
- ログインしている時だけ投稿できる
- 投稿者名をdeviseのユーザー名にする
- 自分の投稿だけ、編集・削除できる

作成手順
- ログイン時だけ投稿できる掲示板を作る
- 1行掲示板の記事に、Emailを表示する
- Userモデルに、nameカラムを追加する
- Userモデルに、ユーザー名を保存する
- 投稿時にログインユーザー名を保存
- 自分の記事だけを編集・削除

参考になるWebページ
- [ASCII.jp:ユーザー認証でなにができるのですか?|セキュリティの素朴な疑問を解く]
http://ascii.jp/elem/000/000/436/436614/


#02:ログイン時だけ投稿できる掲示板を作ろう
ここでは、前回のレッスンで作成したユーザー認証機能を利用して、1行掲示板へのアクセスを制御します。誰でも記事を表示できて、登録したユーザーだけが新しい記事を投稿・編集できるようにしましょう。

1行掲示板を作成する

$ cd bbs_users
$ rails g scaffold article user_id:integer content:string
$ rails db:migrate

掲示板の初期データを投入する
db/seeds.rb

Article.create(user_id: 1, content: 'hello world')
Article.create(user_id: 1, content: 'hello paiza')
Article.create(user_id: 2, content: '世界の皆さん、こんにちは')

データベースに反映するには、次のコマンドを実行する

$ rails db:seed

ログイン時に、特定のアクションだけ実行できるようにする
articles_controller.rb

before_action :authenticate_user!, only: [:new, :create, :edit, :update, :destroy]
before_action :set_article, only: [:show, :edit, :update, :destroy]


演習課題「ユーザーログインに初期ユーザーを登録する・作成する」
右の環境には、「myblog」プロジェクトに「talk」という1行掲示板が作成されています(user_idとcontentというカラムを持っています)。

ここに、以下の初期投稿を登録してください。この時、seed.rbファイルで一括登録します。

  • user_id: 1, content: '吾輩は猫である'
  • user_id: 1, content: '名前はまだない'
  • user_id: 2, content: 'どこで生まれたか'
  • user_id: 3, content: 'とんと見当がつかぬ'
  • user_id: 1, content: 'なんでも'

採点して、すべてのジャッジに正解すれば、演習課題クリアです!


模範解答1
/home/ubuntu/myblog/db/seed.rbファイルに登録するデータを記述する。

Talk.create(user_id: 1, content: '吾輩は猫である')
Talk.create(user_id: 1, content: '名前はまだない')
Talk.create(user_id: 2, content: 'どこで生まれたか')
Talk.create(user_id: 3, content: 'とんと見当がつかぬ')
Talk.create(user_id: 1, content: 'なんでも')


演習課題「ログインしているときだけ投稿・編集・削除」
右の環境には、「myblog」プロジェクトに「talk」という1行掲示板が作成されています(user_idとcontentというカラムを持っています)。また、ユーザー認証構築用にdeviseを導入して、「User」というモデルを作成してあります。

この環境で、ログインしているユーザーだけが編集・削除できるように、talk_controllers.rbファイルを設定してください。編集・削除に対応するのは、以下のアクションです。

  • edit
  • update
  • destroy

採点して、すべてのジャッジに正解すれば、演習課題クリアです!

模範解答1
/home/ubuntu/myblog/app/controllers/talks_controller.rbに次の内容を記述する

class TalksController < ApplicationController
  before_action :authenticate_user!, only: [:edit, :update, :destroy]
  before_action :set_talk, only: [:show, :edit, :update, :destroy]

  # GET /talks
  # GET /talks.json
  def index
    @talks = Talk.all
  end

  # GET /talks/1
  # GET /talks/1.json
  def show
  end

  # GET /talks/new
  def new
    @talk = Talk.new
  end

  # GET /talks/1/edit
  def edit
  end

  # POST /talks
  # POST /talks.json
  def create
    @talk = Talk.new(talk_params)

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

  # PATCH/PUT /talks/1
  # PATCH/PUT /talks/1.json
  def update
    respond_to do |format|
      if @talk.update(talk_params)
        format.html { redirect_to @talk, notice: 'Talk was successfully updated.' }
        format.json { render :show, status: :ok, location: @talk }
      else
        format.html { render :edit }
        format.json { render json: @talk.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /talks/1
  # DELETE /talks/1.json
  def destroy
    @talk.destroy
    respond_to do |format|
      format.html { redirect_to talks_url, notice: 'Talk was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

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

    # Never trust parameters from the scary internet, only allow the white list through.
    def talk_params
      params.require(:talk).permit(:user_id, :content)
    end
end

#03:1行掲示板にEmailアドレスを表示しよう
ここでは、ユーザーの情報を掲示板に利用します。ここでは、投稿一覧にユーザーのメールアドレスを表示しましょう。

ArticlesモデルとUserモデルを関連付ける
model/article.rb

class Article < ApplicationRecord
belongs_to :user
end

投稿者のメールアドレスを表示する
iews/articles/index.html.erb

User Content

Welcomeページから、掲示板にリンクする
index.html.erb

Welcome#index

Find me in app/views/welcome/index.html.erb

<%= link_to "articles", articles_path %>

ナビゲーションを共通で表示する
app/views/layouts/application.html.erb


<% if user_signed_in? %>
Logged in as <%= current_user.email %>.
<%= link_to "Settings", edit_user_registration_path %> |
<%= link_to "Logout", destroy_user_session_path, method: :delete %>
<% else %>
<%= link_to "Sign up", new_user_registration_path, :class => 'navbar-link' %> |
<%= link_to "Login", new_user_session_path, :class => 'navbar-link' %>
<% end %>

<%= notice %>


<%= alert %>


<%= yield %>

演習課題「掲示板とユーザーを関連付ける」
右の環境には、「myblog」プロジェクトに「talk」という1行掲示板が作成されています(user_idとcontentというカラムを持っています)。また、ユーザー認証構築用にdeviseを導入して、「User」というモデルを作成してあります。

掲示板の投稿一覧では、Userモデルのメールアドレスを表示するようになっていますが、エラーになってしまいます。データベースの関連付けを設定して、メールアドレスが表示されるようにしてください。


模範解答1
/home/ubuntu/myblog/app/models/talk.rbに次の内容を記述する

class Talk < ApplicationRecord
belongs_to :user
end


演習課題「投稿一覧にメールアドレスを表示する」
右の環境には、「myblog」プロジェクトに「talk」という1行掲示板が作成されています(user_idとcontentというカラムを持っています)。また、ユーザー認証構築用にdeviseを導入して、「User」というモデルを作成し、talkと関連付けてあります。

この掲示板の投稿一覧に、Userモデルのメールアドレスを表示するように設定してください。

模範解答1
/home/ubuntu/myblog/app/views/talks/index.html.erbに次の内容を記述する

Talks

User Content


<%= link_to 'New Talk', new_talk_path %>


#04:Userモデルにnameカラムを追加しよう
ここでは、記事を投稿したユーザーの名前を表示するため、deviseのUserモデルに名前のカラムを追加します。それに合わせて、ユーザーの登録フォームを変更しましょう。

Userモデルにカラムを追加

$ rails g migration AddNameToUser name:string
$ rails db:migrate

コンソールで確認

rails console
User.all

サインアップ画面に「name」カラムを追加
app/views/devise/registrations/new.html.erb


ユーザー情報の変更画面に「name」カラムを追加
app/views/devise/registrations/edit.html.erb


参考になるWebページ
- [devise にusername カラムを追加し、usernameを登録できるようにする。 - Qiita]
https://qiita.com/yasuno0327/items/ff17ddb6a4167fc6b471

  • [初めてのdevise ② -- カラムを追加してみる -- ~ やってみようカスマイズ! ~ - Qiita]
    https://qiita.com/uloruson/items/40154b4be19d1ac900f3

  • [Railsのログイン認証gemのDeviseのカスタマイズ方法 - Rails Webook]

    http://ruby-rails.hatenadiary.com/entry/20140804/1407168000

    演習課題「Userモデルにnameカラムを追加する」
    右の環境には、「myblog」プロジェクトに「talk」という1行掲示板が作成されています(user_idとcontentというカラムを持っています)。また、ユーザー認証構築用にdeviseを導入して、「User」というモデルを作成して、talkと関連付けてあります。

このUserモデルに、nameカラムを追加してください。


模範解答1
次のコマンドを順にターミナルで実行する
cd myblog
rails g migration AddNameToUser name:string
rails db:migrate


演習課題「サインアップ画面と変更画面に、nameカラムを追加する」
右の環境には、「myblog」プロジェクトに「talk」という1行掲示板が作成されています(user_idとcontentというカラムを持っています)。また、ユーザー認証構築用にdeviseを導入して、「User」というモデルを作成し、talkと関連付けてあります。

このUserモデルにnameカラムを追加したので、次のフォームに、ラベルとテキストフィールドを追加してください。

  • edit.html.erb
  • new.html.erb

採点して、すべてのジャッジに正解すれば、演習課題クリアです!


模範解答1
/home/ubuntu/myblog/app/views/devise/registrations/edit.html.erbに次の内容を記述する

<h2>Edit <%= resource_name.to_s.humanize %></h2>

<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
  <%= devise_error_messages! %>

  <div class="field">
    <%= f.label :email %><br />
    <%= f.email_field :email, autofocus: true, autocomplete: "email" %>
  </div>

  <div class="field">
    <%= f.label :name %><br />
    <%= f.text_field :name %>
  </div>

  <% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
    <div>Currently waiting confirmation for: <%= resource.unconfirmed_email %></div>
  <% end %>

  <div class="field">
    <%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br />
    <%= f.password_field :password, autocomplete: "off" %>
    <% if @minimum_password_length %>
      <br />
      <em><%= @minimum_password_length %> characters minimum</em>
    <% end %>
  </div>

  <div class="field">
    <%= f.label :password_confirmation %><br />
    <%= f.password_field :password_confirmation, autocomplete: "off" %>
  </div>

  <div class="field">
    <%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
    <%= f.password_field :current_password, autocomplete: "off" %>
  </div>

  <div class="actions">
    <%= f.submit "Update" %>
  </div>
<% end %>

<h3>Cancel my account</h3>

<p>Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %></p>

<%= link_to "Back", :back %>


#05:Userモデルのユーザー名を保存しよう
ここでは、Userモデルにある名前のカラムをデータベースに保存できるようにします。

コントローラで、nameカラムを保存する
app/controllers/application_controller.rb

before_action :configure_permitted_parameters, if: :devise_controller?

protected

def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
devise_parameter_sanitizer.permit(:account_update, keys: [:name])
end


演習課題「nameカラムを保存できるようにする」
右の環境には、「myblog」プロジェクトに「talk」という1行掲示板が作成されています(user_idとcontentというカラムを持っています)。また、ユーザー認証構築用にdeviseを導入して、「User」というモデルを作成し、talkと関連付けてあります。

このUserモデルに、nameカラムを追加したので、保存できるようにコードを修正してください。

採点して、すべてのジャッジに正解すれば、演習課題クリアです!


模範解答1
/home/ubuntu/myblog/app/controllers/application_controller.rbに次の内容を記述する

class ApplicationController < ActionController::Base
protect_from_forgery with: :exception

before_action :configure_permitted_parameters, if: :devise_controller?

protected

def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
devise_parameter_sanitizer.permit(:account_update, keys: [:name])
end
end


#06:掲示板にユーザー名を表示しよう
ここでは、1行掲示板のナビゲーションと投稿一覧に、Userモデルのnameカラムを表示しましょう。

ナビゲーションのログイン情報に、ユーザー名を表示
app/views/layouts/application.html.erb

<% if user_signed_in? %>
Logged in as <%= current_user.name %>.
<%= link_to "Settings", edit_user_registration_path, :class => "navbar-link" %> |
<%= link_to "Logout", destroy_user_session_path, method: :delete, :class => "navbar-link" %>
<% else %>
<%= link_to "Sign up", new_user_registration_path, :class => 'navbar-link' %> |
<%= link_to "Login", new_user_session_path, :class => 'navbar-link' %>
<% end %>

投稿一覧に、nameカラムを表示する
views/articles/index.erb.html

Name Content

投稿の詳細画面に、nameカラムを表示する
views/articles/show.erb.html

User:


演習課題「投稿一覧と詳細画面に、Userモデルのnameカラムを表示する」
右の環境には、「myblog」プロジェクトに「talk」という1行掲示板が作成されています(user_idとcontentというカラムを持っています)。また、ユーザー認証構築用にdeviseを導入して、「User」というモデルを作成し、talkと関連付けてあります。

このUserモデルに、nameカラムを追加したので、投稿一覧と詳細画面で、user_idの代わりにUserモデルのnameカラムを表示してください。

採点して、すべてのジャッジに正解すれば、演習課題クリアです!


模範解答1
/home/ubuntu/myblog/app/views/talks/index.html.erbに次の内容を記述する

Talks

User Content


<%= link_to 'New Talk', new_talk_path %>

模範解答2
/home/ubuntu/myblog/app/views/talks/show.html.erbに次の内容を記述する

User:

Content:

<%= link_to 'Edit', edit_talk_path(@talk) %> |

<%= link_to 'Back', talks_path %>

#07:ログインユーザー名で投稿を保存しよう
ここでは、1行掲示板の投稿を、ログインしたユーザーの名前で保存できるようにします。すでに、ログインした時だけ投稿できるようになっているので、現在のログインユーザーで投稿できるようにしましょう。

新規投稿フォームを修正して、user_idを削除する
app/views/articles/_form.html.erb

<%= form_with(model: article, local: true) do |form| %>
<% if article.errors.any? %>


<%= pluralize(article.errors.count, "error") %> prohibited this article from being saved:

  <ul>
  <% article.errors.full_messages.each do |message| %>
    <li><%= message %></li>
  <% end %>
  </ul>
</div>

<% end %>


<%= form.label :content %>
<%= form.text_field :content, id: :article_content %>


<%= form.submit %>

<% end %>

createメソッドを修正する
app/controllers/articles_controller.rb

POST /articles

POST /articles.json

def create
@article = Article.new(article_params)
@article.user_id = current_user.id


演習課題「投稿一覧と詳細画面に、Userモデルのnameカラムを表示する」
右の環境には、「myblog」プロジェクトに「talk」という1行掲示板が作成されています(user_idとcontentというカラムを持っています)。また、ユーザー認証構築用にdeviseを導入して、「User」というモデルを作成し、talkと関連付けてあります。

talks_controllerを修正し、ユーザーがログインしている時だけ、
新規投稿のユーザー名をログインユーザー名にしてください。なお、ログインしているかどうかは「user_signed_in?」で判別できます。

採点して、すべてのジャッジに正解すれば、演習課題クリアです!


模範解答1
/home/ubuntu/myblog/app/controllers/talks_controller.rbに次の内容を記述する

class TalksController < ApplicationController
  before_action :authenticate_user!, only: [:edit, :update, :destroy]
  before_action :set_talk, only: [:show, :edit, :update, :destroy]

  # GET /talks
  # GET /talks.json
  def index
    @talks = Talk.all
  end

  # GET /talks/1
  # GET /talks/1.json
  def show
  end

  # GET /talks/new
  def new
    @talk = Talk.new
  end

  # GET /talks/1/edit
  def edit
  end

  # POST /talks
  # POST /talks.json
  def create
    @talk = Talk.new(talk_params)

    if user_signed_in?
        @talk.user_id = current_user.id
    end

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

  # PATCH/PUT /talks/1
  # PATCH/PUT /talks/1.json
  def update
    respond_to do |format|
      if @talk.update(talk_params)
        format.html { redirect_to @talk, notice: 'Talk was successfully updated.' }
        format.json { render :show, status: :ok, location: @talk }
      else
        format.html { render :edit }
        format.json { render json: @talk.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /talks/1
  # DELETE /talks/1.json
  def destroy
    @talk.destroy
    respond_to do |format|
      format.html { redirect_to talks_url, notice: 'Talk was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

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

    # Never trust parameters from the scary internet, only allow the white list through.
    def talk_params
      params.require(:talk).permit(:user_id, :content)
    end
end

#08:自分の記事だけ編集・削除 その1
ここでは、投稿したユーザーだけが自分の記事を編集・削除できるようにしましょう。そのために、contollerで、user_idが一致した時だけ、アクションを実行させます。

updateアクションを修正する
```app/controllers/articles_controller.rb

def update
if @article.user_id == current_user.id
respond_to do |format|
if @article.update(article_params)
format.html { redirect_to @article, notice: 'Article was successfully updated.' }
format.json { render :show, status: :ok, location: @article }
else
format.html { render :edit }
format.json { render json: @article.errors, status: :unprocessable_entity }
end
end
else
redirect_to @article, notice: "You don't have permission."
end
end
```

destroyアクションを修正する
```app/controllers/articles_controller.rb

def destroy
if @article.user_id == current_user.id
@article.destroy
msg = "Article was successfully destroyed."
else
msg = "You don't have permission."
end
respond_to do |format|
format.html { redirect_to articles_url, notice: msg }
format.json { head :no_content }
end
end
```


#09:自分の記事だけ編集・削除 その2
ここでは先ほどの続きとして、使わないアクションを呼び出すリンクを非表示にします。

updateアクションを修正する
```app/controllers/articles_controller.rb

def update
if @article.user_id == current_user.id
respond_to do |format|
if @article.update(article_params)
format.html { redirect_to @article, notice: 'Article was successfully updated.' }
format.json { render :show, status: :ok, location: @article }
else
format.html { render :edit }
format.json { render json: @article.errors, status: :unprocessable_entity }
end
end
else
redirect_to @article, notice: "You don't have permission."
end
end
```

destroyアクションを修正する
```app/controllers/articles_controller.rb

def destroy
if @article.user_id == current_user.id
@article.destroy
msg = "Article was successfully destroyed."
else
msg = "You don't have permission."
end
respond_to do |format|
format.html { redirect_to articles_url, notice: msg }
format.json { head :no_content }
end
end
```

投稿一覧を修正する
```app/views/articles/index.html.erb

<% if user_signed_in? && article.user_id == current_user.id %>

<%= link_to 'Edit', edit_article_path(article) %>
<%= link_to 'Destroy', article, method: :delete, data: { confirm: 'Are you sure?' } %>
<% end %>
```

詳細画面を修正する

app/views/articles/show.html.erb

<% if user_signed_in? && @article.user_id == current_user.id %>
    <%= link_to 'Edit', edit_article_path(@article) %> |
<% end %>
<%= link_to 'Back', articles_path %>

演習課題「ユーザーがログインしている時だけ、編集・削除を可能にする」
右の環境には、「myblog」プロジェクトに「talk」という1行掲示板が作成されています(user_idとcontentというカラムを持っています)。また、ユーザー認証構築用にdeviseを導入して、「User」というモデルを作成し、talkと関連付けてあります。

この掲示板で、ユーザーがログインしている時だけ、投稿一覧と詳細画面に、編集と削除のリンクを表示してください。なお、ログインしているかどうかは「user_signed_in?」で判別できます。

採点して、すべてのジャッジに正解すれば、演習課題クリアです!


模範解答1
/home/ubuntu/myblog/app/views/talks/index.html.erbに次の内容を記述する

<p id="notice"><%= notice %></p>

<h1>Talks</h1>

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

  <tbody>
    <% @talks.each do |talk| %>
      <tr>
        <td><%= talk.user.name %></td>
        <td><%= talk.content %></td>
        <td><%= link_to 'Show', talk %></td>
        <% if user_signed_in? && talk.user_id == current_user.id %>
          <td><%= link_to 'Edit', edit_talk_path(talk) %></td>
          <td><%= link_to 'Destroy', talk, method: :delete, data: { confirm: 'Are you sure?' } %></td>
        <% end %>
        </tr>
    <% end %>
  </tbody>
</table>

<br>

<%= link_to 'New Talk', new_talk_path %>

模範解答2
/home/ubuntu/myblog/app/views/talks/show.html.erbに次の内容を記述する

<p id="notice"><%= notice %></p>

<p>
  <strong>User:</strong>
  <%= @talk.user.name %>
</p>

<p>
  <strong>Content:</strong>
  <%= @talk.content %>
</p>

<% if user_signed_in? && @talk.user_id == current_user.id %>
  <%= link_to 'Edit', edit_talk_path(@talk) %>
<% end %>
<%= link_to 'Back', talks_path %>

お疲れ様でした!!!!

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1