20210305のRailsに関する記事は18件です。

【Rails】ルーティングを名前空間でグループ分けしている場合のform_withの記法【Ruby】

はじめに

ヘルパーメソッドのform_withを使用して入力フォームを作ろうとしていたところ、NoMethodErrorが出てしまい詰まっていました。
スクリーンショット 2021-03-05 21.50.46.png

結論

route.rbにおいてルーティングを名前空間shopsでグループ分けしていたにもかかわらず、shopsをform_withの引数に渡していなかった。

コード

route.rb
namespace :shops do
    resources :posts  
---中略---
end
shops/posts_controller.rb
class Shops::PostsController < ApplicationController
  --- 中略 ---
  def new
    @post = Post.new
  end
  --- 中略 ---
end

shops/post/new.html.erb
<%= form_with model:[:shops,@post], local: true do |f| %>
      --- 中略 ---
    <div>
      <%= f.submit "送信"%>
    </div>
<% end %>

resourcesをネストしているときに親モデルを引数に渡すのと同じ感覚です。

参考

https://techracho.bpsinc.jp/ohno/2019_12_10/84349
https://railsdoc.com/page/form_with

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】私が成長を実感したエラーの対処法

はじめに

本記事では、私がRailsで学習をする際に、エラーが出た場合の向き合い方について記載しております。
「エラーが出たときが成長する一番のチャンス」という考えの元、エラーとしっかり向き合う姿勢を持って取り組んできたので、その方法を共有します。

前提

以下のgemをインストールします。
既に導入済みの方は読み飛ばしてください?‍♂️

導入するgem一覧
① better_errors
② binding_of_caller
③ pry-byebug

better_errorsとは

Better Errors replaces the standard Rails error page with a much better and more useful error page. It is also usable outside of Rails in any Rack app as Rack middleware.
(better_errorsのGitHub公式から引用)

要するに、標準のRailsのエラーページをより見やすく、より便利なエラーページに置き換えてくれるgemです。

binding_of_callerとは

Using binding_of_caller we can grab bindings from higher up the call stack and evaluate code in that context. Allows access to bindings arbitrarily far up the call stack, not limited to just the immediate caller.
(binding_of_callerのGitHub公式から引用)

要するに、binding_of_callerを使うと、irbを使用して、エラー画面上でコードを評価することができるようになるということです。

pry-byebugとは

Adds step-by-step debugging and stack navigation capabilities to pry using byebug.
(pry-byebugのGitHub公式から引用)

要するに、pryを使用してデバッグするためのデバッグツールです。
irbのように対話的にrubyを実行できるようになります。

To use, invoke pry normally. No need to start your script or app differently. Execution will stop in the first statement after your binding.pry.
(pry-byebugのGitHub公式から引用)

ブレークポイントをうちたい場所にbinding.pryを書いて処理を実行すればその箇所で処理が止まり、変数の値などを確認できるようになります。

では3つのgemをインストールしましょう

Gemfile
gem 'better_errors'
gem 'binding_of_caller'

group :development, :test do
  gem 'pry-byebug'
end

ターミナルで$bundle installを行えばgemのインストールは完了です。

エラーの解決方法

① エラーログを確認する

エラー画面に表示される「エラー文」「トレース情報」「irb」をもとに『エラーの本質』と『エラーの場所』を特定します。
スクリーンショット 2021-03-05 20.36.59.png

② デバッグ

エラーの原因と場所が特定できたら、デバッグを行い「どのようなことが」「どんな風に起こったのか」をさらに詳しく具現化します。
エラー画面のirb上でも変数の値などを確認できます!
スクリーンショット 2021-03-05 20.37.23.png

③ 情報収集

エラーログとデバッグで得た情報をもとに、公式ドキュメントやGitHubの公式ページを見て問題に対応する情報を集めます。

④ 収集した情報をもとに仮説を立てる

集めた情報を自分で組み立てて仮説を立てます。
→この過程が一番頭を使うので成長していると実感できます。

⑤ 仮説をもとに検証する

仮説をもとに実際に検証します。
解決できない場合は再度仮説を立てて検証します。

⑥ 解決できるまで②〜⑤を繰り返す

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsでおすすめ機能を作る

質問掲示板風サイトを作っている時、おすすめ機能を実装したいと思ったので作りました。

前提

・既読機能がある
・タグ機能がある(acts-as-taggable-on使用)
・devise使用

流れ

①自分が最近見た記事から30件取得
②記事に紐づいているタグを取得し、さらにその中から数が多い順に5件取得
③5件の中からランダムに1個のタグを取得
④取得したタグを含み、かつユーザー自身の投稿ではない投稿を取得
⑤他のユーザーからの既読数が多い投稿順に並べ替えて表示

実際の記述

参考程度にお願いします。(元はコントローラーに書いていたのですが、リファクタリングの際にService層を作りそこに移行したため)

app/controllers/top_pages_controller.rb
#Service層とやりとりするための記述です。実際の流れは次にあるのでそちらを参考にするといいと思います。

def index

    if user_signed_in?
      @recommend_tag   = Posts::Postservices.recommend_tag(current_user)
      @recommend_posts = Posts::Postservices.recommend_posts(current_user, @recommend_tag, params).includes(:user, :taggings)
    end

end
app/services/posts/postservices.rb
module Posts
  module Postservices
  
    def self.recommend_tag(current_user)
      #①自分が最近見た記事から30件取得
      recommends = current_user.already_reads.order("created_at DESC").limit(RECENTLY_READ_POST_COUNT)
      #②記事に紐づいているタグを取得し...
      array = Array.new
      recommends.each do |reco|
        reco = Post.find_by(id: reco.post_id)
        reco = reco.tag_counts_on(:tags).pluck(:name) #(Postモデルからtagsカラムのタグ名を取得。tag_counts_onはacts-as-taggable-onのメソッド。)
        array.push(reco)
      end
      #②...数が多いものから順に5件取得&③5件の中からランダムに1個のタグを取得
      return array.compact
                  .flatten
                  .group_by{|e| e}
                  .sort_by{|_,v|-v.size}
                  .map(&:first)[0..4]
                  .sample
    end

    def self.recommend_posts(user_id, recommend_tag, params)
   #④取得したタグを含み、かつユーザー自身の投稿ではない投稿を取得
      posts = Post.tagged_with(recommend_tag).where.not(user_id: user_id)
     #⑤他のユーザーからの既読数が多い順に並べ替えて表示
      return posts.select('posts.*', 'count(already_reads.id) AS already_reads')
                              .left_joins(:already_reads)
                              .group('posts.id')
                              .order('already_reads desc')
                              .order('created_at desc')
                              .limit(DEFAULT_PAGE_ITEM_COUNT)
                              .page(params[:page]).per(DEFAULT_PAGE_ITEM_COUNT)
    end
end
end

config/initializers/constants.rb
#あとで修正しやすいように件数などは変数で渡しています
DEFAULT_PAGE_ITEM_COUNT = 10
RECENTLY_READ_POST_COUNT = 30
app/views/top_pages/index.html.rb
<!-- viewの参考程度においときます... -->
<div class="main-contents">
<% if user_signed_in? && @recommend_posts.present?%>
  <h3 class="title-index"><%=@recommend_tag%>に興味がある人におすすめ</h3>
      <% @recommend_posts.each do |reco| %>
          <div class="post-index">
          <div class="overall-container">
              <%= link_to post_path(reco.id) do %>
                <div class="title"><%= reco.title %></div>
              <% end %>

              <div class="tag-container">
                <% reco.tag_list.each do |tag| %>
                  <span class="post-tag"><%= link_to tag, root_path(tag_name: tag) %></span>
                <% end %>
              </div>

              <div class="other-container">
                <% if user_signed_in? %>
                  <div class="already-read"><%= render 'shared/alreadyread', post: reco %></div>
                <% end %>

                <div class="comments-count"><i class="far fa-comment"></i> <%=  reco.comments.count %></div>
                <div class="likes-count"><i class="far fa-heart"></i> <%=  reco.likes.count %></div>

                <div class="user-info">
                    <% if reco.user.image? %>
                      <div><%= image_tag post.reco.image.url, class: "user-index-icon" %></div>
                    <% else %>
                      <div><%= image_tag "/assets/default.jpg", class: "user-index-icon" %></div>
                    <% end %>
                    <div class="user-name"> <%= reco.user.name %></div>
                </div>
              </div>

          </div>

      </div>
    <% end %>
<div class="paginate"><%= paginate @recommend_posts %></div>

<% end %>

</div>

↓こんな感じで表示できます(CSSはお好みで調整してください)
スクリーンショット 2021-03-05 20.32.19.png

終わりに

自分で作ったおすすめ機能を紹介しました。拙い機能ではありますが、自分で考えて色々調べて実装した初めての機能なのでとても思い入れがあります。
ほぼコードを載せただけになってしまいましたが誰かの参考になれば幸いです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】Bootstrap 4 Tag Input Plugin With jQueryを使ってタグの見た目をよくする

タグ入力後の見た目をよくしよう

題名通りBootstrap 4 Tag Input Plugin With jQueryを用いてタグ入力後の見た目をよくしていきます。
(2回目の)初投稿なので誤字や脱字など至らない点はあると思いますが、よろしくお願いいたします。

完成形

現在のタグ入力機能は下のような感じですが、このままだと殺風景なので
Image from Gyazo


↓のように入力後にきれいに装飾されるようにしてみましょう。
またエンターキーでもタグの登録ができるようになります
Image from Gyazo

前提

