【Rails】ユーザー登録・編集機能をプログラミング作成しました

2018年4月15日

今日はユーザーの登録機能を作りました。

いま僕が作っているお店の口コミサイトですが、基本的にユーザーログインしなくても口コミが出来るようにしています。(ログインしなきゃ口コミ出来ないなんて投稿に躊躇するからね)

でもユーザー登録&ログインしても使えるようにする予定です。

それでユーザーの登録、編集機能を付与する事にしました。

Railsの標準的な流れに従ってまずはモデルを作ります。モデルを作ったらルーター→コントローラー→ビューの順です。

userモデルを作る

以下のカラムを持たせています。

カラム 内容
nickname string ニックネーム
email string メールアドレス
password_digest string パスワード
image string プロフィール画像のURL
introduce string 自己紹介文
age tinyint 年齢
sex string 性別
address string 住所

既にニックネームとメールアドレスとパスワードとプロフィール画像はカラムを作っていたので、後から残り4つのカラムを追加しました。

Railsでモデルにカラムを追加する

コンソールから生成

$ rails g migration AddIntroduceToUsers introduce:string
$ rails g migration AddAgeToUsers age:integer
$ rails g migration AddSexToUsers sex:string
$ rails g migration AddAddressToUsers address:string

構文は
rails g migration Addカラム名Toテーブル名 カラム名:型
です。カラム複数を同時に追加する事は出来ないようで、1個ずつ生成しました。

tinyintを指定するには、上記のように事前にintegerでマイグレーションファイルを生成しておいて、その後マイグレーションファイルを修正する必要があります。

t.integer :age
#↓これをこのように指定するとtinyintになりました。
t.integer :age,:limit => 1

マイグレーションファイルを生成したら、migrateを実行。

$ rails db:migrate

ちゃんとテーブルにカラムが追加されているか確認

$ sudo service mysqld start
$ mysql -u root
mysql> show databases;
mysql> USE DB名_development;
mysql> show tables;
mysql> describe users;

Userクラスにバリデーションを入れる

入力されたユーザー情報の検証です。

class User < ApplicationRecord
  before_save { self.email.downcase! }

  validates :nickname, presence: true, length: { maximum: 50 }
  validates :introduce, length: { maximum: 255 }
  validates :address, length: { maximum: 50 }

  validates :email, presence: true, length: { maximum: 255 },
                    format: { with: /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i },
                    uniqueness: { case_sensitive: false }

end

Userのストロングパラメーター

ストロングパラメーターはユーザー登録画面からPOSTされた情報のセキュリティのために実施。Railsの一般的なやり方。

  private

  #ストロングパラメーター
  def user_params
    params.require(:user).permit(:nickname, :email, :password, :password_confirmation, :image, :introduce, :age, :sex, :address)
  end

パスワード暗号化のためのGemを追加

こちらの記事→password_digest:が暗号化されない問題

で色々失敗しながらもなんとか暗号化できました。

これでUserモデル関連の実装が完了!

User関連のルーティングを作成

以下のようにルーティングを作成。(routes.rb)

  get 'signup', to: 'users#new'
  resources :users, only: [:index, :show, :create, :edit, :update]

ユーザー登録画面はsignupというURLで行うようにしました。

rails routesで見ると以下のようになりました。

  signup GET   /signup(.:format)       users#new
   users GET   /users(.:format)       users#index
      POST   /users(.:format)       users#create
 edit_user GET   /users/:id/edit(.:format)  users#edit
   user GET   /users/:id(.:format)     users#show
      PATCH  /users/:id(.:format)     users#update
      PUT   /users/:id(.:format)      users#update

まぁよくあるユーザー機能でしょうか。

現時点ではdestroy(ユーザーの退会処理)は考えていません。
またindex(ユーザーの一覧表示画面)これもあるだけで実装は考えていません。

Userコントローラーの作成

$ rails g controller users index show new create edit update

これでapp/controllers/users_controller.rbと、app/views/users/配下にビューファイルが生成されました。

