Ruby好き非エンジニアのブログ

〜Ruby on Railsの学習記録〜

toastrの導入

前回まで開発の流れをひとつひとつ備忘録として残してきましたが、細かくブログに書こうとするとかなり時間がかかるので、今回からは開発の過程で触れたコトを切り取って記していきます。



今回はtoastrの導入。

検索エンジンで、

toastr gem

と入力していただくと、下記GitHubのページが出てくるので、クリックしてください。
github.com


クリックするとこんな画面に飛びます。
f:id:Jyoko:20170113233501g:plain


そもそもtoastrって何?という方は、まずは見てみるのが一番!
画面を少し下にスクロールしていただくと、

Demo
Demo can be found at http://CodeSeven.github.com/toastr

と書いてあるところがあるので、この
http://CodeSeven.github.com/toastr
をクリック。

クリックするとまたまた同じような内容で、

Demo
Demo can be found at http://codeseven.github.io/toastr/demo.html

と書いてある画面が出てくるので、
今度はこの中のリンクをクリック。
http://codeseven.github.io/toastr/demo.html


そして画面内の「Show Toast」ボタンをクリックすると、
f:id:Jyoko:20170113234029g:plain
上記のように画面右上にメッセージが浮かび上がってきます。
これがtoastr。

これは、ログイン機能を実装した際、
「ログインしました」
「ログアウトしました」
など、その時々の状態を知らせるためのメッセージを表示させる際に使用します。


それでは早速導入していきます。
先ほどのtoastrのGitHubページに戻っていただいて
下記Quick Start部分を見てください。
f:id:Jyoko:20170113235400g:plain

まずは、この流れにそって

gem 'toastr-rails'

をコピーして、Gemfileに貼付け。

続いてターミナルで

bundle

を実行。

次に、下記を見てみると、
f:id:Jyoko:20170114000118g:plain
application.css と application.jsに、

*= require toastr

//= require toastr

を追加と書いてあります。

これを参考に、app/assets/stylesheets/application.scssに

@import "toastr";

を追加。
※今回は拡張子がscssなので、scss用に書き換えています。

続いて、app/assets/javascripts/application.jsに

//= require toastr

を追加。


あとはjavascriptでtoastrを呼び出せば完了。
f:id:Jyoko:20170114005702g:plain
上記GitHubのドキュメントを参考に、

app/views/layouts/application.html.erb

<% unless flash.empty? %> //flashにメッセージがある時
    <script type="text/javascript">
      toastr.info('更新しました')
    </script>
<% end %>

などと書いて終了です。
これで、何かを保存した際などに
「更新しました」の文字が浮かびあがってきます。
上記はあくまで一例ですので、表示させたい内容により書き換えてみてください。



今回は以上です。

自分が学習する中でGitHubのドキュメントの見方がわかることで理解が進んだので、少しですがその流れも書いてみました。

記事内で間違っている部分やもっと良い方法をご存知の方がいらっしゃれば是非教えてください。

では今日はこの辺で。

画像アップロード

前回の続きですが、プロフィール画像をアップロードする機能を実装していきます。

今回から少しずつHerokuを使っていくので、アカウント登録がまだの場合は下記など参照の上、Herokuの登録と、Herokuをコマンドラインからコントロールできるようにするための「Heroku toolbelt」のインストールをおこなってみてください!

Heroku初心者がHello, Herokuをしてみる - Qiita

※HerokuとはPaaS(Platform as a Service)と呼ばれるサービスで、
アプリケーションを実行するためのプラットフォームです。


では登録が済んだらアプリケーションの作成。

$ heroku create (Herokuアプリケーション名)

※入力時にHerokuのメールアドレスとパスワードを求められるので入力してください。


アプリケーションを作成したら、下記のコマンドを実行してCloudinaryのアドオンを適用します。
参照URL:
Rails & CarrierWave integration | Cloudinary

Cloudinary + Carrierwave + Heroku + Railsでの画像を手軽に利用する方法 - Qiita

$ heroku addons:create cloudinary:starter

そして、Gemfileに

gem 'cloudinary'
gem 'carrierwave'

を追加し、bundle installを実行。

下記コマンドで画像のアップローダーを作成。

rails generate uploader Avatar