Rails 6.0.3.5
Bootstrap 4.5
jQuery導入済み
タグ機能を実装済み

Bootstrap 4 Tag Input Plugin With jQueryの導入

Bootstrap 4 Tag Input Plugin With jQueryの公式サイト

上の公式ページからダウンロードしてきましょう。


解凍すると
Bootstrap-4-Tag-Input-Plugin-jQueryというディレクトリができます。
ディレクトリ内の
tagsinput.js

app/javascripts

tagsinput.css

tagsinput.scss
に名前を変えて
app/javascripts/stylesheets
にいれましょう。


tagsinput.jsを読み込めるように記述します。

application.js
require('jquery')
require('tagsinput') //←これを追加します

tagsinput.scssを読み込むための記述もします。

application.scss
@import '~bootstrap/scss/bootstrap';
@import '~@fortawesome/fontawesome-free/scss/fontawesome';
@import 'tagsinput'; //←これを追加します。

導入はこれで終わりです。

データをdata-roleで送ってtagsinputを起動させよう。

タグの入力フォームにdata-roleを追加します。

new.html.erb
<div class="tags">
  <%= f.label :tag_list %>
  <%= text_field_tag 'post[tag_list]', @post.tag_list, data: {role: "tagsinput"} %>   # ←を追加  
</div>

これで
Image from Gyazo
のようにタグ入力後に装飾されるようになりました!

少し設定を変えてみましょう

現状だとタグが無限に登録できてしまします。

追加できるタグの数と最大文字数を設定しましょう。
tagsinput.jsの中身を少しみてみましょう。

tagsinput.js
    maxTags: undefined,
    maxChars: undefined,

こちらを見るとタグの文字数の縛りもないことがわかりますね!!!
こちらを変えていきましょう。

tagsinput.js
    maxTags: 4,
    maxChars: 8,

タグの最大数4と最大文字数8と設定できました。


Image from Gyazo

↑半角英数ならいいのですが、全角入力時に入力画面にずれがでてしまいます。
こちらを直していきましょう。

tagsinput.js
    this.inputSize = Math.max(1, this.placeholderText.length);

こちらを

tagsinput.js
    this.inputSize = Math.max(20, this.placeholderText.length);

にかえてみましょう。
Image from Gyazo

いい感じになりましたね!!!

最後に

導入にするにあたっていろいろなエラーと戦いましたorz
bootstrap-tagsinput

最初はこちらを導入しようとしたのですが、古いためかなかなかうまく行かずorz
またTag itの導入もうまくいかずorz
いろいろ探し求めてこちらにたどり着きました。

またBootstrap 4 Tag Input Plugin With jQueryについての日本語の文献がなく、オプションなどについて英語の公式を参考にしました。
英語だからといって苦手意識を持たない。しっかりと読むことの大切さを知りました(遅い)
ついでにgifのマークダウン記法があるのを初めて知りました(遅い)


以上となります。拙い文章ですがご拝読いただきありがとうございました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Wikipediaの情報をCSVに保存し、Railsで活用

野球選手のデータをRailsで扱いたかったんですが、活用できるAPIがなかったので自力で集めてみました。
PythonはGoogleColaboratoryを使用してます。

0.流れ

Wikipediaの情報をGoogleColaboratoryからスクレイピング

データを整え、CSVに保存

Railsのデータベースに保存

表示する

1.スクレイピング

準備

import requests
import pandas as pd
from bs4 import BeautifulSoup

# 広島東洋カープの選手一覧
url = "https://ja.wikipedia.org/wiki/%E5%BA%83%E5%B3%B6%E6%9D%B1%E6%B4%8B%E3%82%AB%E3%83%BC%E3%83%97%E3%81%AE%E9%81%B8%E6%89%8B%E4%B8%80%E8%A6%A7"

データの取得

df = pd.read_html(url)
df[5].head()

スクリーンショット 2021-03-05 17.09.53.jpg

df[4]には投手の情報が入っています。
df[5],[6],[7]に捕手、内野手、外野手の情報が入っているので、野手として1つにまとめます。

df_before_fielder = pd.concat([df[5], df[6], df[7]], ignore_index=True) #新たに行番号の割り当てのオプション

カラム名を英語表記に変更

df_before_fielder.rename(columns={"背番号":"number", "選手名":"player_name", "投":"hand", "打":"bat", "備考":"remark"}, inplace=True)
df_fielder=df_before_fielder.drop("remark", axis=1) #備考蘭がいらなかったため削除
df_fielder["team"]="C" #チーム名として、カープ(Carp)の省略英表記のCを追加
df_fielder.head()

スクリーンショット 2021-03-05 17.08.52.jpg

2.CSV保存

from google.colab import files
import datetime

# ファイル名に日時を挿入
dt_now = datetime.datetime.now()
dt = dt_now.strftime('%Y%m%d%H%M%S')
file_name = "c_pitcher_"+ dt + ".csv"

# CSVに変換
df_fielder.to_csv(file_name, index=False)

# CSVファイルのダウンロード
files.download(file_name)

3.Rails

モデルの作成

$ rails g model Player number:integer player_name:string hand:string bat:string team:string

CSVの情報をデータベースに保存

require 'csv'

CSV.foreach("c_fielder_20210304124010.csv", headers: true) do |row|  #「headers: true」先頭行をヘッダーとするので、rowには入らない
  Player.create!(
    # rowには、["22", "中村奨成", "右", "右", "C"]と各選手の情報が入っている。
    number: row[0].to_i,  #ファイル内で文字列になっていたため数値へ変換
    player_name: row[1],
    hand: row[2],
    bat: row[3],
    team: row[4]
  )
end

puts "Finish!"

コントローラの作成

$ rails g controller Players index

コントローラからDBの情報を取得

class PlayersController < ApplicationController
  def index
    @players = Player.all
  end
end

ビューで表示

<% @players.each do |player| %>
  <li style="list-style: none"> 
    <%= player.number %>
    <%= player.player_name %>
    <%= player.hand %>
    <%= player.bat %>
    <%= player.team %>
  </li>
<% end %>

4.結果

こんな感じに表示することができました。
スクリーンショット 2021-03-05 17.26.22.jpg

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

日付フォーマットの共通化

はじめに

日付フォーマットメソッドを共通化して適用する方法について

環境

Rails 5.2.4

やったこと

共通フォーマットの設定はここに記述します。

config/initializers/time_formats.rb
Time::DATE_FORMATS[:datetime_jp] = '%Y年%m月%d日 %H時%M分'

Viewに適用します。

<% @boards.each do |b| %>
  <tr>
    <th><%= f.created_at.to_s(:datetime_jp) %></th>
    <th><%= f.updated_at.to_s(:datetime_jp) %></th>
  </tr>
<% end %>

これが(フォーマット前)
image.png

こうなります(フォーマット後)
image.png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】renderメソッドのcollectionオプションの使い方

環境

macOS: Big Sur Ver11.2.2
Rails: 6.0.0
Ruby: 2.6.5

エラーの内容

ビューファイルで以下のようにrenderメソッドを使って部分パーシャルを呼び出したのだが、なぜかエラーが出て表示されなかった。

<div class="main-contents">
  <h2 class="main-title">新規登録店舗</h2>
  <div class="contents-bar">
    <%= render partial: "static_pages/new_users", collection: @users %>
  </div>
</div>

解決策

通常なら上記の記述でパーシャルファイルでは「user」として変数を利用できるが、なぜか変数がうまく渡っていなかった模様。
試しに以下の記述を追記したら無事に表示された。

<div class="main-contents">
  <h2 class="main-title">新規登録店舗</h2>
  <div class="contents-bar">
    <%= render partial: "static_pages/new_users", collection: @users, :as => "user" %>
  </div>
</div>

「as」でパーシャルファイルで使う変数名を明確に指定しただけ。

とりあえず表示されて一安心です!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Dockerによる開発環境を立ち上げるまで【Rails + Nginx + Unicorn + MySQL】

Dockerを導入し、コンテナを立ち上げVSCodeで開発を行うところまで環境構築ができました。
備忘として導入した流れを簡単にまとめておきたいと思います。

インストール

Docker公式サイトからDocker Desctopをダウンロード。
以下の記事を参考にしてインストールしました。

参考記事:Dockerインストール手順<macOS向け>

フォルダ構成

Dockerfileは記事によって配置場所が異なりますが、個人的にはこの構成が一番綺麗にまとまってると思いました。
Dockerfileやdocker-compose.yml、それにNginxやUnicornの設定ファイルは自動生成されないので自分で作ります。

app
├ config
│ ├ database.yml
│ └ unicorn_development.conf.rb
├ docker
│ ├ web
│ │ └ Dockerfile
│ └ nginx
│   ├ Dockerfile
│   └ revorite.conf
└ docker-compose.yml

Docker関連ファイルの記述

以下記事を参考にさせていただきました。
参考記事:DockerでNginx+unicorn+rails+Mysqlの開発環境を作ってみた

docker/web/Dockerfile

FROM ruby:2.7.1
# dockerizeパッケージダウンロード用環境変数
ENV DOCKERIZE_VERSION v0.6.1

# パッケージの取得
RUN apt-get update && \
    apt-get install -y --no-install-recommends\
    nodejs  \
    vim \
    mariadb-client  \
    build-essential  \
    wget \
    && wget https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz \
    && tar -C /usr/local/bin -xzvf dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz \
    && rm dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /app

COPY Gemfile /app/Gemfile
COPY Gemfile.lock /app/Gemfile.lock