それぞれのメソッド(アクション)を実装していきます。

ユーザー登録機能 users#newアクションとnew.html.erb

users#newアクションの実装

新規ユーザー登録ボタンを押したら、このnewメソッドに来て、new.html.erb(ユーザ登録画面)に遷移していきます。

users_controller.rbのnewメソッドはユーザーのインスタンスを生成。

  def new
      @user = User.new
  end

new.html.erbの実装

ユーザー登録画面(new.html.erb)はbootstrapのCSSを使用してちょっとデザインしつつ。

ニックネームとメールアドレスとパスワードを入力させます。プロフィール画像とかはログイン後の編集画面で登録できるようになります。

<%= form_for(@user) do |f| %>

  <div class="form-group">
    <%= f.label :nickname, 'ニックネーム' %>
    <%= f.text_field :nickname, class: 'form-control' %>
  </div>

  <div class="form-group">
    <%= f.label :email, 'メールアドレス' %>
    <%= f.email_field :email, class: 'form-control' %>
  </div>

  <div class="form-group">
    <%= f.label :password, 'パスワード' %>
    <%= f.password_field :password, class: 'form-control' %>
  </div>

  <div class="form-group">
    <%= f.label :password_confirmation, 'パスワード(もう1度ご入力ください)' %>
    <%= f.password_field :password_confirmation, class: 'form-control' %>
  </div>

  <%= f.submit '登録する', class: 'btn btn-primary btn-block' %>
<% end %>

これで以下の画面を出しています。

users#createアクション

ユーザー登録画面からPOSTされた情報を受け取るメソッドの実装です。

users_controller.rbのcreateメソッドを作っていきます。

  def create
    @user = User.new(user_params) #user_paramsはPOSTデータをチェックするメソッド

    if @user.save
      flash[:success] = '新しいユーザーを登録しました。'
      redirect_to @user
    else
      flash.now[:danger] = 'ユーザーの登録に失敗しました。'
      render :new
    end
  end

これでユーザーの登録処理が出来ました。

実際にデータベース内を覗いてみるとちゃんと作成したユーザーが存在している事を確認できます。

$ rails c
> User.all

ユーザー情報表示機能

これは何のことはなく、users#showアクションとshow.html.erbを実装するだけでした。

/users/:id
このようなURLでアクセスしてきたらユーザーの情報を表示したいと思います。

コントローラーのメソッドは以下のように、URLから取ってきたidでuserテーブルを探してインスタンスを生成。

  def show
      @user = User.find(params[:id])
  end

show.html.erbでは、そのユーザー情報を画面に表示するだけ。

<div class="row">
  <aside class="col-md-4">
    <div class="panel panel-default">
      <div class="panel-heading">
        <h3 class="panel-title"><%= @user.nickname %></h3>
      </div>
      <div class="panel-body al-c">
          <% if @user.image? %>
            <%= image_tag @user.image, :class => "mw50" %>
          <% else %>
            <%= image_tag("/images/icon/icon-mama-02-160px.png") %>
          <% end %>
      </div>
    </div>
  </aside>
  <div class="col-md-8">
  <p><span class="orange b"><%= @user.nickname %></span>
  &nbsp;<%= @user.live %>
  <% if @user.age.present? %> &nbsp;<%= @user.age %>代 <% end %>
  &nbsp;<%= @user.sex %></p>
  <p class="orange b">自己紹介</p>
  <p><%= @user.intro %></p>
  </div>
</div>