出来上がったapp/uploaders/avatar_uploader.rbにアップロードに関する記述をしていきます。

if Rails.env.production?
  include Cloudinary::CarrierWave
else
  storage :file
end


process :convert => 'png'
  process :tags => ['avatar']

  version :standard do
    process :resize_to_fill => [100, 150, :north]
  end

  version :thumbnail do 
    process :resize_to_fit => [50, 50]
  end
  ・・・
  def public_id
    model.id
  end

※「Rails.env.production?」・・・Railsがproductionモードで動いている時にtrueを返すメソッド

続いて、Userモデルにavatarのカラムを追加します。

$ rails g migration AddAvatarToUsers avatar:string

$ rake db:migrate

ついでに、
app/controllers/users_controller.rbのstrong paramaterにavatarを追加。


app/models/user.rbに下記を追加。

attr_accessor :avatar
・・・
mount_uploader :avatar, AvatarUploader

プロフィール編集のフォームに画像登録を追加。
app/views/users/edit.html.erb

<div class="avatar_edit">
  <%= image_tag(@user.avatar.url(:thumbnail), :width => 80, :height => 80) %>
  <%= f.label :画像登録 %>
  <%= f.file_field :avatar %>
</div>

※file_fieldヘルパーでファイルボックスを作成できます。

app/views/users/show.html.erb

<%= image_tag(@user.avatar_url) %>

を追加。


あとは、cloudinaryのチュートリアルを参考に、

cloudinaryにてcloudinary.ymlダウンロード
configに保存。

environment.rbに下記を追加

config.gem 'carrierwave',:version => '〜>0.4.10'
config.gem 'cloudinary'


見た目は置いておいて…出来上がった画面はとりあえずこんな感じです。
f:id:Jyoko:20161106155908g:plain

ここで「ファイル選択」→「更新」をするとエラー発生。

UsersControllerのUpdateメソッドの下記部分。

if @user.update_attributes(user_params)

convertのメソッドがありませんよ?とのことでした。