RUN echo "alias cp='cp -i'" >> /root/.bashrc
RUN echo "alias mv='mv -i'" >> /root/.bashrc
RUN echo "alias rm='rm -i'" >> /root/.bashrc
RUN echo "alias la='ls -al'" >> /root/.bashrc
RUN echo "alias ll='ls -l'" >> /root/.bashrc

RUN gem install bundler
RUN bundle install

COPY . /app

docker/nginx/Dockerfile

FROM nginx:stable
# デフォルトのNginxの設定ファイルを削除し、作成しておいた設定ファイルをコピー
RUN rm -f /etc/nginx/conf.d/*
COPY ./docker/nginx/revorite.conf /etc/nginx/conf.d/revorite.conf

RUN echo "alias cp='cp -i'" >> /root/.bashrc
RUN echo "alias mv='mv -i'" >> /root/.bashrc
RUN echo "alias rm='rm -i'" >> /root/.bashrc
RUN echo "alias la='ls -al'" >> /root/.bashrc
RUN echo "alias ll='ls -l'" >> /root/.bashrc

# -c以降の設定ファイルを指定して起動 daemon offでフォアグラウンドで起動
CMD /usr/sbin/nginx -g 'daemon off;' -c /etc/nginx/nginx.conf

docker/nginx/revorite.conf (Nginx設定ファイル)

docker/nginx/revorite.conf
# log directory
error_log  /var/log/nginx.error.log;
access_log /var/log/nginx.access.log;
# max body size
client_max_body_size 2G;
upstream unicorn {
  # for UNIX domain socket setups
  server unix:/app/tmp/sockets/.unicorn.sock fail_timeout=0; 
}
server {
  listen 80;
  server_name localhost; 
  # nginx so increasing this is generally safe...
  keepalive_timeout 5;
  # path for static files
  root /app/public; 
  location @unicorn {
    # HTTP headers
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_pass http://unicorn;
  }
  location / {
    try_files $uri/index.html $uri.html $uri @unicorn;
    include /etc/nginx/mime.types;
  }
  location ~ ^/assets/(.*) {
    alias /app/public/assets/$1;
  }
  # Rails error pages
  error_page 500 502 503 504 /500.html;
  location = /500.html {
    root /app/public; 
  }
}

docker-compose.yml

docker-compose.yml
version: '3'
services:
  web:
    build:
      context: .
      dockerfile: ./docker/web/Dockerfile
    # dockerizeを使い、DBの起動を待ってからUnicornを起動する。
    command: dockerize -wait tcp://db:3306 -timeout 20s bundle exec unicorn -p 3000 -c /app/config/unicorn_development.conf.rb
    environment:
      TZ: Asia/Tokyo
    tty: true         # binding.pryを利用可能にするための2行
    stdin_open: true  # binding.pryを利用可能にするための2行
    depends_on:
      - db 
    ports:
      - "3000:3000"
    volumes:
      - .:/app:cached 
      # ソケット通信用ファイルをnginxコンテナと共有
      - tmp-data:/app/tmp/sockets
      # アセットファイルをnginxと共有
      - public-data:/app/public

  db:
    image: mysql:5.7
    command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci
    ports: 
      - "4306:3306"
    environment:
      MYSQL_DATABASE: revorite_development
      MYSQL_ROOT_PASSWORD: password
    # dbのデータを永続化しておく
    volumes:
      - mysql-data:/var/lib/mysql

  nginx:
    build:
      context: .
      dockerfile: ./docker/nginx/Dockerfile
    ports:
      - 80:80
    restart: always #明示的にstopさせるまでリスタートする。(失敗するたび遅延あり)
    volumes:
      - tmp-data:/app/tmp/sockets
      - public-data:/app/public
    depends_on:
      - web 

volumes:
  public-data:
  tmp-data:
  mysql-data:

config/database.yml

database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>

development:
  <<: *default
  host: db
  username: root
  password: password
  database: revorite_development

config/unicorn_development.conf.rb

config/unicorn_development.conf.rb
# set lets
$worker  = 2
$timeout = 30
$app_dir = "/app"
$listen  = File.expand_path 'tmp/sockets/.unicorn.sock', $app_dir
$pid     = File.expand_path 'tmp/pids/unicorn.pid', $app_dir
$std_log = File.expand_path 'log/unicorn.log', $app_dir
# set config
worker_processes  $worker
working_directory $app_dir
stderr_path $std_log
stdout_path $std_log
timeout $timeout
listen  $listen
pid $pid
# loading booster
preload_app true
# before starting processes
before_fork do |server, worker|
  defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!
  old_pid = "#{server.config[:pid]}.oldbin"
  if old_pid != server.pid
    begin
      Process.kill "QUIT", File.read(old_pid).to_i
    rescue Errno::ENOENT, Errno::ESRCH
    end
  end
end
# after finishing processes
after_fork do |server, worker|
  defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
end

コンテナ作成・起動

$ docker-compose build  # イメージの作成
$ docker-compose up -d  # コンテナの作成・起動

詰まった点

他の記事ではあまり語られておらず、自分が詰まった点をいくつか。

Unicornの起動で失敗する

関連ファイルを作り終え、いざdocker-compose builddocker-compose up -dを叩く。
そしてdocker psを叩くと・・・

CONTAINER ID   IMAGE            COMMAND                  CREATED          STATUS          PORTS                               NAMES
11e605b70c51   revorite_nginx   "/docker-entrypoint.…"   21 minutes ago   Up 21 minutes   0.0.0.0:80->80/tcp                  revorite_nginx_1
313d53cbbc27   mysql:5.7        "docker-entrypoint.s…"   21 minutes ago   Up 21 minutes   33060/tcp, 0.0.0.0:4306->3306/tcp   revorite_db_1

あれ?アプリサーバは???
で、docker-compose logsでログを見てみると

web_1    | 2021/03/04 11:01:27 Command exited with error: exit status 1

exit status 1とは一体・・・
exitしたということは一度起動して即落ちた、と読めるので、落ちたコンテナに入ってログも見てみたのですがそれらしいログは出ていない。
(落ちたコンテナに入る方法はこちらを参考にしました)

最終的に、database.ymlhost: dbの記述が漏れているためだということが判明。一文追加し、無事起動しました。
こんな単純なミスなのですが一日使ってしまったので、Dockerfileとdocker-composeだけを書いて満足しないように注意です。

コンテナ内でGitが使えない

GitをインストールしSSH認証もできるようにしたのですが、どうしてもgit pushだけが弾かれてしまうんですよね。(commitまではできる)

git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

仕方ないのでgit関連の操作はホスト側で実行しています(ホスト側でコンテナ内のソースコードに対しマウントしている)。git操作もコンテナ内で完結できたらベストだったのですが。
 

コンテナ内で開発を行う(VSCode: Remote Development)

コンテナ内で開発を行うには、VSCodeでコンテナ内のソースを参照・開発できるRemote Developmentという拡張機能を使います。
参考記事:VS Code Remote Development で Docker 開発環境を利用する

前述の起動コマンドで起動できていれば、参考記事の通りに起動するだけで特に問題は起きないはず。

その他補足

docker関連のコマンドは長いので、~/.bashrcにエイリアスを設定すると便利。
またエラーが起きる度にコンテナやイメージの削除コマンドを打つのが大変のため、こちらも設定しておくと快適です。

# 例
alias dco='docker-compose'
alias docker-purge='docker stop $(docker ps -q) && docker rm $(docker ps -a -q) && docker rmi $(docker images -q -a) -f'

改善点や誤りなどありましたらコメントで指摘いただけると幸いです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails + JavaScript】投稿画面に画像プレビュー機能を実装しよう!

画像を投稿する際に選択した画像がプレビューできる機能を実装していきます。
今回も初心者向けにレシピ投稿アプリを例に作成していきます。

JavaScript初心者にもわかりやすいようにメソッドやイベントについては外部リンクを参照しながら解説していきます。

画像投稿機能実装については前回記事にしておりますので、そちらを参照してください。
【超かんたん】Active Storageで画像投稿機能を実装しよう!

完成イメージ

5c93c9251ef0f4ecbbbe1eb8ccc91142.gif

事前準備

Javascriptファイルの作成

まずは、プレビュー機能を実装するためのpreview.jsを作成します。

ターミナル
touch app/javascript/packs/preview.js

ファイルが作成できたらpreview.jsを読み込むための記述をapplication.jsにしていきます。
また、turbolinksはコメントアウトします。

app/javascript/packs/application.js
// This file is automatically compiled by Webpack, along with any other files
// present in this directory. You're encouraged to place your actual application logic in
// a relevant structure within app/javascript and only use these pack files to reference
// that code so it'll be compiled.

require("@rails/ujs").start()
// require("turbolinks").start()  // コメントアウト
require("@rails/activestorage").start()
require("channels")
require('./preview')  // 追記

//以下略

画像を表示するスペースの作成

画像を表示する場所をビューファイルに指定します。

app/views/recipes/new.html.erb
<%= form_with model: @recipe, local: true do |f| %>

#中略
    <div class="form-group">
      <label class="text-secondary">画像</label><br>
      <%= f.file_field :image %>
    </div>

    <div id="new-image"></div>  #追記

#以下略

<% end %>

Javascriptファイルの編集

preview.jsを新規投稿ページでしか発火しないようにif文を作成します。

app/javascript/packs/preview.js
if (document.URL.match(/new/)){

}

次にHTMLが最初に読み込まれたときに作動する関数を定義していきます。
addEventListenerメソッドとDOMContentLoadedイベントを使います。

addEventListenerの使い方は下記の通りです。

要素.addEventListener(イベント, 関数, オプション);

それでは処理を記述していきます。

app/javascript/packs/preview.js
if (document.URL.match(/new/)){
  document.addEventListener('DOMContentLoaded', () => {

  });
}

続いて、検証ツールを用いて投稿フォームのファイル選択ボックスのidを確認しましょう。
e4ef3687bbb1149610a8aa9301d91f83.gif

今回のレシピアプリの場合はid="recipe_image"だったのでこのrecipe_imagegetElementByIdメソッドで取得していきます。
そして、投稿フォームのファイル選択ボックスに変化(change)が起こったときに行われる処理を記述していきます。

app/javascript/packs/preview.js
if (document.URL.match(/new/)){
  document.addEventListener('DOMContentLoaded', () => {
    document.getElementById('recipe_image').addEventListener('change', (e) =>{
      console.log(e);
    });
  });
}

アロー関数の「e」はgetElementByIdで取得した投稿フォームのファイル選択ボックスの中身になります。(eはeventの略)

では、本当に中身が取得できたいるか確かめて見ましょう。
以下のようにコンソールに出力されていれば成功です。
event.gif

では、取得した情報を定数に格納します。

e.target.files[0]で取得したファイルの情報を定数fileに格納し、URL.createObjectURL(file)で取得した情報を文字列に変換し、定数blobに格納します。

そして、blobを引数にcreateImageHTML( )という関数を呼び出します。(createImageHTML( )はこのあと作成します。)

app/javascript/packs/preview.js
if (document.URL.match(/new/)){
  document.addEventListener('DOMContentLoaded', () => {
    document.getElementById('recipe_image').addEventListener('change', (e) => {

      console.log(e);  //削除

//ここから追記
      const file = e.target.files[0];  
      const blob = window.URL.createObjectURL(file); 
      createImageHTML(blob); 
//ここまで追記
    });
  });
}

それでは、createImageHTML( )を作成しましょう。
まずは、getElementByIdでnew.html.erbに先ほど追加したdiv要素のidのnew-imageを取得します。

app/javascript/packs/preview.js
if (document.URL.match(/new/)){
  document.addEventListener('DOMContentLoaded', () => {
//ここから追記
    const createImageHTML = (blob) => {  
      const imageElement = document.getElementById('new-image'); 
    }; 
//ここまで追記

    document.getElementById('recipe_image').addEventListener('change', (e) => {
      const file = e.target.files[0];
      const blob = window.URL.createObjectURL(file);
      createImageHTML(blob);
    });
  });
}

次にcreateElementメソッドでHTML要素の「img」を作成し、blobImageに格納します。
そして、setAttributeでclassとsrcをimgに付与します。
classを付与しているのはCSSを当てるためです。

setAttributeの使い方は以下の通りです。

要素.setAttribute("データ名",データ);

以上のことを踏まえて、記述していきましょう。

app/javascript/packs/preview.js
if (document.URL.match(/new/)){
  document.addEventListener('DOMContentLoaded', () => {
    const createImageHTML = (blob) => {
      const imageElement = document.getElementById('new-image');
//ここから追記
      const blobImage = document.createElement('img'); 
      blobImage.setAttribute('class', 'new-img') 
      blobImage.setAttribute('src', blob); 
//ここまで追記
    };

    document.getElementById('recipe_image').addEventListener('change', (e) => {
      const file = e.target.files[0];
      const blob = window.URL.createObjectURL(file);
      createImageHTML(blob);
    });
  });
}

最後に、appendChildメソッドを使ってnew.html.erbに追加したdiv要素の中にimg要素を入れます。

appendChildの使い方は以下の通りです。

親要素.appendChild(追加する子要素);

それでは、preview.jsに追記しましょう。

app/javascript/packs/preview.js
if (document.URL.match(/new/)){
  document.addEventListener('DOMContentLoaded', () => {
    const createImageHTML = (blob) => {
      const imageElement = document.getElementById('new-image');
      const blobImage = document.createElement('img');
      blobImage.setAttribute('class', 'new-img')
      blobImage.setAttribute('src', blob);

      imageElement.appendChild(blobImage); //追記
    };

 //以下省略

setAttributeで付与したクラス「new-img」にCSSをあてます。

style.css
.new-img{
  width: 400px;
  object-fit: cover;
}

実際にビューを確認してみましょう。
てり.jpg
画像が表示され以下のようにimg要素にclass属性とsrc属性がセットされていれば成功です。
6007c0be3679ea9ee27b2e55cab74e10.png

既存のプレビューを削除しよう

現状だと画像ファイルを選択し直すとどんどん画像がプレビューされていくという問題点があります。
542452a03055e4b5d01981c40f15b950.gif
この問題を解決していきましょう。

querySelectorメソッドを使ってimg要素を取得し、imageContentに格納します。

そして、if文を使いimageContentに値が入っている場合removeされます。
(img要素がない、つまりimageContentがnullの場合はif文がfalseとなり、実行されません。)

app/javascript/packs/preview.js
//中略
    document.getElementById('recipe_image').addEventListener('change', (e) => {
//ここから追記
      const imageContent = document.querySelector('img'); 
      if (imageContent){ 
        imageContent.remove(); 
      } 
//ここまで追記

      const file = e.target.files[0];
      const blob = window.URL.createObjectURL(file);
      createImageHTML(blob);
    });
  });
}

それでは確認してみましょう。
以下の通り、画像ファイルを選択し直すと再プレビューされれば成功です。
957bdc1ca5a903937315a55e59b92ff5.gif

以下、完成形のコードです。

app/javascript/packs/preview.js
if (document.URL.match(/new/)){
  document.addEventListener('DOMContentLoaded', () => {
    const createImageHTML = (blob) => {
      const imageElement = document.getElementById('new-image');
      const blobImage = document.createElement('img');
      blobImage.setAttribute('class', 'new-img')
      blobImage.setAttribute('src', blob);

      imageElement.appendChild(blobImage);
    };

    document.getElementById('recipe_image').addEventListener('change', (e) => {
      const imageContent = document.querySelector('img');
      if (imageContent){
        imageContent.remove();
      }

      const file = e.target.files[0];
      const blob = window.URL.createObjectURL(file);
      createImageHTML(blob);
    });
  });
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

"共働き夫婦特化型"の家計簿作りました!〜Common Wallet(コモンウォレット)〜

はじめに

※「はじめに」では私の家計簿への愛が無駄に長く語られます。
面倒な人は次章までお飛ばし下さい。

・共働き夫婦の家庭に質問です。

「どのように家計を管理してますか?」
A)一部または全部のお金を渡し、片方が管理(いわゆる「お小遣い制」)
B)それぞれ自分の財布で管理して、家賃は旦那、食費は嫁など項目ごとに分担する
C)共通財布を用意し、毎月お金をお互い入れて、そこで生活費をやりくりする。
だいたいこの3つでしょうか?

ちなみにリクルートブライダル総研が行った「新婚生活実態調査」によると、
共働き家庭では、Aが50.5%、Cが33.0%、最後にBが14.2%と、
Aが半数以上を締めているらしいです。(ちなみにうちの両親もAです。)
image.png
※上記調査を基に筆者作成

しかもAの中でも「妻が管理」が46.8%、「夫が管理」はわずか3.7%と、妻が殆ど、、、
つまり世の中の財布は大半を妻が握っているのです!!

私は世の旦那に問いかけたい、、、

「それで良いんですか?」

と。

自分の稼いだお金がいつのまにか搾取されていることも気づかず、
いつまでも妻に尻に敷かれてて良いんですか!!(世のお小遣い制の男性陣どうか叩かないで・・・)

そういう意味で私はBも良いなと思ってます。完全に個人管理ですし、何より楽ですし。
ただ、生活費の負担額は極力平等に、そして公開されている方がお金に対する不満はなくなるかな、とも思い、
うちではCの共通財布制を採用しています。
不満があれば家計簿を見れば一発で原因がわかります。
実際うちではお金の喧嘩は一度もしたことないから、共通財布の家計簿管理は夫婦仲的にもおすすめです!笑

ただ、
共通財布って管理がものすごく面倒なんです。

というのも、家計簿って逐一入力するのさえ面倒ですよね?
共通財布だとそれに加えて、たまに個人の財布から立替えたりすることもあるので、その立替処理も記録してるともうぐっちゃぐちゃになるんです。
それに、毎月の入金額も給料から色々計算したい場合、それも別途で管理しているともう何がなんだかわからなくなります。

私も色んな家計簿を試してみましたが、上記の悩みを解決する家計簿が見つからず、
仕方なく、自作のエクセルで管理してました。

しかし!今や私も半人前ながらプログラミングを勉強している身!
プログラマーならそのアプリを作ってしまおう、ということで作りました!!
スマホでも操作しやすいようにしたかったですし。

名付けて「Common Wallet(コモンウォレット)」共通財布専用家計簿アプリです。

共通財布家計簿「Common Wallet(コモンウォレット)」

以下が私が今回作ったアプリです。

Common Wallet

image.png
いくつか機能をご紹介したいと思います。

①基本的な家計簿機能

通常の家計簿アプリにある機能
「明細入力」「残高管理」「予算管理」等は実装してあるので、
共通財布ではなく個人の家計簿として利用することもできます。
image.png

②データ分析

支出と予算を入力すると、
分析画面から「項目別支出」や「予算対比」など各種データを閲覧できます。
image.png
また家計簿一覧ページでは、
月次の残高推移もグラフで確認できます。
image.png

③精算機能

精算画面で精算未済の明細について
自動的に集計して精算額を算出してくれます。
精算対象はステータスが「未済」かつ今日以前の日付のものになります。
image.png

また、精算画面については、
ホーム画面の精算未済欄からも飛ぶことができます。
image.png

④入金計算

毎月の入金金額を算出してくれます。
算出方法は「可処分所得均等法(私が勝手に命名笑)」を採用しており、
生活費を差し引いた残りの手取りが夫婦同額になるような入金額を計算してくれます。
ただしこの場合、給料を多くもらっている方が、かなり多く負担するケースがあるので、補正項目を追加しています。
補正基準については各家庭で決めてもらっていいと思います。
image.png
image.png

技術面

僕は未熟者なので大した技術は使えていないですが、
苦労した箇所の参考記事は勉強中の方にも参考になると思うのでご紹介します。
rails使ってます。

Highcharts

本サービスで使っているグラフはchartkickの「Highcharts」を使っています。
chartkickでは他にも、chart-js、 Google Chartsが使えますが、
Highchartsが微調整も利きやすく、そしてきれいな印象です。
この記事にすごくわかりやすい作成例があったので、参考にしました。
chartkick × Highchartsでドーナツグラフを作る

Ajax処理

初めて実践でAjax処理をしたのでだいぶ苦労しました。。。
そもそもjsの書き方とか知らないし。。。
でも何度も追加や削除を行う画面ではAjax化しないとかなりUX的にマイナスだと思うので、
使うべきだなと感じました。
以下の記事を読んでAjaxの理解が進みました。
Ruby on RailsのAjax処理のおさらい
RailsにおけるAjaxの実装(JavaScriptとjQueryのコード比較)

AWSデプロイ

初めて作った(クソ)アプリ「笑うぎんこうまん」はherokuが全部勝手にデプロイしてくれたので、超絶楽チンでした。
でも、「まともなサービスなら独自ドメインもしっかり取りたいし、しっかり勉強もしたい!」とか意気込んでAWSに挑戦してみましたが、しっかり爆死。。。
用語全てが意味不明でだいぶしんどかったですが、構築知識は身についたなと思います。
ちなみにAWSデプロイは以下の記事がすごく丁寧でわかりやすいです。
世界一丁寧なAWS解説

レスポンシブデザイン

今回は「スマホでも操作しやすい」を目的としていたので、
レスポンシブデザインにもところどころこだわりました。
例えば明細一覧画面。

大きい画面では収入・支出が別々に記載されていますが、
スマホサイズでは「収支」とまとめて書かれています。

○パソコンサイズ
image.png
○スマホサイズ
image.png
これはCSSでサイズごとに文字を「display:none;」して非表示にしています。
以下の記事を参考にしました。
【レスポンシブデザイン】不要な要素をCSSだけで非表示にする方法
ただし記事にもある通り、
「display:none;」はSEO的にリスクがあるそうなのでご利用は計画的に笑

おわりに

以上が今回私の作ったアプリの説明です。
正直ここまで細かく家計簿を作る人もそうそういないと思うので、かなりニッチなサービスですが、、、笑

良ければ使って下さい。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Ruby on Rails】OmniAuthのGitHub認証にて近似エラーメッセージが出て一苦労

環境

MacOS 11.2.1
Ruby 3.0.0
Rails 6.1.0
devise 4.7.3
omniauth 1.9.1
omniauth-github 1.4.0
omniauth-oauth2 1.7.1

問題

OmniAuthの概ねの実装を行ったがGitHubの認証用APIにPOSTしている時点でコケてしまう。

結論

以下2パターンの間違いがほぼ同じエラーを出していた。エラーが似ているので、片方が間違えたまま、もう片方を修正しても動作確認でわからない。
- OAuth AppsとGitHub Appsを間違える(詳細は下記)
- token_params: { parse: :json }をDeviseのconfigに設定する(詳細は下記)

解決方法

本当はログをよくチェックするべきだったと思います。
自分の場合は、POSTのあと”Invalid Credential”と出ているので、Deviseの設定が怪しいと思って一つ一つ直しながらひたすら動作確認をしていました。

OAuth AppsとGitHub Appsを間違える、とは

developer settingsによく似た二つの項目がある。
GitHub AppsとOAuth Apps

image.png

image.png


OmniAuthでGitHub認証で必要なのはOAuthAppsで生成するIDとSECRET。
まちがえてGitHubAppsで生成するIDとSECRETを使うと以下のような現象が起こる。

1度目のみ認証画面になる

image.png

認証してもログインできず、2度目以降は認証画面は出ず、ログインに失敗しつづける

ログ
1回目

48826 Started POST "/users/auth/github" for ::1 at 2021-03-05 10:17:35 +0900
48827 Started GET "/users/auth/github/callback?code=xxx&state=xxx" for ::1 at 2021-03-05 10:20:24 +0900
48828 Processing by Users::OmniauthCallbacksController#failure as HTML
48829   Parameters: {"code"=>"xxx", "state"=>"xxx"}
48830 Redirected to http://localhost:3000/
48831 Completed 302 Found in 3ms (ActiveRecord: 0.0ms | Allocations: 334)

2回目以降

48876 Started POST "/users/auth/github" for ::1 at 2021-03-05 10:30:39 +0900
48877 Started GET "/users/auth/github/callback?code=xxx&state=xxx" for ::1 at 2021-03-05 10:30:39 +0900
48878 Processing by Users::OmniauthCallbacksController#failure as HTML
48879   Parameters: {"code"=>"xxx", "state"=>"xxx"}
48880 Redirected to http://localhost:3000/
48881 Completed 302 Found in 1ms (ActiveRecord: 0.0ms | Allocations: 205)

コンソール

Started POST "/users/auth/github" for ::1 at 2021-03-05 10:30:39 +0900
I, [2021-03-05T10:30:39.445975 #78131]  INFO -- omniauth: (github) Request phase initiated.
Started GET "/users/auth/github/callback?code=xxx&state=xxx" for ::1 at 2021-03-05 10:30:39 +0900
I, [2021-03-05T10:30:39.860370 #78131]  INFO -- omniauth: (github) Callback phase initiated.
E, [2021-03-05T10:30:40.842629 #78131] ERROR -- omniauth: (github) Authentication failure! invalid_credentials: OAuth2::Error, : 
{"message":"Resource not accessible by integration","documentation_url":"https://docs.github.com/rest/reference/users#list-email-addresses-for-the-authenticated-user"}
Processing by Users::OmniauthCallbacksController#failure as HTML
  Parameters: {"code"=>xxx, "state"=>xxx}
Redirected to http://localhost:3000/
Completed 302 Found in 1ms (ActiveRecord: 0.0ms | Allocations: 205)

コンソールの方のログを見るとAuthentication failure! invalid_credentialsとなっている

token_params: { parse: :json }をDeviseのconfigに設定する、とは

Facebook認証をする場合、あるバージョン以降、レスポンスフォーマットがJSONに変わっているので、それをパースする処理を加える必要があるそうな。
https://qiita.com/anoworl/items/ea04d941d5d2bdea0e66

config/initializers/devise.rb

config.omniauth :github, ENV["GITHUB_ID"], ENV["GITHUB_SECRET"], token_params: { parse: :json }

token_params: { parse: :json }の部分を加えるとJSONをパースしてくれる

GitHub認証には必要ない設定で、入れるとエラーになってしまう。

入れた場合、POST直後に認証失敗してログインできない。

エラーログ

49561 Started POST "/users/auth/github" for ::1 at 2021-03-05 10:46:03 +0900
49562 Started GET "/users/auth/github/callback?code=xxx&state=xxx" for ::1 at 2021-03-05 10:46:04 +0900
49563 Processing by Users::OmniauthCallbacksController#failure as HTML
49564   Parameters: {"code"=>"xxx", "state"=>"xxx"}
49565 Redirected to http://localhost:3000/
49566 Completed 302 Found in 1ms (ActiveRecord: 0.0ms | Allocations: 207)

コンソール

Started POST "/users/auth/github" for ::1 at 2021-03-05 10:46:03 +0900
I, [2021-03-05T10:46:03.756773 #78764]  INFO -- omniauth: (github) Request phase initiated.
Started GET "/users/auth/github/callback?code=xxx&state=xxx" for ::1 at 2021-03-05 10:46:04 +0900
I, [2021-03-05T10:46:04.210471 #78764]  INFO -- omniauth: (github) Callback phase initiated.
E, [2021-03-05T10:46:04.593857 #78764] ERROR -- omniauth: (github) Authentication failure! invalid_credentials: OAuth2::Error, access_token=xxx&scope=user%3Aemail&token_type=bearer
Processing by Users::OmniauthCallbacksController#failure as HTML
  Parameters: {"code"=>"xxx", "state"=>"xxx"}
Redirected to http://localhost:3000/
Completed 302 Found in 1ms (ActiveRecord: 0.0ms | Allocations: 207)

コンソールの方のログを見るとAuthentication failure! invalid_credentialsとなっている
二つの現象で非常によく似たエラーが出るので原因追求が難しかった。
しかしよくみると、GitHub APPに取り違えた方のエラーメッセージには{"message":"Resource not accessible by integration","documentation_url":"https://docs.github.com/rest/reference/users#list-email-addresses-for-the-authenticated-user”}という情報が書いてある。この部分に気づければもっと早く解決していたかもしれない。

ちなみに単純にパスワードを間違えると

以下のログでPOSTしたまま以下の画面になるので動作確認ですぐに気づける

48807 Started POST "/users/auth/github" for ::1 at 2021-03-05 09:48:08 +0900

image.png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Ruby on Rails】OmniAuthのGitHub認証、APIにPOST時点でのエラー

環境

MacOS 11.2.1
Ruby 3.0.0
Rails 6.1.0
devise 4.7.3
omniauth 1.9.1
omniauth-github 1.4.0
omniauth-oauth2 1.7.1

過程

deviseでユーザー認証機能を導入した後、下記のサイトにのっとってGitHub認証を導入する。
https://github.com/heartcombo/devise/wiki/OmniAuth:-Overview

問題

概ねの実装を行ったがAPIにPOSTしている時点でコケてしまう。

結論

以下2パターンの間違いがほぼ同じエラーを出していた。エラーが似ているので、片方が間違えたまま、もう片方を修正しても動作確認でわからない。
- OAuth AppsとGitHub Appsを間違える(詳細は下記)
- token_params: { parse: :json }をDeviseのconfigに設定する(詳細は下記)

解決方法

本当はログをよくチェックするべきだったと思います。
自分の場合は、POSTのあと”Invalid Credential”と出ているので、Deviseの設定が怪しいと思って一つ一つ直しながらひたすら動作確認をしていました。

OAuth AppsとGitHub Appsを間違える、とは

developer settingsによく似た二つの項目がある。
GitHub AppsとOAuth Apps

image.png

image.png


OmniAuthでGitHub認証で必要なのはOAuthAppsで生成するIDとSECRET。
まちがえてGitHubAppsで生成するIDとSECRETを使うと以下のような現象が起こる。

1度目のみ認証画面になる

image.png

認証してもログインできず、2度目以降は認証画面は出ず、ログインに失敗しつづける

ログ
1回目

48826 Started POST "/users/auth/github" for ::1 at 2021-03-05 10:17:35 +0900
48827 Started GET "/users/auth/github/callback?code=xxx&state=xxx" for ::1 at 2021-03-05 10:20:24 +0900
48828 Processing by Users::OmniauthCallbacksController#failure as HTML
48829   Parameters: {"code"=>"xxx", "state"=>"xxx"}
48830 Redirected to http://localhost:3000/
48831 Completed 302 Found in 3ms (ActiveRecord: 0.0ms | Allocations: 334)

2回目以降

48876 Started POST "/users/auth/github" for ::1 at 2021-03-05 10:30:39 +0900
48877 Started GET "/users/auth/github/callback?code=xxx&state=xxx" for ::1 at 2021-03-05 10:30:39 +0900
48878 Processing by Users::OmniauthCallbacksController#failure as HTML
48879   Parameters: {"code"=>"xxx", "state"=>"xxx"}
48880 Redirected to http://localhost:3000/
48881 Completed 302 Found in 1ms (ActiveRecord: 0.0ms | Allocations: 205)

コンソール

Started POST "/users/auth/github" for ::1 at 2021-03-05 10:30:39 +0900
I, [2021-03-05T10:30:39.445975 #78131]  INFO -- omniauth: (github) Request phase initiated.
Started GET "/users/auth/github/callback?code=xxx&state=xxx" for ::1 at 2021-03-05 10:30:39 +0900
I, [2021-03-05T10:30:39.860370 #78131]  INFO -- omniauth: (github) Callback phase initiated.
E, [2021-03-05T10:30:40.842629 #78131] ERROR -- omniauth: (github) Authentication failure! invalid_credentials: OAuth2::Error, : 
{"message":"Resource not accessible by integration","documentation_url":"https://docs.github.com/rest/reference/users#list-email-addresses-for-the-authenticated-user"}
Processing by Users::OmniauthCallbacksController#failure as HTML
  Parameters: {"code"=>xxx, "state"=>xxx}
Redirected to http://localhost:3000/
Completed 302 Found in 1ms (ActiveRecord: 0.0ms | Allocations: 205)

コンソールの方のログを見るとAuthentication failure! invalid_credentialsとなっている

token_params: { parse: :json }をDeviseのconfigに設定する、とは

Facebook認証をする場合、あるバージョン以降、レスポンスフォーマットがJSONに変わっているので、それをパースする処理を加える必要があるそうな。
https://qiita.com/anoworl/items/ea04d941d5d2bdea0e66

config/initializers/devise.rb

config.omniauth :github, ENV["GITHUB_ID"], ENV["GITHUB_SECRET"], token_params: { parse: :json }

token_params: { parse: :json }の部分を加えるとJSONをパースしてくれる

GitHub認証には必要ない設定で、入れるとエラーになってしまう。

入れた場合、POST直後に認証失敗してログインできない。

エラーログ

49561 Started POST "/users/auth/github" for ::1 at 2021-03-05 10:46:03 +0900
49562 Started GET "/users/auth/github/callback?code=xxx&state=xxx" for ::1 at 2021-03-05 10:46:04 +0900
49563 Processing by Users::OmniauthCallbacksController#failure as HTML
49564   Parameters: {"code"=>"xxx", "state"=>"xxx"}
49565 Redirected to http://localhost:3000/
49566 Completed 302 Found in 1ms (ActiveRecord: 0.0ms | Allocations: 207)

コンソール

Started POST "/users/auth/github" for ::1 at 2021-03-05 10:46:03 +0900
I, [2021-03-05T10:46:03.756773 #78764]  INFO -- omniauth: (github) Request phase initiated.
Started GET "/users/auth/github/callback?code=xxx&state=xxx" for ::1 at 2021-03-05 10:46:04 +0900
I, [2021-03-05T10:46:04.210471 #78764]  INFO -- omniauth: (github) Callback phase initiated.
E, [2021-03-05T10:46:04.593857 #78764] ERROR -- omniauth: (github) Authentication failure! invalid_credentials: OAuth2::Error, access_token=xxx&scope=user%3Aemail&token_type=bearer
Processing by Users::OmniauthCallbacksController#failure as HTML
  Parameters: {"code"=>"xxx", "state"=>"xxx"}
Redirected to http://localhost:3000/
Completed 302 Found in 1ms (ActiveRecord: 0.0ms | Allocations: 207)

コンソールの方のログを見るとAuthentication failure! invalid_credentialsとなっている
二つの現象で非常によく似たエラーが出るので原因追求が難しかった。
しかしよくみると、GitHub APPに取り違えた方のエラーメッセージには{"message":"Resource not accessible by integration","documentation_url":"https://docs.github.com/rest/reference/users#list-email-addresses-for-the-authenticated-user”}という情報が書いてある。この部分に気づければもっと早く解決していたかもしれない。

ちなみに単純にパスワードを間違えると

以下のログでPOSTしたまま以下の画面になるので動作確認ですぐに気づける

48807 Started POST "/users/auth/github" for ::1 at 2021-03-05 09:48:08 +0900

image.png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsポートフォリオ作成 #6 基本機能フロントエンド開発

こんにちは:smiley:
今回は基本機能のフロントエンド開発を行いました。
(前回記事(#5 基本機能バックエンド開発))

私は、前職(ホテルの料飲部)における、コミュニケーションの課題を解決するアプリを作っています。
具体的には、「レストランで使うものの数を管理するアプリ」です。

今回は、基本機能のフロントエンド開発を行いました

フロントエンドは経験値が低いので、なんとか"見れる見た目"にするので精一杯でした。
ここから、ポートフォリオとして恥ずかしくない見た目にする自信が正直ないです。
正直、途中で挫折するかも、、、
とか思ってしまいます、、、

他の方のポートフォリオを拝見したのですが、レベルが高すぎて言葉を失いました。

前回仕組みで解決したいと書いたのですが、まだ完全にはうまくいっていません。
まだまだ改善が必要です。

感じたこと

  • 知識は必要な時に身につけるべき
    以前時間があった時に、後からいるからと思ってHTML・CSSの復習をしていたのですが、結局また少し復習することになってしまい、二度手間になってしまいました。
    ちなみに、これをTwitterで呟いたところ、今までで一番いいね等をゲットしたツイートになりました。

  • レスポンシブにしないと、、、
    パソコンで作っているので、パソコンで合うようになっていて、スマホで見た際に見づらくなっていないかと、スマホでもチェックしながらやらないといけないと思いました。

とりあえず、なんとか見れるようにはなったので、次に進もうと思います。

次はDockerです

「開発環境でDockerとdocker-composeを導入してみる」
ということを目標に、取り組んでいきたいと思います。



フロントエンドが終わり、第一段階が終了したので、第二段階に進みたいと思います。
まずはDockerの導入をしていきたいと思います:fist:
勉強するところからなので、時間がかかると思いますが、少しずつやっていきたいと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RailsのDockerイメージの作り方

0. はじめに

以下のようなディレクトリ構成にします。

.
├── app/       # Railsアプリ
└── docker/    # Dockerfile置き場
    └── app/
        └── Dockerfile

1. ローカル環境にRailsをインストール

% rails new app

2. Dockerfileの作成

docker/app/Dockerfile
# syntax=docker/dockerfile:1.2

# base
FROM ruby:3.0.0-alpine3.13 AS base
WORKDIR /app
RUN \
  --mount=type=cache,target=/var/cache/apk \
  apk add -U \
    build-base \
    git \
    nodejs \
    sqlite-dev \
    tzdata \
    yarn \
    ;

# bundle
FROM base AS bundle
COPY Gemfile Gemfile.lock /app/
RUN \
  --mount=type=cache,target=/app/vendor/cache \
  bundle install && \
  bundle cache

# yarn
FROM base AS node_modules
COPY package.json yarn.lock /app/
RUN \
  --mount=type=cache,target=/usr/local/share/.cache/yarn/v4 \
  yarn install

# main
FROM base
ARG RAILS_MASTER_KEY
ENV RAILS_MASTER_KEY $RAILS_MASTER_KEY
COPY --from=bundle /usr/local/bundle/ /usr/local/bundle/
COPY --from=node_modules /app/node_modules/ /app/node_modules/
COPY . /app/
EXPOSE 3000
CMD ["bundle", "exec", "rails", "s", "-b", "0.0.0.0"]

3. .dockerignoreの用意

不要なファイルをイメージに含めないために.dockerignoreを作成します

app/.dockerignore
/.bundle/
/.dockerignore
/.git/
/.git*
/.ruby-version
/README.md
/config/master.key
/log/
/node_modules/
/storage/
/tmp/
/vendor/bundle/

4. Dockerイメージのビルド

% DOCKER_BUILDKIT=1 docker image build --build-arg RAILS_MASTER_KEY=<RAILS_MASTER_KEY> -t boccifarm/rails:6.1.3-ruby3.0.0-alpine3.13 -f docker/app/Dockerfile app

5. Dockerイメージのプッシュ

% docker login
% docker image push boccifarm/rails:6.1.3-ruby3.0.0-alpine3.13
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Ruby on Rails】コントローラーの単体テストコードについてまとめ(RSpec)

初学者です。
テストコードがなぜか大好きです。

今回はコントローラーの単体テストコードについてまとめます。
私はRSpecを利用しています。

コントローラーのテストコードを書く方針は
アクションにリクエストを送ったとき想定通りのレスポンスが返されるかどうかを確かめる
ことです。

ちなみにモデルの単体テストコードについてはこちらにまとめています。

前提条件

  • pry-railsを導入済みである
  • FactoryBotを導入済みである
  • RSpec導入済みである

上記については以下の記事にまとめています。

【Ruby on Rails】デバッグツール(pry-rails)
【Ruby on Rails】FactoryBotとFakerについてまとめ
【Ruby on Rails】モデルの単体テストコードについてまとめ(RSpec)

準備

下記コマンドでテストコード用のファイルを生成します。
成功すればspec/requests配下に該当のファイルが生成されます。

ターミナル
rails g rspec:request samples

テストコード

describeitで検証すべき項目を出していきます。

spec/requests/samples_spec.rb
require 'rails_helper'
describe SamplesController, type: :request do

  before do
    @sample = FactoryBot.create(:sample)
  end

  describe 'GET #index' do
    it 'indexアクションにリクエストすると正常にレスポンスが返ってくる' do 
    end
    it 'indexアクションにリクエストするとレスポンスに投稿済みのテキストが存在する' do 
    end
    it 'indexアクションにリクエストするとレスポンスに投稿済みの画像URLが存在する' do 
    end
    it 'indexアクションにリクエストするとレスポンスに投稿フォームが存在する' do 
    end
  end
end

FactoryBotはbuildではなくcreateにしています。
今回のテストではDBにデータが存在する必要があるのでcreateです。
テストする度にデータが作られ、終わると削除されます。便利!

ではindexアクションにリクエストすると正常にレスポンスが返ってくるのテストコードを書いていきます。

spec/requests/samples_spec.rb
it 'indexアクションにリクエストすると正常にレスポンスが返ってくる' do 

# 以下を追加
  get root_path
  binding.pry

end

解説します。
get ○○_pathでどのパスにリクエストを送りたいかを書きます。
rails routesで確認してそのパスを記述します。

この状態で下記コマンドでテストコードを実行します。

ターミナル
bundle exec rspec spec/requests/samples_spec.rb

binding.pryしてるので処理が途中で止まりターミナルに入力できるようになっていると思います。
下記のコマンドを入力します。

ターミナル
response.status

そうするとそのレスポンスのステータスコードが出力されます。
HTTP通信においてステータスコードは以下のようになっています。

ステータスコード 内容
100~ 処理継続中
200~ 処理成功
300~ リダイレクト
400~ クライアント側のエラー
500~ サーバーエラー

つまり今回の場合はresponse.status200がステータスコードで返ってくればOKということです。

正常に200が返ってきたらテストコードを編集します。

spec/requests/samples_spec.rb
it 'indexアクションにリクエストすると正常にレスポンスが返ってくる' do 
  get root_path

# 以下に編集
  expect(response.status).to eq 200

end

これでテストコードを実行して成功すればOKです。

次にindexアクションにリクエストするとレスポンスに投稿済みのテキストが存在するのテストコードを書いていきます。

spec/requests/samples_spec.rb
it 'indexアクションにリクエストするとレスポンスに投稿済みのテキストが存在する' do 

# 以下を追加
  get root_path
  expect(response.body).to include(@sample.text)

end

解説します。
response.bodyと記述してincludeで引数の内容(今回はテキスト)が存在するかを確認してます。bodyでブラウザに表示されるHTMLの情報を抜き出すことができます。

これでテストコードを実行して成功すればOKです。

次にindexアクションにリクエストするとレスポンスに投稿済みの画像URLが存在するのテストコードを書いていきます。ほぼ先ほどと同じです。

spec/requests/samples_spec.rb
it 'indexアクションにリクエストするとレスポンスに投稿済みの画像URLが存在する' do 
  get root_path
  expect(response.body).to include(@sample.image)
end

これでテストコードを実行して成功すればOKです。

次にindexアクションにリクエストするとレスポンスに投稿フォームが存在するのテストコードを書いていきます。
難しく考えずにその文言が存在するかを確認できればOKなので下記のようになります。

spec/requests/samples_spec.rb
it 'indexアクションにリクエストするとレスポンスに投稿フォームが存在する' do 
  get root_path
  expect(response.body).to include('投稿する')
end

これでテストコードを実行して成功すればOKです。

他のアクションについてもほぼ書き方は同じです!
コントローラーの単体テストコードは結合テストとかぶる部分もありますよねー。

以上です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Docker】Ruby2.6.5とRails6.0.0とmysql DockerComposeで環境構築

はじめに

Ruby2.6.5とRails6.0.0とmysqlでDockerComposeで環境構築をしたので記録として記事を書きます。
もし誰かのお役に立てたら幸いです。

Docker環境でアプリケーション開発する手順

1、RailsのDockerfileを作成してDockerをbuild
2、DockerCompose.ymlを作成しコンテナを作る
3、Rails のセットアップ
4、データベースを作成する

開発環境

Docker version 20.10.0
docker-compose version 1.27.4

1、RailsのDockerfile作成

新しいデレクトリを作成します。
今回はデレクトリ名をexamとしてます。

ターミナル
mkdir [新規デレクトリ名]
cd [新規デレクトリ名]

Dockerfile

新規で作ったデレクトリに「Dockerfile」をいう名前でDockerファイルを作成します。
VSコードをお使いの方はcode Dockerfileでターミナルから直接ファイルの作成&移動をしてくれます。
もちろんディレクトリを呼び込んでファイルを作成しても大丈夫です。

exam/Dockerfile
FROM ruby:2.6.5
RUN apt-get update && apt-get install -y \
    build-essential \
    libpq-dev \
    nodejs\
    yarn \
    vim 

WORKDIR /新規デレクトリ名
COPY Gemfile Gemfile.lock /新規デレクトリ名/
RUN bundle install

Gemファイルを作成する

ターミナル
touch Gemfile Gemfile.lock

Gemfileにファイルを持ってくるソースとrailsのバージョンを記述します。

Gemfile
source 'https://rubygems.org'
gem 'rails', '~>6'

Dockerを建てます。

ターミナル
docker build .
.
.
.
Installing rails 6.1.2.1
Bundle complete! 1 Gemfile dependency, 42 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
Removing intermediate container 06448279a57c
 ---> c21a3ec7e3a4
Successfully built c21a3ec7e3a4

#イメージが出来てるか調べる事も出来ます。
docker images 

#もし使っていないイメージがあれば下記のコマンドで削除できます。
docker rmi [IMAGE ID]

2、DockerCompose.ymlを作成しコンテナを作る

dockerc-compose.ymlファイルを作成し記述する

ターミナル
code docker-compose.yml

これで新しいdocker-compose.ymlが作成されます。

docker-compose.yml
version: '3'

services:
  web:
    build: .
    ports:
      - 3000:3000
    volumes:
      - '.:/[作成したディレクトリ名]'
    tty: true
    stdin_open: true

dockerc-ompose.ymlの確認をして実行します

#確認します
cat docker-compose.yml

#実行します
docker-compose up -d


#コンテナが動いてる事を確認します。
docker ps
docker-compose ps

#コンテナの中に入ります。
docker-compose exec web bash

3、Rails のセットアップ

Railsの環境でコンテナができのでその中でrails newをしてセットアップして行きます。

#新しいrailsを作ります
rails new . --force --database=mysql --skip-bundle

#一度コンテナから抜けます
exit

#今のコンテナとイメージを削除します
docker-compose down

#Downになってるか確認します
docker ps

#新しいイメージでコンテナを建てます
docker-compose up --build -d

#確認します
docker-compose ps

#コンテナに入ります
docker-compose exec web bash

#Railsを起動します
rails s -b 0.0.0.0 #現段階ではエラーが出ます

現段階ではデータベースの記述を Dockerfileに記述していないので、mysql2のエラーが出ると思います。
下記の対応を試して下さい。

【Docker】エラー Could not find gem 'mysql2 (~> 0.5)' in any of the gem sources listed in your Gemfile
https://qiita.com/AKI3/items/8009b5218be0ad67b6b7

エラーが解決したらrails s -b 0.0.0.0でサーバーが立ち上がります。
実際にlocalhost:3000でアクセスします。
しかしこのままではデータベースが無いのでエラー画面が表示されます。
スクリーンショット 2021-02-15 17.02.13.png

4、データベースを作成する。

ローカルであればrails db:createをするとデータベースを作れるのですが、コンテナ内では現状の設定では作れません。
Dockerではサービス(環境)ごとにコンテナを作る事が推奨されております。
今回であればRubyとmysqlのコンテナを別々に作り、それぞれのコンテナどうしを接続する必要があります。
その為、detabase.ymlの設定ファイルを編集して正しい指定をし、docker-compose.ymlの設定ファイルの編集します。

先ずdetabase.ymlを編集します。

config/detabase.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  host: db

development:
  <<: *default
  database: 新規デレクトリ名_development
  username: root
  password:

省略

次にdocker-compose.ymlを編集します。

docker-compose.yml
version: '3'

volumes:
  db-data:

services:
  web:
    build: .
    ports:
      - 3000:3000
    volumes:
      - '.:/新規デレクトリ名'
    environment:
      - 'MYSQL_ROOT_PASSWORD=1'
    tty: true
    stdin_open: true
    depends_on:
      - db
    links:
      - db

  db:
    image: mysql:8
    volumes:
      - 'db-data:/var/lib/mysql'
    # このenvironmentはテスト環境でのみ使用可能
    environment:
      MYSQL_ALLOW_EMPTY_PASSWORD: 1

    # command: bundle exec rails s -p 3000 -b '0.0.0.0' #こちらはお好みで

docker-compose.ymlを編集したので新しくコンテナを作ります。
今回はweb(Raisl)とdb(mysql)2つのコンテナを作る事になります。

#再びコンテナを建てます
docker-compose up -d

#upになってるか確認します
docker-compose ps

#コンテナに入ります
docker-compose exec web bash

#データベースを作成します
rails db:create #現段階ではエラーが出ます

Rails側のコンテナ内で作業を進めていきます。
先程作ったRails側のコンテナとmysql側のコンテナがしっかり繋がっていればrails db:createのコマンドは通りますが、現段階では下記のエラーが発生します。

Mysql2::Error::ConnectionError: Plugin caching_sha2_password could not be loaded: /usr/lib/x86_64-linux-gnu/mariadb19/plugin/caching_sha2_password.so: cannot open shared object file: No such file or directory

これはwebコンテナが mysql 8.0 のcaching_sha2_passwordが認証方式に対応していないためだそうです。

詳しくは、こちらの記事で解決できます。
https://blog.toshimaru.net/rails-on-docker-compose/

コマンドだけこちらに記載します。

ターミナル
 #データベース側のコンテナに入る
docker-compose exec db bash

 #mysqlを操作する
mysql -u root

 #ユーザー一覧とその認証方式が閲覧
select User,Host,plugin from mysql.user;

 #root@% のユーザー設定を変更
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '';

 #再度ユーザー一覧とその認証方式が閲覧
select User,Host,plugin from mysql.user;

エラーが解決できたら最後サーバーを立ち上げます。

ターミナル
rails s -b 0.0.0.0

=> Booting Puma
=> Rails 6.1.2.1 application starting in development 
=> Run `bin/rails server --help` for more startup options
Puma starting in single mode...
* Puma version: 5.2.1 (ruby 2.6.5-p114) ("Fettisdagsbulle")
*  Min threads: 5
*  Max threads: 5
*  Environment: development
*          PID: 29
* Listening on http://0.0.0.0:3000
Use Ctrl-C to stop
.
.
.
省略

出来ました!
localhost3000にアクセスすると-Yay! You’re on Rails!-の画面が表示されます。
スクリーンショット 2021-02-17 17.16.29.png

最後に

手探りの対処療法でサーバー起動まで達成しましので、これからも継続学習が必要です。
なんとか環境構築まで至りましたが、Dockerについて完全に理解できておりません、万が一情報が間違っている場合ご指摘していただけると幸いです。

エンジニア初学者ですが、同じ様に悩んでる方々の助けになればと思い記事を投稿しております。
万が一情報が間違っている場合ご指摘していただけると幸いです。

参考

今回Udemyの教材とやっすんのエンジニア大学を主に参考にさせていただきました。
https://www.udemy.com/course/aidocker/
https://github.com/yassun-youtube/docker-compose-sample/blob/master/docker-compose.yml

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Formオブジェクトの概要

Formオブジェクトとは

Formオブジェクトとは、1つのフォームからのデータ送信で複数のモデル操作、テーブルに保存しない情報にバリデーションを設定したい場合に使います。

モデルに似た機能を持ったクラスを作り、バリデーションやデータを保存する処理を記述して実装します。
実装手順はこんな感じです。

1.modelsディレクトリ直下にファイル作成、クラスを定義
2.include ActiveModel::Modelの設定
3.attr_accessorで保存したい複数のテーブルのカラム名を属性値として扱えるように記述
4.バリデーションを記述
5.データをテーブルに保存する処理を記述
6.コントローラーのnew、createアクションなどでFormオブジェクトのインスタンスを生成
7.フォーム作成の部分をFormオブジェクトのインスタンスを引数として渡す形に変更

以下はコードの一例と内容についてです。

qiita.rb
class OrderPurchase  #OrderモデルとPurchaseモデルの処理
  include ActiveModel::Model
  attr_accessor

   #ここにバリデーションなどの記述をする

  def save
   #ここにデータを保存する記述をする
  end
end

①include ActiveModel::Model
ActiveModel::Modelをincludeすると、バリデーションなどの機能が使えるようになります。
Railsガイドにも記載がありました。
Railsガイド

②attr_accesor
attr_accesorでは、モデルに対応するテーブルに設定したカラム名以外の属性を扱う時に使用します。
ゲッターとセッター(データの取得と更新)をこの記述だけでできるようになります。

①でモデルの機能が使えるようしているので、②でバリデーションを設定したい属性を指定できるのだと思います。

おわりに

プログラミング初心者が備忘録としてまとめたので、間違い等あるかもしれません。
新たにわかった事や、間違いがあれば随時更新します。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】Railsサーバーが起動してもlocalhost:3000で表示されなかった症状が、解決した件について【Ruby】

症状

rails sでサーバーを起動し、コンソール上では起動してそうな感じだが、locakhost:3000にアクセスしても全く反応しない事象が発生しました。

以下はターミナル

ubuntu:~/environment/hello_app (master) $ rails s
=> Booting Puma
=> Rails 6.0.3 application starting in development 
=> Run `rails server --help` for more startup options
Puma starting in single mode...
* Version 4.3.6 (ruby 2.6.3-p62), codename: Mysterious Traveller
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://127.0.0.1:8080
* Listening on tcp://[::1]:8080
Use Ctrl-C to stop

実施したが解決しなかった対策
・rails server起動しなおし
・adBlockerなどは無効化
・ブラウザの開き直し
・bundle install→updateのやり直し
・rails s -b 0.0.0.0→rails s -b $IP -p $PORT

解決方法

1.「preview」→「previewrunningapplication」で表示させた画面を閉じる
2.再度「previewrunningapplication」開きなおす
3.サーバーを起動下記画像の「Browser」の右側の■を押下

→別タブで「Yay! You’re on Rails!」の画面が開けるようになりました。
image.png
image.png

以下は成功時のターミナル

ubuntu:~/environment/hello_app (master) $ rails s
=> Booting Puma
=> Rails 6.0.3 application starting in development 
=> Run `rails server --help` for more startup options
Puma starting in single mode...
* Version 4.3.6 (ruby 2.6.3-p62), codename: Mysterious Traveller
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://127.0.0.1:8080
* Listening on tcp://[::1]:8080
Use Ctrl-C to stop
Started GET "/" for 61.215.149.134 at 2021-03-04 14:18:46 +0000
Cannot render console from 61.215.149.134! Allowed networks: 127.0.0.0/127.255.255.255, ::1
   (2.7ms)  SELECT sqlite_version(*)
Processing by Rails::WelcomeController#index as HTML
  Rendering /home/ubuntu/.rvm/gems/ruby-2.6.3/gems/railties-6.0.3/lib/rails/templates/rails/welcome/index.html.erb
  Rendered /home/ubuntu/.rvm/gems/ruby-2.6.3/gems/railties-6.0.3/lib/rails/templates/rails/welcome/index.html.erb (Duration: 13.0ms | Allocations: 479)
Completed 200 OK in 64ms (Views: 27.3ms | ActiveRecord: 0.0ms | Allocations: 2758)


Started GET "/" for 61.215.149.134 at 2021-03-04 14:18:58 +0000
Cannot render console from 61.215.149.134! Allowed networks: 127.0.0.0/127.255.255.255, ::1
Processing by Rails::WelcomeController#index as HTML
  Rendering /home/ubuntu/.rvm/gems/ruby-2.6.3/gems/railties-6.0.3/lib/rails/templates/rails/welcome/index.html.erb
  Rendered /home/ubuntu/.rvm/gems/ruby-2.6.3/gems/railties-6.0.3/lib/rails/templates/rails/welcome/index.html.erb (Duration: 7.9ms | Allocations: 192)
Completed 200 OK in 12ms (Views: 10.8ms | ActiveRecord: 0.0ms | Allocations: 1165)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む