この中では画像があれば表示し、無ければ自前のno-image画像を表示しています。
自前のCSSを利用しているのでこれで見栄え良く(?)できました。
個人的にはbootstrapのcssに使い慣れて無くあまり見栄えも良くない気がしています(; ・`ω・´)

ユーザー情報表示画面はいかのようになりました。

ユーザープロフィール編集機能・画面の作成

まずはusers#editアクションとedit.html.erbとusers#updateアクションの実装です。

users#editアクションの実装

users#editではやはりURLからidのパラメータを取ってきてuserインスタンスを生成し、それをedit.html.erbへ持ち回ります。

  def edit
    @user = User.find(params[:id])
  end

プロフィール編集画面の実装

簡単な部分を先に実装して現時点では以下のような画面が出ています。

ここにパスワードや性別、年齢の入力もできるようにします。

取り急ぎパスワード部分を先に実装!

edit.html.erbの実装

<div class="form-group">
<%= f.label :nickname, 'ニックネーム' %>
<%= f.text_field :nickname, class: 'form-control' %>
</div>

<div class="form-group">
<%= f.label :email, 'メールアドレス' %>
<%= f.email_field :email, class: 'form-control' %>
</div>

<div class="row">
<div class="col-xs-6 form-group">
	<%= f.label :age, '年齢', class:'control-label' %>
	<%= f.select :age, [["",""], ["10代","10"], ["20代","20"], ["30代","30"], ["40代","40"], ["50代","50"], ["60代","60"], ["70代以上","70"] ], {},   class: 'form-control' %>
</div>

<div class="col-xs-6 form-group">
	<%= f.label :sex, '性別', class:'control-label' %>
	<%= f.select :sex, [["",""], ["女性","女性"], ["男性","男性"]], {},   class: 'form-control' %>
</div>
</div>

<div class="form-group">
<%= f.label :live, '地域(県や市など)' %>
<%= f.text_field :live, class: 'form-control' %>
</div>


<div class="form-group">
<%= f.label :intro, '自己紹介(255文字未満)' %>
<%= f.text_area :intro, :maxlength => "255", :size => "80x5",  class: 'form-control'  %>
</div>


<div class="accbox">
  <label for="label1">パスワードを変更するかたはこちら</label>
  <input type="checkbox" id="label1" class="cssacc" />
  <div class="accshow">
    <div class="form-group">
      新しいパスワード<br>
      <%= f.password_field :password, class: 'form-control' %>
    </div>

    <div class="form-group">
      新しいパスワードを再入力<br>
      <%= f.password_field :password_confirmation, class: 'form-control' %>
    </div>
  </div>
</div>

</div>

<div class="al-c"><%= f.submit 'プロフィール編集を完了する', class: 'btn btn-primary' %></div>

これで実装しました。年齢や性別は必須じゃないので空白も作っています。

またパスワードもこの画面から変更できるようにしていますが、アコーディオンボックスを使って最初は見せないようにして、クリックしたら開くようにしています。

なんでパスワード部分をこのようにしたかというと、最初はパスワード入力欄に[●●●●●●●]みたいな感じで表示をさせたかったのです。

けど、初期値をパスワード欄に表示させる事が出来なかったからです。userのpassword_digestは暗号化されていてシステム管理者からも復元できないから表示できません。

で、初期値を表示することができないのでパスワード入力欄は空欄になってしまいます。これをユーザーが見た時に、「パスワードが空やんけ」と勘違いして再入力させてしまう事を懸念しました。

それで、パスワード入力部分は最初は隠すことにして、回避したわけです。

性別、年齢、地域を追加し、ここまででプロフィール編集画面はできました。

プロフィール画像のアップロード機能は次回にします。

users#updateアクションの実装

プロフィール編集画面からPOSTされたデータを受け取るのがこのメソッドです。ここでデータベースの更新を行います。

def update
@user = User.find(params[:id])

#編集しようとしてるユーザーがログインユーザーとイコールかをチェック
if current_user == @user

  if @user.update(user_params)
    flash[:success] = 'ユーザー情報を編集しました。'
    render :edit
  else
    flash.now[:danger] = 'ユーザー情報の編集に失敗しました。'
    render :edit
  end    

else
    redirect_to root_url
end
  

end

current_userメソッドはセッションを扱うメソッドで別途用意しています(割愛)。

ちゃんと更新ができたので、ここまででプロフィールの編集が出来るようになりました。