public/uploads/tmp/****内にuploadした画像は保存されている模様。
保存→コンバート→表示の過程でエラーが発生しているのかなーと思いつつ。。

とりあえずconvert部分の記述を一度コメントアウト
app/uploaders/avatar_uploader.rb

#process :convert => 'png' 
#process :tags => ['avatar']

#version :standard do
  # process :resize_to_fill => [100, 150, :north]
#end

#version :thumbnail do 
  # process :resize_to_fit => [50, 50]
#end
  
# Create different versions of your uploaded files:
  # version :thumb do
  # process :resize_to_fit => [50, 50]
# end

そして、上記でversion :thumbnailをコメントアウトしたので、
app/views/users/edit.html.erbの:thumbnailも削除。

<%= image_tag(@user.avatar.url(:thumbnail), :width => 80, :height => 80) %>
↓
<%= image_tag(@user.avatar.url, :width => 80, :height => 80) %>

これで再度アップロードを試してみると、無事マイページに画像が表示されました。
f:id:Jyoko:20161106160800g:plain

まだまだエラー盛りだくさんですが、画像が表示されたのでとりあえず今日はこの辺で。
見た目も悪いので、徐々にレイアウトも調整していきたいと思います。



追記:
前回更新からかなり日にちが空いてしまったのでうろ覚えで書いてます(汗
ゆっくりなペースではありますが、もう少しコンパクトにして更新するようにします。

gem 'pg' インストール時のエラー解決方法

プロフィール用の画像アップロードを実装する前にRailsの環境設定をしていたところ、
gem 'pg'のインストールで少しハマったのでメモ。


画像アップロードはクラウド上でおこないます。
使用するgemは、
・carrierwave
・cloudinary
※アップロード先はHeroku。

ということでHerokuにデプロイするため、PostgreSQLを使えるようにアプリケーションの設定を変更します。
(現在はSQLiteを使用していますが、Heroku上ではSQLiteは使用できないため)

gem 'sqlite3', group: :development
#本番ではpostgressを使用
gem 'pg', group: :production

※developmentモードではSQLiteを、productionモードではPostgreSQLを使用するようgroup分けをしています。

続いて

$ bundle install

ここは簡単にスルー。

のはずが、エラー発生。

エラー内容を見てみると、

An error occurred while installing pg (0.19.0), and Bundler cannot continue.
Make sure that `gem install pg -v '0.19.0'` succeeds before bundling.

と出ています。



んー。



もう少し遡ってみると、

Can't find the 'libpq-fe.h header

とありました。

libpq-fe.hが無くエラーが出ているようです。

いろいろ調べながら試してもエラー続きでしたが、
postgresql を Homebrew でインストールしたら解決しました。

$ brew install postgresql

これで

$bundle install

で通りました!

は〜良かった良かった。

ついでにデータベースの設定もしておきます。
config/database.yml

〜略〜
production:
  <<: *default
  adapter: postgresql
  encoding: unicode
  pool: 5

以上。
思わぬところで止まってしまいましたが、ちゃんと次に進めそうです。

ではでは。

プロフィール編集ページの作成

プロフィール編集についてのメモ。

前回ログイン周りを一通りおこなったので、今回は登録した情報の編集・更新ができるようにします。


まずは、コントローラーにeditアクションを追加します。

app/controllers/users_controller.rb

def edit
    @user = User.find(params[:id])
    render :layout => 'users'
end

※render :layout => 'users' 
・・・通常画面と会員画面のレイアウトが異なるため、会員画面のレイアウトに飛ばしています。



そして、それに対応するViewも作成していきます。
登録時の、「ニックネーム」と「パスワード」カラムに加えて、
プロフィールの編集では、「肩書き」と「自己紹介」のカラムも追加してみます。
決まりは無いので何でも良いですが、
肩書き=position
自己紹介=s_introduction
としてみました。
(肩書きの英訳はtitleですが、titleは他で使用する予定のため、別の名前にしました)


ではまずはカラムの追加。ターミナルにて以下を実行。

rails generate  migration AddEditToUsers position:string s_introduction:text
rake db:migrate

これでマイグレーションファイルが出来ました。
db/migrate/2016*******_add_edit_to_users.rb

class AddEditToUsers < ActiveRecord::Migration[5.0]
  def change
    add_column :users, :position, :string
    add_column :users, :s_introduction, :text
  end
end


次は編集フォームの作成。
先ほど追加したカラムと、画像の登録をできるようにします。
とりあえずはgravatorでサンプル画像を表示しておきます。
(画像の登録・表示はまた別の回で)

<% provide(:title, "Edit user") %>
<h1>プロフィール編集</h1>

<div class="row">
  <div class="col-md-6 col-md-offset-3">
   <%= form_for(@user) do |f| %>
    <%= render 'shared/error_messages', object: f.object %>
    
    <div class="profile_left">
    
    <%= f.label :ニックネーム %>
    <%= f.text_field :nickname, class: 'form-control' %>

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

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

    <%= f.label :パスワード確認 %>
    <%= f.password_field :password_confirmation, class: 'form-control' %>
    </div>

    <div class="profile_right">
    <%= f.label :肩書き %>
    <%= f.text_field :position, class: 'form-control' %>

    <%= f.label :自己紹介 %>
    <%= f.text_area :s_introduction, class: 'form-control' %>
    
    <div class="gravatar_edit">
     <%= gravatar_for @user %>
     <a href="http://gravatar.com/emails" target="_blank">画像編集</a>
    </div>
    </div>


    <%= f.submit "更新する", class: "btn btn-primary" %>
   <% end %>
 </div>
</div>


出来上がった画面
f:id:Jyoko:20161008114826g:plain
登録時に入力した情報は引き継がれています。
細かいCSS部分は割愛させていただきますが、元々の登録情報と、新しく追加したカラムを左右分けてみました。


続いて更新部分。
editと同様、UsersControllerにupdateアクションを追加します。
app/controllers/users_controller.rb

def update
    if @user.update_attributes(user_params)
      redirect_to @user
      flash[:success] = "プロフィールを更新しました" 
    else
      render'edit'
    end
end

更新ができたらユーザー画面へ、それ以外はedit画面へ飛びます。

更新後、ユーザー画面に表示する内容がまだできていないので、showページに情報追加します。

<% provide(:title, @user.nickname)%>
<div class="row">
  <aside class="col-md-4">
    <section class="user_info">
      <h1>
        <%= gravatar_for @user %>
        <h2><%= @user.nickname %></h2>
        <h3><%= @user.position %></h3>
      </h1>
    </section>
  </aside>
</div>

とりあえずは、
・画像
・ニックネーム
・肩書き
をここに表示します。
肩書き・自己紹介を入力して更新を押すと
f:id:Jyoko:20161008114711g:plain

画像・ニックネーム・肩書きのみが表示されます。
f:id:Jyoko:20161008114750g:plain

最後に、過入力による負荷を避けるため、バリデーションも追加しておきます。

validates :position, length: { maximum: 30 }
validates :s_introduction, length: { maximum: 300 }

・肩書きは30文字以下
・自己紹介は300文字以下
※とりあえずこれだけ設定し、状況に合わせて修正します。

仮に肩書きを30文字以上入れてみると…
f:id:Jyoko:20161008120558g:plain
エラーのアラートが流れ、編集画面に戻されます。

ざっくりですが、プロフィールの編集・更新部分が出来上がりました。
また日本語化等等、細かいところは修正しながら進めていきます。

ユーザー登録時にログイン

前回解決できなかったユーザー登録時にheaderが切り替わらないという話。

・ログイン時はheaderが切り替わる
・ユーザー登録時はheaderが切り替わらない
というものでした。

前回の解決策として、ユーザーページを新たに作成し、そこにredirectするという方法にしましたが、
Ruby on Railsチュートリアルを見たら簡単に解決したのでメモ(汗
第8章 ログイン、ログアウト | Rails チュートリアル


まずは
app/helpers/sessions_helper.rbに下記を追加。

def log_in(user)
  session[:user_id] = user.id
end

そして、
チュートリアル通り、SessionsControllerとUsersControllerのcreateメソッドに

SessionsController

log_in user

UsersController

log_in @user

をそれぞれを追加

こんな感じになります。
SessionsController

def create
  user = login(params[:login], params[:password], params[:remember_me])
  if user
    log_in user #ここを追加
    flash[:info] = "ログインしました"
    redirect_back_or_to user
  else
    flash[:danger] = 'ニックネーム・メールアドレス もしくはパスワードが間違っています'
    render :new
  end
end

UsersController

def create 
  @user = User.new(user_params)
  if @user.save
    log_in @user #ここを追加
    flash[:success] = "Welcome to the Jammies!"
    redirect_to @user
  else
    render 'new'
  end
end

以上です。笑
とりあえず、今のところエラー無く無事動作しています。

細かいところですが、モヤモヤしていたので解決できて良かった。
ということで今回はここまで!

会員ページのviewの切り替えについて

前回未ログインユーザーと・ログインユーザーのheader切り替え部分の修正をおこなっていましたが、
できたと思った切り替えがうまくいっておらず、、
とりあえずその後あれこれ試してみたのでメモ。

とその前に、前回から変更したところは、

・ニックネーム 10文字以下
・パスワード3文字以上
・メールアドレス30文字以下
上記バリデーションだけ追加しておきました。



で、切り替えの部分ですが、確かに

・ログイン→会員ページ
への遷移の場合はちゃんとheader切り替わってました。

ですが、

・新規登録→会員ページ
へ遷移した際にはheaderが未ログイン状態のviewのままになっていました。

今まで何度かログイン部分は作成しましたが、ここの部分はスムーズだったのでなぜだろう??

とりあえずhelperから情報を呼び出す記述をしていなかったので下記を追加。

app/helpers/sessions_helper.rb

module SessionsHelper
	def current_user
		@current_user ||= User.find_by(id: session[:user_id])
	end

	def logged_in?
		!!current_user
	end

	def store_location
		session[:forwarding_url] = request.url if request.get?
	end
end

app/controllers/application_controller.rb

class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception
  include SessionsHelper #ここを追加

  private
  def logged_in_user
  	unless logged_in?
  		store_location
  		flash[:danger] = "ログインしてください"
  		redirect_to login_url
  	end
  end
end

これでどうだろう?と思いましたが、何も変わらず。
ちなみに、ヘッダの記述はパーシャルで下記の通り記述
app/view/layouts/_header.html.erb

<nav>
  <ul class="nav navbar-nav navbar-right">
     <li><%= link_to "Jammiesホーム", root_path %></li>
     <li><%= link_to "使い方", '#' %></li>
     <li><%= link_to "お知らせ", '#' %></li>
     <% if logged_in? %>
       <li><%= link_to "マイページ", current_user %></li>
       <li class="dropdown">
         <a href="#" class="dropdown-toggle" data-toggle="dropdown">
           アカウント <b class="caret"></b>
         </a>
           <ul class="dropdown-menu">
             <li><%= link_to "アカウント情報", current_user %></li>
             <li><%= link_to "プロフィールの編集", '#' %></li>
             <li class="divider"></li>
             <li>
             <%= link_to "ログアウト", logout_path, method: "delete" %>
             </li>
           </ul>
       </li>
     <% else %>
             <li><%= link_to "会員登録", signup_path %></li>
             <li><%= link_to "ログイン", login_path %></li>
     <% end %>
  </ul>
</nav>
<% if logged in? %>

の部分で、ログイン時しか呼び出せていないんだろうなーと思いつつ。

<% if current_user %>

にしてみたりしましたが、状況変わらず。
いまいち解決方法がわかりませんでした。

ということで少し切り替えて、会員ページごと替えてしまえー!ということで
ユーザーページごとレイアウトを切り替えることにしました。
ついでにヘッダの色も変えてわかりやすく。

app/views/layouts/に下記2つのファイルを作成
・users.html.erb
・_header_users.html.erb


users.html.erbに

<%= render 'layouts/header_users' %>

を追加し、_header_users.html.erbに飛ぶようにする。

続いて
UsersControllerとSessionsControllerに、

layout 'application'

を追加。

そして、UsersControllerに、

def show
    @user = User.find(params[:id])
    render :layout => 'users'  #ここを追加
  end

と記述。

たったこれだけですが、
とりあえず切り替えは上手くいったようです。

◆登録前
f:id:Jyoko:20160911133211g:plain

◆登録後
f:id:Jyoko:20160911133253g:plain

ヘッダーの色は白→黒へ。
登録前に表示されていた「会員登録」「ログイン」
の表記は、「マイページ」「アカウント」へ。

またいろいろと問題発生しそうですが、とりあえず今回はこの辺で終了!

ではまた!

ログイン周りの修正②

ログインする前とログインした後のヘッダメニューの切り替えをおこないます。

app/views/layouts/_header.html.erb

<header class="navbar navbar-fixed-top navbar-inverse" >
  <div class="container">
    <%= link_to "Jammies", '#', id: "logo" %>
    <nav>
      <ul class="nav navbar-nav navbar-right">
        <li><%= link_to "Jammiesホーム", '#' %></li>
        <li><%= link_to "使い方", '#' %></li>
        <li><%= link_to "お知らせ", '#' %></li>
      <% if current_user %>
        <li><%= link_to "マイページ", current_user %></li>
        <li class="dropdown">
          <a href="#" class="dropdown-toggle" data-toggle="dropdown">
            アカウント <b class="caret"></b>
          </a>
          <ul class="dropdown-menu">
            <li><%= link_to "アカウント情報", current_user %></li>
            <li><%= link_to "プロフィールの編集", '#' %></li>
            <li class="divider"></li>
            <li>
              <%= link_to "ログアウト", logout_path, method: "delete" %>
            </li>
          </ul>
        </li>
      <% else %>
        <li><%= link_to "会員登録", signup_path %></li>
        <li><%= link_to "ログイン", login_path %></li>
      <% end %>
      </ul>
     </nav>
   </div>
 </header>

・ログイン前
f:id:Jyoko:20160827183545g:plain

・ログイン後
f:id:Jyoko:20160827183221g:plain

ログイン前に表示されていた「会員登録」や「ログイン」がなくなり、「マイページ」「アカウント」が表示されました。
※「アカウント」のところはプルダウンにしてあります。

あとは、ログアウトする時、/logoutを「URL直接入力」していたのを「ログアウトボタン押下」に変更
config/routes.rb

get 'logout', to: 'sessions#destroy'
↓
delete 'logout', to: 'sessions#destroy'

f:id:Jyoko:20160827183126g:plain

プルダウンもログアウトボタンでのログアウトもできました。

ということで今回はこの辺で。