20210403のRailsに関する記事は27件です。

[Rails]正規表現でバリデーションしてみよう

#はじめに
私の過去の記事で,ユーザ管理機能の実装でdeviseをご紹介しました。その際に特別触れることはありませんでしたが、実はdeviseではemailのアドレス登録で@をつけることが必須です。
当時は、便利だな〜と思いましたがその仕組みが気になり、調べていくと、、、
「正規表現」といものと巡り合ったのでこの記事にてご紹介します。

正規表現とは

正規表現とは、文字列の一部を抽出あるいは置換をしたり、文字列が制約を満たしているかを調べるための表現方法です。

たとえば、あるアンケートで電話番号と郵便番号を書かせるフォームがあったとします。
その時にただの空欄ボックスであった場合にハイフンをつけたりつけなかったり、いろんな人がでてきて管理がしづらいですよね。なので、正規表現によってハイフンが入っていたら取り除いたりするわけです。
このように文字列に特定の文字が含まれているかを確認することや、特定の文字を取り除くなどの操作を行うための技術が正規表現です。

正規表現の基礎

まずは正規表現を利用するための3つのメソッドをご紹介します。
・subメソッド
・matchメソッド
・gsubメソッド

subメソッド

subメソッドは、文字列の指定した部分を別の文字列に置き換えるためのメソッドです。
操作する文字列は//で囲ってやって、第2引数に置換後の文字列を入れます

こんな感じです

irb(main):001:0> str = "ラーメンを食べる"
=> "ラーメンを食べる"

irb(main):002:0> str.sub(/ラーメン/,"チャーハン")
=> "テャーハンを食べる"

matchメソッド

matchメソッドは、指定した文字列がある文字列に含まれているか否かをチェックするためのメソッドです。
これはみた方が理解が早いので以下に例を示します。

irb(main):001:0> str = "Hello, World"
=> "Hello, World"

irb(main):002:0> str.match(/Hello/)
=> #<MatchData "Hello">

irb(main):003:0> str.match(/Good/)
=> nil

戻り値には、MatchDataという種類のオブジェクトで返されます。

gsubメソッド

指定の文字列すべてを置換します。
subと似ていますね。ただし、subの場合、最初にマッチした文字列に対してのみで、gsubは全てです。
そう、gとはgrobalのこと、全てなのです!!!!(笑)

irb(main):001:0> tel = '090-1234-5678'
=> "090-1234-5678"

irb(main):002:0> tel.sub(/-/,'')
=> "0901234-5678"
# 最初のハイフンしか置換されない

irb(main):003:0> tel.gsub(/-/,'')
=> "09012345678"

いよいよバリデーションの準備です!!

ここまでで、なんとなく基本的な部分は理解できましたか??
ここからはさっそくバリデーションをかける準備です。

今回はパスワードに4文字以上という制限をかけましょう。

先に結論から言うと、こんな感じにします。

user.rb
validates :password,format:{with: /[a-z\d]{4,}/i }

初見殺しすぎますよね。。。わかります。。。。

でも焦らない!一つづつ見ていきましょう。
まず、/[a-z\d]{4,}/iの部分を分解してみましょう。

[a-z]
\d
{n, m}
i

[a-z]

角括弧[]を使用することで角括弧で囲まれた文字のうちいずれか1つがマッチするかをチェックしています。-(ハイフン)で範囲を設定することができます。
今回はアルファベットのaからzまでのいずれかにマッチという意味になります。
実際にmatchを使って見てみます

irb(main):001:0> 'debug'.match(/[a-c]/)
=> nil

\d

これは数字を表します。なお、このような文字を特殊文字といいます。

{n, m}

直前の文字が少なくとも n 回、多くても m 回出現するものにマッチすることを確認します。

i

iはオプションで、大文字・小文字を区別せずに検索します。

もう意味はわかりましたか??

ここまでこればもう意味はなんとなくわかってきたはず!!
もう一度さっきのバリデーションをみてみましょう

user.rb
validates :password,format:{with: /\A[a-z\d]{4,}\z/i }

/[a-z\d]{4,}/i を読むと、
[a-z\d](英数字を)
{4,}(最低4回)
/i(大文字小文字区別なく)
と言う意味になります!!!

追記(2021年4月4日):
英数字4文字以上のパスワードにするためには、文字列の最初ですと言う意味を持つ\Aと文字列の末尾ですよと言う芋を持つ\zが必要です。詳しくはこちらをどうぞ。
https://qiita.com/itsumoonazicode/items/e3c7886909ce68986c9a

この制約でのフォーマットをバリデーションをかけると上記のようになるわけです。

おわりに

以上、正規表現についてざっくりですがご紹介いたしました、
ほかにもたくさん表現の仕方があるので興味のある方は調べてみてください!!

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

【EC2】bundle install時、mysql2でエラーがでた件

背景

EC2上で、bundle install を実行したらエラーが発生したのでメモ。

「mysql2(0.5.3)のインストール中にエラーが発生し、Bundlerを続行できません。」という内容で、パッケージの依存を解決することで解消しました。

エラー内容

EC2でbundle installを行うと下記のようなエラーが発生。

Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

    current directory: /home/ec2-user/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mysql2-0.5.3/ext/mysql2
/home/ec2-user/.rbenv/versions/2.6.5/bin/ruby -I /home/ec2-user/.rbenv/versions/2.6.5/lib/ruby/2.6.0 -r ./siteconf20210403-11662-qkup4a.rb extconf.rb
--with-ldflags\=-L/usr/local/opt/openssl/lib
checking for rb_absint_size()... yes
checking for rb_absint_singlebit_p()... yes
checking for rb_wait_for_single_fd()... yes
checking for -lmysqlclient... no
-----
mysql client is missing. You may need to 'sudo apt-get install libmariadb-dev', 'sudo apt-get install libmysqlclient-dev' or 'sudo yum install mysql-devel', and try again.
-----
*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of necessary
libraries and/or headers.  Check the mkmf.log file for more details.  You may
need configuration options.

Provided configuration options:
    --with-opt-dir
    --without-opt-dir
    --with-opt-include
    --without-opt-include=${opt-dir}/include
    --with-opt-lib
    --without-opt-lib=${opt-dir}/lib
    --with-make-prog
    --without-make-prog
    --srcdir=.
    --curdir
    --ruby=/home/ec2-user/.rbenv/versions/2.6.5/bin/$(RUBY_BASE_NAME)
    --with-mysql-dir
    --without-mysql-dir
    --with-mysql-include
    --without-mysql-include=${mysql-dir}/include
    --with-mysql-lib
    --without-mysql-lib=${mysql-dir}/lib
    --with-mysql-config
    --without-mysql-config
    --with-mysql-dir
    --without-mysql-dir
    --with-mysql-include
    --without-mysql-include=${mysql-dir}/include
    --with-mysql-lib
    --without-mysql-lib=${mysql-dir}/lib
    --with-mysqlclientlib
    --without-mysqlclientlib

To see why this extension failed to compile, please check the mkmf.log which can be found here:

  /home/ec2-user/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/extensions/x86_64-linux/2.6.0/mysql2-0.5.3/mkmf.log

extconf failed, exit code 1

Gem files will remain installed in /home/ec2-user/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mysql2-0.5.3 for inspection.
Results logged to /home/ec2-user/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/extensions/x86_64-linux/2.6.0/mysql2-0.5.3/gem_make.out

An error occurred while installing mysql2 (0.5.3), and Bundler cannot continue.
Make sure that `gem install mysql2 -v '0.5.3' --source 'https://rubygems.org/'` succeeds before bundling.

仮説(考えたこと)

  • mysql2 0.5.3 をインストールできないよっていうエラー内容
  • 以下のエラー文からパッケージ関係のエラーであることがわかった
mysql client is missing. You may need to 'sudo apt-get install libmariadb-dev', 'sudo apt-get install libmysqlclient-dev' or 'sudo yum install mysql-devel', and try again.

やったこと

 $ sudo yum install mysql-devel

EC上で実行

$ bundle install

解決!

実行内容の意味

sudo yum install mysql-devel
sudo => rootレベルの特権
yum => パッケージ(各種ソフトをインストールするときのひとかたまりの単位)を管理するコマンド
install => installする
mysql-devel=> インストールする対象のパッケージ(=ファイル群)の名前

'sudo apt-get install libmariadb-dev', 'sudo apt-get install libmysqlclient-dev'

apt-get => パッケージの操作・管理を行うコマンド

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

【rails初学者な】ピンとこない英単語たちの意味を知ろう!

知らない英単語たくさん出てきますよね

プログラミングを勉強していると知らない英単語がたくさん出てくる。
ただでさえ難しいプログラミングなのに英単語の意味がわからないと何がどのように働きそうなのんか予想しずらいと思う。

しかし、私の経験から、英単語の意味を確認するとピンとくる事が多いので下の表に単語の意味をまとめた。
今回はrails tutorial に出てくる日常で見かけない言葉を中心に記したい。

よく出てくるけどピンとこない英単語

英単語    意味     
assert 断言する
belong (...に)属す、(...の)ものである
branch 木の枝、部門
commit 受託する、引き渡す
deploy 展開する、配置する
digest 消化する、圧縮して整理する
fix 修理する、壊れたものをなおす感
fixture 定着物、居座った人
merge 統合する、溶け込ませる
migrate 移住する、渡る、大群が移動するニュアンスもある
modify 改造する、そんなに壊れてないけど改良する感
presence 存在、配置
render (…に)する、与える、下す、提出する、give に近いけどもっとお硬い感
unique 唯一の、比類のない
valid 正当な、確かな
validate 有効にする、確認する
yield 産む、もたらす、身を委ねる

プログラミングを行う際にピンときやすい表現を多くしたつもりです。
学習のヒントになったらなによりです。

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

【rails初学者】ピンとこない英単語たちの意味を知ろう!

知らない英単語たくさん出てきますよね

プログラミングを勉強していると知らない英単語がたくさん出てくる。
ただでさえ難しいプログラミングなのに英単語の意味がわからないと何がどのように働きそうなのか予想しずらいと思う。

しかし、私の経験から、英単語の意味を確認するとピンとくる事が多いので下の表に単語の意味をまとめた。
今回はrails tutorial に出てくる日常で見かけない言葉を中心に記したい。

よく出てくるけどピンとこない英単語

英単語    意味      本来の意味、ニュアンス
assert 主張する 断言する、キッパリ言う
belong (...に)属す、(...の)ものである
branch 木の枝、部門
commit 受託する、引き渡す
deploy 展開する、配置する
digest 消化する、圧縮して整理する
fix 修理する、壊れたものをなおす感
fixture 定着物、居座った人
merge 統合する、溶け込ませる
migrate 移住する、渡る 大群が移動するニュアンスもある
modify 改造する そんなに壊れてないけど改良する感
presence 存在
render 描画する、表現する (…に)する、与える、提出する、give に近いけどもっとお硬い感
unique 唯一
valid 正当な、確かな
validate 有効であることを確認する 確認する、有効にする
yield 産む、もたらす、身を委ねる

プログラミングを行う際にピンときやすい表現を多くしたつもりです。
学習のヒントになったらなによりです。

*ご指摘をくださった方、ありがとうございます。

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

【Ruby】配列の最初の要素を削除するshiftメソッドの使い方

プログラミング勉強日記

2021年4月3日

shiftメソッドとは

 配列の先頭の要素を削除した要素を返すメソッド。ただし、shiftメソッドを使用すると元となる配列自体が変更されるので注意しないといけない。
 引数を指定することもでき、指定した場合にはその個数だけ取り除いてそれを配列で返す。空の配列で指定した場合はnilを返す。

使い方
配列オブジェクト.shift
配列オブジェクト.shift(num)

サンプルプログラム

引数を指定しない場合
# 配列を定義
num = [0, 1, 2, 3, 4, 5]

puts "削除前:#{num}"

# 配列の最初の要素を削除する
puts "削除した要素:#{num.shift}"

puts "削除後#{num}"
実行結果
削除前:[0, 1, 2, 3, 4, 5]
削除した要素:0
削除後:[1, 2, 3, 4, 5]
引数を指定する場合
# 配列を定義
num = [0, 1, 2, 3, 4, 5]

puts "削除前:#{num}"

# 配列の最初の要素を削除する
puts "削除した要素:#{num.shift(2)}"

puts "削除後#{num}"
実行結果
削除前:[0, 1, 2, 3, 4, 5]
削除した要素:[0, 1]
削除後:[2, 3, 4, 5]

参考文献

instance method Array#shift

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

Rails6・Docker・MySQLによる環境構築

無事環境構築できたものを自分用に備忘録として残しておく(適宜修正予定)

プラスでよく使うものも込みでまとめておく。
・Bootstrap導入
・Git / Heroku へPush

ファイル用意

ディレクトリを作成し、その中に以下のファイルを用意
Dockerfile
docker-compose.yml
Gemfile
Gemfile.lock
entrypoint.sh

これより以下のファイル内のmyappは自分が作成したディレクトリ名に置き換える

Dockerfile
FROM ruby:2.7.1

RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
    && echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list

RUN apt-get update -qq && apt-get install -y nodejs yarn
RUN mkdir /myapp
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
COPY . /myapp

# Add a script to be executed every time the container starts.
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

# Start the main process.
CMD ["rails", "server", "-b", "0.0.0.0"]

Rails5との変更点は、webpacker導入によるyarnnodeのインストール
credentials:editを使う予定の場合は、build時点で設定すると良さそう。
RUN apt-get install -y vim

Gemfile
source 'https://rubygems.org'
gem 'rails', '6.0.3'
Gemfile.lock
# 空のままで
entrypoint.sh
#!/bin/bash
set -e

# Remove a potentially pre-existing server.pid for Rails.
rm -f /myapp/tmp/pids/server.pid

# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"
docker-compose.yml
version: '3'
services:
  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: password
    ports:
      - '3306:3306'
    command: --default-authentication-plugin=mysql_native_password
    volumes:
      - mysql-data:/var/lib/mysql
  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
    depends_on:
      - db
    stdin_open: true
    tty: true
volumes:
  mysql-data:
    driver: local

アプリ作成

このコマンドで最後webpackerがインストールされて完了

$ docker-compose run web rails new . --force --no-deps --database=mysql

アプリ生成したら、buildする。最後Successfully ~~と出る

$ docker-compose build

DB作成

config/database.ymlを以下のように変更
また、ここまでの時点でmyappが適切に書き変わっているため、config/database.ymlでは修正する必要は無し。

config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: <%= ENV.fetch("MYSQL_USERNAME", "root") %>
  password: <%= ENV.fetch("MYSQL_PASSWORD", "password") %>
  host: <%= ENV.fetch("MYSQL_HOST", "db") %>

development:
  <<: *default
  database: myapp_development

test:
  <<: *default
  database: myapp_test

production:
  <<: *default
  database: myapp_production
  username: myapp
  password: <%= ENV['MYAPP_DATABASE_PASSWORD'] %>

DBを作成する

$ docker-compose run web rake db:migrate

Dockerを起動する

$ docker-compose up

http://localhost:3000にアクセスし、お馴染みのページが表示されれば無事成功。

Bootstrap導入

必要なものをインストール(バージョンは指定しなくても。)

$ yarn add bootstrap@4.4.1 jquery@3.5.1 popper.js@1.16.1

config/webpack/environment.jsに追記

config/webpack/environment.js
const { environment } = require('@rails/webpacker')

const webpack = require('webpack')
environment.plugins.append('Provide', new webpack.ProvidePlugin({
    $: 'jquery',
    jQuery: 'jquery',
    Popper: ['popper.js', 'default']
}))

module.exports = environment

app/javascript/packs/application.jsに追記

app/javascript/packs/application.js
require("bootstrap/dist/js/bootstrap")

application.cssの拡張子cssをscssに変更

最後にapp/assets/stylesheets/application.scssに追記

app/assets/stylesheets/application.scss
/*
 *= require_tree .
 *= require_self
 */

@import "bootstrap/scss/bootstrap";

bootstrap jquery popper.jsをインストールしてから以上の記述だと、Herokuにデプロイした際にも適用された。

--

しかし以下のやり方だと、Herokuで適用されなかった。一応残しておく
インストールしたファイルをwebpackerの管理下に加える

app/javascript/packs/application.js
~省略~
import "bootstrap"
import "bootstrap/scss/bootstrap.scss"

--

正常に適用されているか確認するために、トップページを用意する。

$ rails g controller welcome index

ルーティングを設定

config/routes.rb
Rails.application.routes.draw do
  root "welcome#index"
end

viewを記述

app/views/layouts/application.html.erb
~省略~
  <body>
    <header class="navbar navbar-expand-sm navbar-light bg-light">
      <div class="container">
        <%= link_to "サービス名", root_path, class: "navbar-brand" %>
      </div>
    </header>
    <div class="container">
      <%= yield %>
    </div>
  </body>
</html>

適切に記述出来ていれば、bootstrapが適用される。

GitへPush

GitHubに登録している名前とメールアドレスを設定

$ git config --global user.name "自分の名前"
$ git config --global user.email "自分のメアド"

パスワード保持の時間設定(1日)

$ git config --global credential.helper "cache --timeout=86400"

Gitリポジトリ初期化

$ git init
$ git add -A
$ git commit -m "コミットメッセージ"

GitHubページで新規リポジトリ作成

そしてPushする

$ git remote add origin https://github.com/GitHubアカウント名/プロジェクト名.git
$ git push -u origin master

HerokuへPush(失敗談込み)

Herokuをインストールする。しかしここで問題発生。以前までCloud9で開発していたので、下のコマンドでインストールしていた。

$ source <(curl -sL https://cdn.learnenough.com/heroku_install)

そして上のコマンドを実行し、versionを確認すると、下のようになり上手くいかず。

$ heroku -v
/usr/local/heroku/bin/heroku: line 44: /usr/local/heroku/bin/node: cannot execute binary file

最終的には下記のように行いインストールに成功

まず、アンインストール

$ rm -rf /usr/local/heroku /usr/local/lib/heroku /usr/local/bin/heroku ~/.local/share/heroku ~/Library/Caches/heroku

次に以下のコマンドでインストール

$ brew tap heroku/brew && brew install heroku

そしてもう一度versionを確認

$ heroku -v
heroku/7.51.0 darwin-x64 node-v12.21.0

気をとりなおして、Herokuにログインする。

$ heroku login --interactive

アプリケーション作成

$ heroku create

Herokuにデプロイする

$ git push heroku master

アプリケーション名変更

$ heroku rename アプリケーション名

参考にした記事

https://qiita.com/me-654393/items/ac6f61f3eee66380ecd7
https://qiita.com/nsy_13/items/9fbc929f173984c30b5d
https://qiita.com/shingokubota/items/3562bf4996468899613c
https://qiita.com/take18k_tech/items/a36d77316e32a6696205

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

[Rails]途中でアプリ名を変更する方法

結論

-手順-
① renameのgem を記述して % bundle install
② 旧名のDBを削除 % rails db:drop
③ アプリ名の変更 % rails g rename:into (新しいアプリ名)
④ 新しいアプリ名のディレクトリへ移動 % cd ../(新しいアプリ名)
⑤ 新しいDBを作成 % rails db:create
⑥ 新しいDBのテーブル作成 % rails db:migrate
⑦ 再起動 % rails s
⑧ GitHubの旧アプリ名を変更

全体の流れは上記の手順です。
下記よりそれぞれ細かく説明していきます。

手順

①renameのgemを追加

Gemfile
  gem 'rename'
  % bundle install

②旧名のDBを削除

  % rails db:drop

旧名のDBを残すなら不要ですが、アプリ名変更の前に削除していた方が簡単です。

③アプリ名の変更

  % rails g rename:into (新しいアプリ名)

①で作成したrenameのgemを使用してアプリ名の変更します。

④新しいアプリ名のディレクトリへ移動

  % cd ../(新しいアプリ名)

⑤新しいDBを作成

  % rails db:create

⑥新しいDBのテーブル作成

  % rails db:migrate

⑦再起動

  % rails s

正しく起動するか確かめます。

⑧GitHubの旧アプリ名を変更

1.GitHubを開いた後、旧アプリ名で利用していたリポジトリを開き、Settingsを選択。
2.Repository nameを変更
3.新アプリ名を入力後、Renameをクリック

これで完了です。

注意点

  • 【アプリ名変更後】元々、旧アプリ名が必ず使用されていた箇所はgemによって修正されましたが、個別に名称を使用した箇所に関しては変更されてない為、自身で修正する必要があります。
  • アプリ名をモデルやコントローラーなどの名称と同じにするとエラーが発生します。

下記のコマンドで旧アプリ名が含まれている箇所を探すことができます。

% grep -rn (新しいアプリ名) . --exclude-dir={.git,tmp,log}

Rubyバージョン

ruby 2.6.5

参考リンク

Railsのアプリ名を変更して、GitHubのリポジトリ名を変更するまで -Qiita

Railsアプリの名称を変更したい!できるだけ楽に安心して行える方法を解説 -blog

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

【Rails6】エラーの中身と対処法 Webpacker::Manifest::MissingEntryError in

rails newでプロジェクトを作成し、scaffoldとmigrationを行ってページを開くと以下が表示される。

image.png

結論からいくと、webpackでコンパイルしていないことが原因。コンパイルすれば解決する。

対策

Webpackerでコンパイルする。方法は4つある。どれも結果は同じ。

1
rails webpacker:compile
2
rails assets:precompile
3
bin/webpack
4
bin/webpack-dev-serve

rails~ はrailsで用意してあるコマンド。bin/webpackはwebpackが用意しているコマンド。

エラー内容の詳細

Showing app/views/layouts/application.html.erb where line #10 raised:

application.html.erbの10行目でエラーが発生。

<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>

javascriptファイル packs/application.jsが読み込めていない。

Webpacker can't find application.js in public/packs/manifest.json. Possible causes:

Webpackerがpublic/packs/manifest.jsonの中に、application.jsが記載されていない。

manifest.js
//= link_tree ../images
//= link_directory ../stylesheets .css

確かに存在していない。


考えうる5つの要因

エラーの中で考えうる解決策を5つ提示してくれている。

1. You want to set webpacker.yml value of compile to true for your environment unless you are using the webpack -w or the webpack-dev-server.

webpack -wwebpack-dev-serverを使っていない場合は、webpakcer.ymlのコンパイルをtrueにする。

→ (済)コンパイルはtrueにっている。

▼補足

コマンド 内容
webpack -w ファイル監視と再ビルド。--watch
webpack-dev-server webpackの開発サーバーの起動


2. webpack has not yet re-run to reflect updates.

webpackが再起動されていないためアップデート内容が反映されていない。
→ (済) rails newでwebpackをインストールしたばかり


3. You have misconfigured Webpacker's config/webpacker.yml file.

webpacker.ymlの設定をミスっている。
→ (済)いじっていない。


4. Your webpack configuration is not creating a manifest.Your manifest contains: { } Ext

webpackの環境環境設定がmanifestを生成してない。
→ (未)manifestを生成するためにはwebpackerが動いている必要がある。(webpackerが動いていない)

webpacker自体は存在しているが、ファイルをコンパイルしていない。

package-lock.json
    "node_modules/@rails/webpacker": {
      "version": "5.2.1",
      "resolved": "https://registry.yarnpkg.com/@rails/webpacker/-/webpacker-5.2.1.tgz",
      "integrity": "sha512-rO0kOv0o4ESB8ZnKX+b54ZKogNJGWSMULGmsJacREfm9SahKEQwXBeHNsqSGtS9NAPsU6YUFhGKRd4i/kbMNrQ==",
      "license": "MIT",
      "dependencies": {省略。依存関係のあるパッケージは多数}
Gemfile.lock
    webpacker (5.2.1)
      activesupport (>= 5.2)
      rack-proxy (>= 0.6.1)
      railties (>= 5.2)
      semantic_range (>= 2.3.0)

エラーの原因

Webpackerが必要なファイルをコンパイル(ビルド)していない。


(補足)コンパイルの実例

bin/webpack

$ bin/webpack
Hash: e332c6419728fac579d5
Version: webpack 4.46.0
Time: 1471ms
Built at: 2021-03-23 21:09:03
                                     Asset       Size       Chunks                         Chunk Names
    js/application-f826770d917d8a37c1d8.js    125 KiB  application  [emitted] [immutable]  application
js/application-f826770d917d8a37c1d8.js.map    139 KiB  application  [emitted] [dev]        application
                             manifest.json  364 bytes               [emitted]              
Entrypoint application = js/application-f826770d917d8a37c1d8.js js/application-f826770d917d8a37c1d8.js.map
[./app/javascript/channels sync recursive _channel\.js$] ./app/javascript/channels sync _channel\.js$ 160 bytes {application} [built]
[./app/javascript/channels/index.js] 211 bytes {application} [built]
[./app/javascript/packs/application.js] 492 bytes {application} [built]
[./node_modules/webpack/buildin/module.js] (webpack)/buildin/module.js 552 bytes {application} [built]
    + 3 hidden modules


rails assets:precompile

$ rails assets:precompile
yarn install v1.22.10
warning package-lock.json found. Your project contains lock files generated by tools other than Yarn. It is advised not to mix package managers in order to avoid resolution inconsistencies caused by unsynchronized lock files. To clear this warning, remove package-lock.json.
[1/4] ?  Resolving packages...
success Already up-to-date.
✨  Done in 0.43s.
I, [2021-03-23T21:02:37.817389 #45531]  INFO -- : Writing public/assets/manifest-b4bf6e57a53c2bdb55b8998cc94cd00883793c1c37c5e5aea3ef6749b4f6d92b.js
I, [2021-03-23T21:02:37.817581 #45531]  INFO -- : Writing public/assets/manifest-b4bf6e57a53c2bdb55b8998cc94cd00883793c1c37c5e5aea3ef6749b4f6d92b.js.gz
I, [2021-03-23T21:02:37.817881 #45531]  INFO -- : Writing public/assets/application-b324c44f04a0d0da658824105489a2676d49df561c3d06723770321fd441977c.css
I, [2021-03-23T21:02:37.818318 #45531]  INFO -- : Writing public/assets/application-b324c44f04a0d0da658824105489a2676d49df561c3d06723770321fd441977c.css.gz
I, [2021-03-23T21:02:37.818606 #45531]  INFO -- : Writing public/assets/posts-04024382391bb910584145d8113cf35ef376b55d125bb4516cebeb14ce788597.css
I, [2021-03-23T21:02:37.819486 #45531]  INFO -- : Writing public/assets/posts-04024382391bb910584145d8113cf35ef376b55d125bb4516cebeb14ce788597.css.gz
Compiling...
Compiled all packs in public/packs
Hash: 01fcdd9bc3cb51647ed0
Version: webpack 4.46.0
Time: 3541ms
Built at: 2021-03-23 21:02:44
                                        Asset       Size  Chunks                         Chunk Names
       js/application-981ce9ad4b929d610701.js   69.3 KiB       0  [emitted] [immutable]  application
    js/application-981ce9ad4b929d610701.js.br   15.3 KiB          [emitted]              
    js/application-981ce9ad4b929d610701.js.gz   17.8 KiB          [emitted]              
   js/application-981ce9ad4b929d610701.js.map    205 KiB       0  [emitted] [dev]        application
js/application-981ce9ad4b929d610701.js.map.br   43.9 KiB          [emitted]              
js/application-981ce9ad4b929d610701.js.map.gz   50.9 KiB          [emitted]              
                                manifest.json  364 bytes          [emitted]              
                             manifest.json.br  129 bytes          [emitted]              
                             manifest.json.gz  142 bytes          [emitted]              
Entrypoint application = js/application-981ce9ad4b929d610701.js js/application-981ce9ad4b929d610701.js.map
[0] (webpack)/buildin/module.js 552 bytes {0} [built]
[4] ./app/javascript/packs/application.js 480 bytes {0} [built]
[5] ./app/javascript/channels/index.js 205 bytes {0} [built]
[6] ./app/javascript/channels sync _channel\.js$ 160 bytes {0} [built]
    + 3 hidden modules

manifest.js, .css, .jsファイルを生成し、同時にgzなどの圧縮ファイルをコンパイルしている。

bin/webpack-dev-server

$ bin/webpack-dev-server
ℹ 「wds」: Project is running at http://localhost:3035/
ℹ 「wds」: webpack output is served from /packs/
ℹ 「wds」: Content not from webpack is served from /Users/***/projects/my-pj/rails-js/public/packs
ℹ 「wds」: 404s will fallback to /index.html
ℹ 「wdm」: Hash: c5285e41bac959286042
Version: webpack 4.46.0
Time: 2394ms
Built at: 2021-03-23 21:10:05
                                     Asset       Size       Chunks                         Chunk Names
    js/application-a3df8194e78e85ae2bd1.js    515 KiB  application  [emitted] [immutable]  application
js/application-a3df8194e78e85ae2bd1.js.map    579 KiB  application  [emitted] [dev]        application
                             manifest.json  364 bytes               [emitted]              
ℹ 「wdm」: Compiled successfully.
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails6, Docker】エラー対処法:ActiveRecord::ConnectionNotEstablished

docker上で起動した、Railsで作成したアプリケーションで、ActiveRecordを使ってDBにアクセスしようとするとエラーが発生する。

ActiveRecord::ConnectionNotEstablished (could not translate host name "db" to address: nodename nor servname provided, or not known)

原因

Docker経由のRailsコンソールではなく、ローカルのRialsコンソールで操作していた。

対処法

Dockerコンテナに入ってから、Rialsコンソールを起動する

#コンテナ名の確認
$ docker ps
CONTAINER ID   IMAGE                       COMMAND                  CREATED        STATUS        PORTS                                            NAMES
588188913f4c   rails6-docker-alpine_web    "bin/rails s -p 3000…"   3 hours ago    Up 3 hours    0.0.0.0:3000->3000/tcp                           rails6-docker-alpine_web_1
6a965250e960   postgres:11.1-alpine        "docker-entrypoint.s…"   20 hours ago   Up 3 hours    5432/tcp                                         rails6-docker-alpine_db_1

railsアプリケーションはrails6-docker-alpine_web_1

コンテナに入る: docker exec -it <コンテナ名> sh
(railsの場合はsh。 laravelなどはbash。)

#コンテナ内に入る
$ docker exec -it rails6-docker-alpine_web_1 sh

#railsコンソールの起動
/usr/src/app # rails c
Running via Spring preloader in process 130
Loading development environment (Rails 6.1.3.1)
irb(main):001:0>

#> 
irb(main):004:0> User.find(1)
  User Load (0.4ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
=> #<User id: 1, name: "aaabbb", created_at: "2021-04-03 07:35:30.551136000 +0000", updated_at: "2021-04-03 07:53:48.907671000 +0000">

データ取得に成功。


ActiveRecordとは?

DBの種類に関係なく、Modelを経由してDBと通信する便利機能。
MySQL, sqlite3, postgresなどどのDBとでも通信できる。

使い方は、Railsコンソールに入って、モデル名.メソッドとする。


例: ActiveRecord経由でDBにデータ追加

Userというモデルと通信する場合は以下のようになる。

#インスタンス作成し変数に格納
irb(main):019:0> user = User.new(name: 'tanaka')

#DBに保存
irb(main):021:0> user.save

#DBのデータ呼び出し
irb(main):022:0> User.all
  • モデル名.new: インスタンスの生成
  • モデル名.save: DBに保存
  • モデル名.all: すべてのデータを抽出



▼実際のターミナル

irb(main):019:0> user = User.new(name: 'tanaka')
=> #<User id: nil, name: "tanaka", created_at: nil, updated_at: ...

irb(main):021:0> user.save
  TRANSACTION (0.5ms)  BEGIN
  User Create (0.9ms)  INSERT INTO "users" ("name", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id"  [["name", "tanaka"], ["created_at", "2021-04-03 08:05:56.412011"], ["updated_at", "2021-04-03 08:05:56.412011"]]
  TRANSACTION (2.2ms)  COMMIT
=> true

irb(main):022:0> User.all
  User Load (0.6ms)  SELECT "users".* FROM "users" /* loading for inspect */ LIMIT $1  [["LIMIT", 11]]
=> #<ActiveRecord::Relation [#<User id: 1, name: "aaabbb", created_at: "2021-04-03 07:35:30.551136000 +0000", updated_at: "2021-04-03 07:53:48.907671000 +0000">, #<User id: 4, name: "tanaka", created_at: "2021-04-03 08:05:56.4120
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Reactでページ内遷移のある横スクロールスライドメニューを実装する

はじめに

スマホ向けのWebアプリケーションをReactで開発していて、横スクロール型のスライドメニュー(ナビゲーション)を作りたい!という時にご参考ください。 React×Railsで開発しています。

HTMLのアンカータグで#を使って特定のid属性に遷移させたい!それをReactでやりたい!みたいな時を想定。

やりたいこと

  1. アプリライクな横スクロール型のメニューを作りたい(スクロールバー非表示にして)
  2. メニューの各要素をクリックしたらそれぞれの要素までぬるっとアニメーション付きでページ内遷移させたい
  3. ヘッダーの高さを考慮してページ内遷移させたい
  4. mapではき出した動的な要素にid属性を振って遷移先にしたい

方針

Reactでページ内遷移するいい方法ないかなーと探していたところ、こちらの記事(Reactでページ内リンクを実装する)を発見。今回はこちらを参考にreact-router-hash-linkを使うことに。

Githubはこちら:React Router Hash Link

前提として本実装では、itemCategorycategory_nameがカテゴリ名で、それをメニューバーにし、同一ページ内のそれぞれのcategory_nameの部分に遷移させています。

実装

1. yarn add かnpmでインストール

Terminal
npm install --save react-router-hash-link

2.react-router-hash-linkMemoryRouter(後述するエラーが出たため)をimport

hoge.tsx
import {MemoryRouter} from 'react-router-dom';
import {HashLink} from 'react-router-hash-link';

3.遷移元となる横スクロールのメニューを作成

smoothをつけるだけでぬるっといい感じの遷移に

HashLinkの機能。とても便利。

href=#hogeになるようにid設定

JSX記法でto={'#' + itemCategory.category_name}とした。これで#hogeとなり、idに遷移できる。

謎のエラーをMemoryRouterで解決

HashLinkを使ったところ、Uncaught Error: Invariant failed: You should not use <Link> outside a <Router>のエラーが表示されたため、こちらの記事(解決方法: "Error: Invariant failed: You should not use outside a ")を参考に、MemoryRouterHashLinkを囲う。

ヘッダーの高さ調整

scroll={el => { el.scrollIntoView(true); window.scrollBy(0, -160) }}でヘッダー部分の高さを考慮。この場合は160px分下げている。

hoge.tsx
<div className={classes.scrollMenuList}>
  <div className={classes.scrollMenuListMask}>
    {props.shopItemCategories.map((itemCategory) => (
      <Typography component="h2" variant="h3" >
    <MemoryRouter>
      <HashLink 
        smooth to={'#' + itemCategory.category_name} 
        scroll={el => { el.scrollIntoView(true); window.scrollBy(0, -160) }}
        className={classes.scrollMenu}>{itemCategory.category_name}
      </HashLink>
    </MemoryRouter>
  </Typography>
  ))}
 </div>
</div>

4.スクロールバーを非表示に

こちらの記事(Appleに学ぶ、横スクロールナビを組む時のCSSメモ)を参考に、MaskとなるscrollMenuListMaskを用意し、親要素のscrollMenuListoverflow:"hidden"としラッパーする。各要素はアンダーバーがダサいので、textDecoration:"none"に。

hoge.tsx
   scrollMenuList: {
      width: '900px',
      overflow: "hidden",
      height: 60,
    },
    scrollMenuListMask: {
      overflowX: "auto",
      whiteSpace: "nowrap",
      display: 'flex',
      height: 80, //Maskのheightを親要素より高くすることがミソ
    },
    scrollMenu: {
      margin: theme.spacing(1, 2, 1),
      fontSize: 36,
      color: "#8f8f8f",
      textDecoration: "none"
    },

5.遷移先にid属性を振る

id属性を振るだけなので簡単。ここで振ったidを遷移元となるHashLinkで指定することでページ内遷移できる。

hoge.tsx
{props.shopItemCategories.map((itemCategory) => (
 <div className={classes.root}>
   <Typography component="h2" variant="h3" id={itemCategory.category_name}>
    {itemCategory.category_name}
   </Typography>
 </div>
...省略
))}

完成

完成したものが以下の通り。

hoge.tsx
//Import
import {MemoryRouter} from 'react-router-dom';
import {HashLink} from 'react-router-hash-link';

//該当部分のみのCSS
const useStyles = makeStyles((theme: Theme) =>
  createStyles({
    scrollMenuList: {
      width: '900px',
      overflow: "hidden",
      height: 60,
    },
    scrollMenuListMask: {
      overflowX: "auto",
      whiteSpace: "nowrap",
      display: 'flex',
      height: 80,
    },
    scrollMenu: {
      margin: theme.spacing(1, 2, 1),
      fontSize: 36,
      color: "#8f8f8f",
      textDecoration: "none"
    },
  })
)

//スクロールスライドメニューとなる部分
<div className={classes.scrollMenuList}>
  <div className={classes.scrollMenuListMask}>
    {props.shopItemCategories.map((itemCategory) => (
      <Typography component="h2" variant="h3" >
    <MemoryRouter>
      <HashLink 
        smooth to={'#' + itemCategory.category_name} 
        scroll={el => { el.scrollIntoView(true); window.scrollBy(0, -160) }}
        className={classes.scrollMenu}>{itemCategory.category_name}
      </HashLink>
    </MemoryRouter>
  </Typography>
  ))}
 </div>
</div>

//メニューからの遷移先になる要素たち
{props.shopItemCategories.map((itemCategory) => (
<>
 <Box>
   <div className={classes.root}>
     <Typography component="h2" variant="h3" id={itemCategory.category_name}>
     {itemCategory.category_name}
   </Typography>
  </div>
 </Box>

...省略
</>
))}

今回も色々な記事を参考にさせていただきました。横スクロールのスライダーみたいなのは結構使いたい場面多いと思うので、少しでも参考になれば嬉しいです。

参考

横スクロールナビゲーションを実装する3つの方法
Reactでページ内リンクを実装する
【React Router】画面遷移時に#を用いて特定の要素に移動させる方法
Reactで動的に属性の値を生成する方法

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

[Rails] 親モデルと子モデルを同時に削除する方法 [dependent: :destroy]

結論

dependent: :destroy を記述することで、「親モデルを削除した際にその子モデルも同時に削除」できます。

投稿内容を削除する場合、その投稿に紐づくコメントなども同時にテーブルから削除する時に使用します。

Rubyバージョン

ruby 2.6.5

dependent: :destroyの記述場所

dependent: :destroyは親モデルのアソシエーションのみに記述します。

(親モデル) post.rb
class Post < ApplicationRecord
  has_many :comments, dependent: :destroy 
(子モデル) comment.rb
class Comment < ApplicationRecord
  belongs_to :post

モデルが複数存在する場合

子モデル(comment)に紐づいて、さらに子モデル(like)が存在する場合、追加で「親モデル」にdependent: :destroyを記述します。

comment.rb
class Comment < ApplicationRecord
  has_many :likes, dependent: :destroy

参考リンク

Active Record の関連付け

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

Rails パーシャル

【Rails パーシャル】

Railsでは、複数のビューで共有するビューをパーシャルとして切り出すことができる。

Rails パーシャルの基本

新規作成画面と編集画面でほぼ同じの作りである場合など、それぞれにフォームを記載していると冗長であり、修正が大変になる。無駄が多い。
 → 共通のものはパーシャルとして再利用する。

 ・可読性アップ
 ・再利用性もアップ

ファイル名の先頭にアンダースコアを付ける。

例) _form.html.erb

パーシャルを呼び出すには、renderメソッドを使用。

例) <%= render partial: 'form' %>

パーシャル内でインスタンス変数は使用しない。

部分テンプレートの依存度が高くなる。

参考

3.2 パーシャル
部分テンプレートまたはパーシャルは、出力を扱いやすく分割するための仕組みです。パーシャルを使用することで、ビュー内のコードをいくつものファイルに分割して書き出し、他のテンプレートでも使いまわすことができます。

3.2.1 パーシャルの命名ルール
パーシャルをビューの一部に含めて出力するには、ビューでrenderメソッドを使用します。

 <%= render "menu" %>

上の呼び出しにより、_menu.html.erbという名前のファイルの内容が、renderメソッドを書いたその場所でレンダリングされます。パーシャルファイル名の冒頭にはアンダースコアが付いていることにご注意ください。これは通常のビューと区別するために付けられています。ただしrenderで呼び出す際にはこのアンダースコアは不要です。以下のように、他のフォルダの下にあるパーシャルを呼び出す際にもアンダースコアは不要です。

<%= render "shared/menu" %>

上のコードでは、app/views/shared/_menu.html.erbパーシャルを読み込んで使用します。

3.2.2 パーシャルを活用してビューを簡潔に保つ
すぐに思い付くパーシャルの使い方といえば、パーシャルをサブルーチンと同等のものとみなすというのがあります。ビューの詳細部分をパーシャルに移動し、コードの見通しを良くするために、パーシャルを使うのです。

Railsガイド 参照

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

field_with_errorsのレイアウトが崩れるのを防ぐ【Tailwind css】

背景

ユーザ管理機能のgem「devise」を導入後、新規登録設定を実施
新規登録に失敗した際にレイアウトが崩れてしまうことを確認
Googleの検証ツールを使用して確認したところ
元は「class="reg_info_field"」というクラスの親に
「div class="field_with_errors"」が追加されていた
見た目が変わるのはよくないため修正を行う

今回もQiitaさんに投稿されている方々にお世話になりました、
ありがとうございます

参考文献
field_with_errorsによるレイアウト崩れを防ぐ
Railsのバリデーションエラーで、「field_with_errors」によるレイアウト崩れを防ぐ

開発環境

  • Ruby 3.0.0
  • Rails 6.1.3.1
  • tailwindcss 2.0.4

改善前の状態

下記の画像は新規登録画面の一部を切り取ったもの
レイアウトが崩れてない状態
Googleの検証ツールで確認したところclass名「reg_info_field」
スクリーンショット 2021-04-03 13.png
スクリーンショット2.png

上記の状態が新規登録の失敗をすると・・・・
入力欄が狭くなっている
加えて「div class="field_with_errors"」が親になっているではないか・・・・
スクリーンショット3.pngスクリーンショット4.png

解決方法

@mogurinchuさんの投稿の「field_with_errorsによるレイアウト崩れを防ぐ
の情報によると下記の2点でいけるらしいのどっちも試す

  • 自動で読み込まれるfield_with_errorsタグを読み込まないように設定する
  • field_with_errorsに対してCSSをあてる

方法1

・自動で読み込まれるfield_with_errorsタグを読み込まないように設定する

config/application.rb
module TestTailwind
  class Application < Rails::Application
   /* 下記追記 */
  config.action_view.field_error_proc = Proc.new { |html_tag, instance| html_tag }
  end
end

解決!!

方法2

・field_with_errorsに対してCSSをあてる
こちらの記事「Railsのバリデーションエラーで、「field_with_errors」によるレイアウト崩れを防ぐ」を少し参考
「Tailwind css」だと少し異なる!!
Tailwind cssだと「display: contents;」は「contents;」だけとなる

app/javascript/css/tailwind.css
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";

/* 下記追記 */
@layer components {
  /* 「field_with_errorr」にCSSをあてる */
  .field_with_errors {
    @apply contents;
  } 
}

解決!!

おわりに

レイアウトが崩れることに関しては上記の方法で問題はなさそう
しかし、どちらを採用したほうがいいのか判断が出来なかった・・・

  • 処理速度の違いがあるのか
  • webpackに影響でやすいのか
  • ローカル環境だから問題はないが、本番環境で影響がでるのか

知識がないため、これらなどを判断する術もなし・・・・
とりあえず、様子見してみる!!

参考文献

field_with_errorsによるレイアウト崩れを防ぐ
Railsのバリデーションエラーで、「field_with_errors」によるレイアウト崩れを防ぐ

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

human_attribute_name(:カラム名)を使う Rails

初めに

railsのviewで度々見かけるが見かける度に毎回調べていたので、メモがわり。

概要

html.slim
Task.human_attribute_name(:name)
/#=> 名称

上記の形で参考書で使われていた。

前提

ja.yml
    models:
      task: タスク
    attributes:
      task:
        name: 名称

config/locales/ja.ymlにおいて、このように記述がされている。

解説

html.slim
Task.human_attribute_name(:カラム名)

ja.ymlファイルの中でカラム名に対応する文字列が引っ張り出される。
ここでは'名称'がブラウザで表示されることになる。

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

Mysql2::Error: Table ' ~~~~~ ' already existsと表示され他時の対処法

・マイグレーションしようとしたときにこのようなエラーが出た。
 
-- create_table(:microposts)
rails aborted!
StandardError: An error has occurred, all later migrations canceled:

Mysql2::Error: Table 'microposts' already exists
~省略~
Caused by:
ActiveRecord::StatementInvalid: Mysql2::Error: Table 'microposts' already exists
~省略~
Caused by:
Mysql2::Error: Table 'microposts' already exists
~省略~


・エラーの意味は「もうすでに同じテーブルがありますよ。」といった感じのエラー。
・この状況になったらテーブルを消すことで解決する。

手順
・rails dbでデータベースを開く。
・mysqlが開くので、SHOW TABLES;を打ち込む。
・上記の例のエラーに関するとmicropostsを消す事になるが、各々違うと思うので、臨機応変に対応。
drop table 〜〜〜;で消す。
・削除ができたかどうかをSHOW TABLES;で確認。
・exitで抜ける。
・rails db:migrateを実行。

完   

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

Rails 6.1・React・Docker・MySQLで環境構築

前書き

2021年3月からE2Eテストの自動化を担当し、初めて仕事でコードを書いている。
テスト対象のアプリケーションのapiがRails、フロントがReactで作られているので、
興味本意でプライベートで何か作ってみることにした。
(職場でテストコードをJSで書くので、JSに慣れるという意味合いもある。)

早速、Dockerで環境構築してみたので、備忘として残す。

環境

・macOS Big Sur 11.2.3
・Ruby 3.0
・Rails 6.1.3.1
・Docker 20.10.5
・docker-compose 1.28.5
・Mysql 8.0

手順

全体をざっくりと説明すると以下の通り。

1.ファイルを全て準備する
2.docker-compose buildする
3.railsとreactの各種コマンド実行
4.docker-compose upする

1.ファイルを全て準備する

最終的に、以下のような構造になる。

spa-chat
|-- docker-compose.yml
|-- api
    |-- entrypoint.sh
    |-- Gemfile
    |-- Gemfile.lock
    |-- Dockerfile
|-- front
    |-- Dockerfile

Rails関連

Gemfile

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

Gemfileには、使いたいRailsのバージョンを記入。
この場合、Rails6系の最新のバージョンを採用。

Gemfile.lock

touch Gemfile.lock

空のGemfile.lockを作成。

entrypoint.sh

entrypoint.sh
#!/bin/bash
set -e

# Remove a potentially pre-existing server.pid for Rails.
rm -f /myapp/tmp/pids/server.pid

# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"

Dockerfile

Dockerfile
FROM ruby:3.0
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
  && echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list \
  && apt-get update -qq \
  && apt-get install -y nodejs yarn \
  && mkdir /myapp
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
COPY . /myapp

COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

CMD ["rails", "server", "-b", "0.0.0.0"]

Dockerfileについては、Rails5系とRails6系で書き方が異なるので注意が必要。
Rails6系では、JavascriptコンパイラがWebpackerになったことに起因する。

React関連

Dockerfile

Dockerfile
FROM node:15.13.0-alpine
RUN mkdir /myapp
WORKDIR /myapp

docker-compose.yml

docker-compose.yml
version: '3'
services:
  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: password
    ports:
      - '3306:3306'
    command: --default-authentication-plugin=mysql_native_password
    volumes:
      - mysql-data:/var/lib/mysql
  api:
    build: ./api
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - ./api:/myapp
      - gem_data:/usr/local/bundle
    ports:
      - "3000:3000"
    depends_on:
      - db
    stdin_open: true
    tty: true
  front:
    build: ./front
    command: yarn start
    ports:
      - '8000:3000'
    volumes:
      - ./front:/myapp
    depends_on:
      - api

volumes:
  mysql-data:
  gem_data:
    driver: local

2.docker-compose buildする

各種ファイルを揃えたので、イメージをbuild。

docker-compose build

3.RailsとReactの各種コマンド実行

コマンドを実行し、必要なファイルを揃えていく。

React


ローカルで立ち上げる時と同じような感じで、以下のコマンドを実行。
docker-compose run npx create-react-app front

※原因は突き止められなかったが、フロント用のDockerfileを置いたfrontディレクトリに、
さらに別のfrontディレクトリが作成され、その配下に各種フォルダが作成された。
なので、Dockerfileと同じ階層に、先程のコマンドで作成したフォルダを移動する必要がある。
(移動させないと、ブラウザからフロントにアクセスできない。)

アドバイスいただけますと幸いです。

Rails

まず、以下のコマンドを実行。

docker-compose run api rails new . --force --no-deps --database=mysql --skip-test --webpacker --api

apiモードでrails new。
RSpecでテストコードを書くので、testディレクトリは作成しない。

次に、config/database.ymlを編集。

database.yml
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: <%= ENV.fetch("MYSQL_USERNAME", "root") %>
  password: <%= ENV.fetch("MYSQL_PASSWORD", "password") %>
  host: <%= ENV.fetch("MYSQL_HOST", "db") %>

development:
  <<: *default
  database: myapp_development

test:
  <<: *default
  database: myapp_test

production:
  <<: *default
  database: myapp_production
  username: myapp
  password: <%= ENV['MYAPP_DATABASE_PASSWORD'] %>

そして、データベースを作成。

docker-compose run api rake db:create

4.docker-compose upする

準備が整ったので、コンテナを起動。

docker-compose up -d

localhost:8000で見慣れたReactの画面が表示。
image.png

localhost:3000で見慣れたRailsの画面が表示。
image.png

参考にしたサイト

https://qiita.com/nsy_13/items/9fbc929f173984c30b5d
Rails側の設定を書くときにとても参考になりました。

https://nakatanorihito.com/programming/docker-rails-api-react-postgresql/
React側の記述や、ディレクトリ構造を参考にしました。
docker-compose.ymlは上記2サイトをどちらも参考にしています。

https://docs.docker.com/compose/rails/
docker docsに記載がある、Railsの環境構築方法。
Rails5系を使うことを前提に書かれている。

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

Base64を完璧に理解したい人以外、見ないでください。

はじめに

タイトルはちょっとウケ狙いなので、許してください。。
業務中に、Base64でエンコードして、デコードして、といった指示があり、初めて聞いた単語に「?」が浮かんだ。
ここでは、自分が調べた情報を共有して、自分のような0からスタートする人の助けになる記事を書きたいと思って書きました。

Base64とは

base64とは、64進数を意味する言葉です。
すべてのデータをアルファベット(a~z, A~z)と数字(0~9)、一部の記号(+,/)の64文字で表すエンコード方式のこと。
ただ、データ長を揃えるためにパディングとして末尾に記号の=を使用するので、厳密にはbase64は、65文字の英数字から表現されています。

エンコードの流れ

  1. 対象の文字列を 16 進数に変換する

  2. 16 進数に変換した数字をそれぞれ 2 進数に変換する

  3. 6 ビットごとに分割して、足りない部分は 0 で詰める

  4. 変換表にしたがって各 6 ビットをエンコードしていく

  5. 4文字ごとに分割して末尾が余る場合、"=" で詰める

  6. 最後にすべての文字をつなげて完成

※デコードは逆の流れ

ABCDEFG

41 42 43 44 45 46 47

0100 0001, 0100 0010, 0100 0011, 0100 0100, 0100 0101, 0100 0110, 0100 0111

010000 010100 001001 000011 010001 000100 010101 000110 010001 11

010000 010100 001001 000011 010001 000100 010101 000110 010001 110000

QUJDREVGRw

"QUJD", "REVG", "Rw"

"QUJD", "REVG", "Rw=="

QUJDREVGRw==

モジュール関数

decode64

与えられた文字列をBase64デコードしたデータで返します。

require 'base64'

str = 'Tm93IGlzIHRoZSB0aW1lIGZvciBhbGwgZ29vZCBjb2RlcnMKdG8gbGVhcm4gUnVieQ=='
puts Base64.decode64(str)
#=> "Now is the time for all good coders\nto learn Ruby"

encode64

与えられた文字列をBase64エンコードしたデータで返します。

require 'base64'

str = "Now is the time for all good coders\nto learn Ruby"
Base64.encode64(str)
#=> Tm93IGlzIHRoZSB0aW1lIGZvciBhbGwgZ29vZCBjb2RlcnMKdG8gbGVhcm4gUnVieQ==

おまけ

こちらのツールを使えば自動でエンコードした文字列を出力してくれるので、エンコード文字列が欲しい場合はこちらを使うのが便利です。

終わりに

ここまでで、0からの知識の人でもある程度は掴めたのではないでしょうか?
頻繁ではないにしろ、必要な知識ではあると思うので、使えるレベルまで持っていって損は無いです!

参考

Base64のしくみを理解するためにRubyで実装してみる

module Base64

base64でエンコードされた画像をActive Storageで保存する

Rails(Ruby)でBase64化された画像を取り回すときのSnippet

singleton method Tempfile.new

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

RailsでLINE_Boot作成する

前提

LINE-Botの作成の方法を備忘録として残してます。

環境

  • Homebrow
  • ruby '2.6.3'
  • rails '6.1.3'

Messaging API | LINE Developers

Messaging API | LINE Developers
先にLINE Developers登録してください。

チャネルの作成

「新規プロバイダー作成」をして「Messaging API」をクリックします。

$ gem 'line-bot-api'

bundle installしましょう

ngrokのインストール

Homebrewを使ってngrokをインストールします。

$ brew install ngrok
$ ngrok --version

バージョンが表示されていたらインストール出来ています。

$ rails s

railsのサーバー起動して新しいターミナルでngrokを起動させます。
http://localhost:3000でアクセスしてますのでhttp 3000します。

$ ngrok http 3000

ngrokのターミナル上で表示されていますのでここからアクセスできます。
ですがrailsでDNSリバインディング攻撃の対策のためアクセスできないようになっています。

Forwarding  https://xxxxxxx.ngrok.io
config/environments/development.rb
  config.file_watcher = ActiveSupport::EventedFileUpdateChecker

  # Uncomment if you wish to allow Action Cable access from any origin.
  # config.action_cable.disable_request_forgery_protection = true
  config.hosts.clear #追加します
end

railsを再起動させてngrokのターミナルのhttps://xxxxxxx.ngrok.ioアクセスします。

app/controllers/line_bot_controller.rb
 protect_from_forgery except: [:アクション名]
 #CSRF対策を無効化するコードです。

.env作成

gem 'dotenv-rails'

bundle installします。

$ touch .env
.env
LINE_CHANNEL_SECRET='xxxxxxxx'
LINE_CHANNEL_TOKEN='xxxxxxxx'

LINE_CHANNEL_SECRET
基本設定のチャンネルシークレットを発行し、コピーします。

LINE_CHANNEL_TOKEN
メッセージングAPI設定のチャネルアクセストークンを発行し、コピーします。

gitignore
/.env #追加します

Webhook設定

表示させたページを設定します。
https://xxxxxxxxxx.ngrok.io/xxx
ngrokを起動するたびにURLが変わるため設定しなおす必要があります。

これでRailsとlineの連携の設定は完成です。
簡単な返答くらいなら可能な状態になりました。

gem 'httpclient'を使用し、WebAPI叩ける様にもできます。

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

【Rails】FontAwesomeの導入方法

はじめに

この記事はFontAwesomeの導入方法について説明します。

Font Awesomeとは、自身のウェブサイトやアプリケーション、WordやPDFなどのドキュメントにも埋め込めるWebアイコンフォントのことで商用利用もできます。

FontAwesomeの導入

まずはgemを編集します

gemfile
gem 'font-awesome-rails'

忘れずにbundle installをしましょう

ターミナル
$ bundle install

最後にapplication.scssを編集します

application.scss
/*
 * This is a manifest file that'll be compiled into application.css, which will include all the files
 * listed below.
 *
 * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's
 * vendor/assets/stylesheets directory can be referenced here using a relative path.
 *
 * You're free to add application-wide styles to this file and they'll appear at the bottom of the
 * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
 * files in this directory. Styles in this file should be added after the last require_* statement.
 * It is generally better to create a new file per style scope.
 *
 *= require_tree .
 *= require_self
 */
 /*
*/
@import "bootstrap";
//↓ 追加
@import "font-awesome";

これで使う準備は整いました。

つかってみよう

リンクを入れたい場所に入れることで使えるようになります。
例えばカレンダーのアイコンを表示させてみます

<i class="fa fa-calendar" aria-hidden="true"></i>

以下のようにカレンダーのアイコンが表示されれば成功です
xTN5ilycotqXg5H1617419586_1617419656.png

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

【Rails】database.ymlとは?役割と見方。rails db:createでDB作成するときの仕様書

RialsでDBを作成するときに、rails db:createコマンドを使う。この時に、database.ymlの中身に基づいてDBが作成される。このdatabase.ymlの記述内容を理解する。

database.ymlとは?

Railsでデータベースに接続するための情報を記載したファイル

rails new <アプリ名>でrailsのプロジェクトを新規作成した時に、configディレクトリ配下に自動生成される

デフォルトのDBはsqliteが指定されている。


DBの指定(sqlite以外)

デフォルトのsqlite以外のDBに変更したい場合は、rails newでオプションを指定すると、自動でdatabase.ymlを上書きしてくれる。

rails new <アプリ名> -d <DBの種類>

  • -d--databaseと同じ
#mysqlの場合
rails new test-app -d mysql

#postgresの場合
rails new test-app -d postgresql


database.ymlの中身

rails new test-app -d postgresqlを実行した時に作成されたdatabase.ymlの中身を見てみる。

コメントアウトで注釈がたくさん記載されている。&<<:*などyaml専用の記述が使われている。

yamlの記述をJSONに変換すると中身が見やすい。

全体像

コメントアウトを除いてjsonにコンパイルすると以下のようになる。
default, development, test, productionの4つから構成されている。

database.yml->json
{
    "default": {
        "adapter": "postgresql",
        "encoding": "unicode",
        "pool": "<%= ENV.fetch(\"RAILS_MAX_THREADS\") { 5 } %>"
    },
    "development": {
        "adapter": "postgresql",
        "encoding": "unicode",
        "pool": "<%= ENV.fetch(\"RAILS_MAX_THREADS\") { 5 } %>",
        "database": "test-app_development"
    },
    "test": {
        "adapter": "postgresql",
        "encoding": "unicode",
        "pool": "<%= ENV.fetch(\"RAILS_MAX_THREADS\") { 5 } %>",
        "database": "test-app_test"
    },
    "production": {
        "adapter": "postgresql",
        "encoding": "unicode",
        "pool": "<%= ENV.fetch(\"RAILS_MAX_THREADS\") { 5 } %>",
        "database": "test-app_production",
        "username": "test-app",
        "password": "<%= ENV['TEST-APP_DATABASE_PASSWORD'] %>"
    }
}

1. 冒頭のコメントアウト

(1)冒頭のコメントアウト
# PostgreSQL. Versions 9.3 and up are supported.
#
# Install the pg driver:
#   gem install pg
# On macOS with Homebrew:
#   gem install pg -- --with-pg-config=/usr/local/bin/pg_config
# On macOS with MacPorts:
#   gem install pg -- --with-pg-config=/opt/local/lib/postgresql84/bin/pg_config
# On Windows:
#   gem install pg
#       Choose the win32 build.
#       Install PostgreSQL and put its /bin directory on your path.
#
# Configure Using Gemfile
# gem 'pg'
#

・PostgreSQLの対応するバージョン。9.3以上をサポート。バージョンはpostgres --versionで確認できる。

pgのインストール方法。pgはrailsからPostgreSQLのDBにアクセスするためのライブラリ。

pgを使うには、Postgresがインストールされている必要がある。


2. default

デフォルトの設定内容。

DBの設定は(1)development, (2)test, (3)productionの3つが用意される。それぞれの共通部がこのdefaultになる。

default: &default
  adapter: postgresql
  encoding: unicode
  # For details on connection pooling, see Rails configuration guide
  # https://guides.rubyonrails.org/configuring.html#database-pooling
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>

default: &default
&はアンカーとよび、&アンカー名で指定して*アンカー名で呼び出すことができる。

&defaultの配下(adapter~)の塊を*defaultで呼び出せるようになる。

adapter: DBの種類
指定したDB名が記載される。デフォルトはsqlite3

pool: 数値
DBに接続するコネクションプールの上限数。
コネクションプールとは、DBの接続情報を維持しておく機能。(プールは人工的に作った表面上の小さな水たまり。DBの表面情に作ったコネクション用のパスといった感じ)

<%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
rubyの記述。環境変数の中にRAILS_MAX_THREADSがあればその値を適用し、ない場合は5にする。


3. development

開発環境用のDB設定。

development:
  <<: *default
  database: test-app_development

先ほどの&アンカーで指定した内容を呼び出している。以下と同じになる。

development:
  adapter: postgresql
  encoding: unicode
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  database: test-app_development

database: DB名
defaultの設定にDB名アプリ名_developmentを追加している。

4. development, test, porductionの違い

DBの構成としてtestとproductionもあるが、中身はほぼ同じ。

共通部
  adapter: postgresql
  encoding: unicode
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>

それぞれの違いはdatabase名の末尾。productionの場合はusernameとpasswordが追加される。

development
development:
  database: test-app_development
test
test:
  database: test-app_test
production
production:
  database: test_app_production
  username: test_app
  password: <%= ENV['TEST-APP_DATABASE_PASSWORD'] %>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】Bootstrapの導入の仕方

はじめに

この記事ではrailsBootstrapの導入の仕方を説明します。bootstrapを使うためにはjQueryを入れる必要があるのでまだjQueryを入れていない人ははじめに以下の記事からjqueryを導入してください

Bootstrapの導入

まず初めに使うgemを記入します

Gemfile
gem 'bootstrap'

と同時にbundle installを行います

ターミナル
$ bundle install

次にapplication.cssファイルapplication.scssに変更してください

app/assets/stylesheets/application.css
application.css → application.scss

そしたらapplication.scssに必要なものを記入していきます

app/assets/stylesheets/application.scss
/*
 * This is a manifest file that'll be compiled into application.css, which will include all the files
 * listed below.
 *
 * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's
 * vendor/assets/stylesheets directory can be referenced here using a relative path.
 *
 * You're free to add application-wide styles to this file and they'll appear at the bottom of the
 * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
 * files in this directory. Styles in this file should be added after the last require_* statement.
 * It is generally better to create a new file per style scope.
 *
 *= require_tree .
 *= require_self
 */
 /*
*/
// ↓追加
@import "bootstrap";

scssファイルではインポートに@importを使うので注意

最後にapplication.jsを変更して終わりです

app/assets/javascripts/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.

import Rails from "@rails/ujs"
import Turbolinks from "turbolinks"
import * as ActiveStorage from "@rails/activestorage"
import "channels"

Rails.start()
Turbolinks.start()
ActiveStorage.start()
// ↓追加
//=require bootstrap
require('jquery')

設定は終わりです。これでbootstrapが使えるようになっていると思います
アプリを再起動して実際にできているか確認してみてください

参考資料

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

[Rails] ActiveRecord::ValueTooLong (Mysql2::Error: Data too long for column 'content' at row 1):

なぜこのエラーが出たか

データ型の文字制限を超えた情報をDBに格納しようとしたから。

解決方法

データ型を変えることにした

    - t.string "content"
    + t.text "content"

migrateした後は、DBにしっかり格納された。

補足:
limitオプションでも条件を変えることができる。

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

Railsアプリのherokuデプロイ

heroku CLIインストール(初回のみ)

% brew tap heroku/brew && brew install heroku

ログイン

heroku login --interactive
 => Email:
 => Password:

アプリケーション作成

heroku create アプリ名

ClearDBアドオン

% heroku addons:add cleardb

% heroku_cleardb=`heroku config:get CLEARDB_DATABASE_URL`

% heroku config:set DATABASE_URL=mysql2${heroku_cleardb:5}

環境変数の設定

% heroku config:set RAILS_MASTER_KEY=`cat config/master.key`

gitをherokuにpush

git push heroku main

マイグレーション

heroku run rails db:migrate

ログ確認

heroku logs --tail --app <<アプリケーション名>>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】jQueryを使えるようにする(Webpacker)

はじめに

この記事ではRailsでjqueryを使うための設定を説明します。
この記事の最後では実際にjqueryが使えているかどうかについて確認する仕方についても載せています

jQueryを導入する

まずは端末で以下のコマンドを打ちます

ターミナル
yarn add jquery

次にenvironment.jsの編集を行います

config/webpack/environment.js
const { environment } = require('@rails/webpacker')
// ↓ 追加
const webpack = require('webpack')
environment.plugins.prepend('Provide',
    new webpack.ProvidePlugin({
        $: 'jquery/src/jquery',
        jQuery: 'jquery/src/jquery'
    })
)
//ここまで

module.exports = environment

次にapplication.jsの編集を行います

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.

import Rails from "@rails/ujs"
import Turbolinks from "turbolinks"
import * as ActiveStorage from "@rails/activestorage"
import "channels"

Rails.start()
Turbolinks.start()
ActiveStorage.start()
// ↓追加
require('jquery')

ここまででjqueryのインストールは完了です
最後にちゃんと設定できているか確認します

jQueryのバージョン確認

まずはアプリを立ち上げます

ターミナル
$ rails s

※ここで注意なのですがすでにアプリを立ち上げている人は一度接続を切ってもう一度立ち上げてください

次にデベロッパーツールを開きコンソールでconsole.log($.fn.jquery)と打ちます

Q3k1N0OIMl7c4HR1617410622_1617410634.png

そしたら右下にjqueryのバージョンが出てくるとおもいますのでこれが出てきたらちゃんと設定できています
お疲れ様でした。

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

Railsでハッシュタグ機能を実装してみた(gemなし) 後半

概要

前半ではRouteの作成とハッシュタグ別のViewを作成する手前まで書きましたが、その続きを書いています。
具体的には、

  • Routeの作成
  • ハッシュタグコントローラーを作成
  • ハッシュタグ別の投稿一覧を表示するView

上記の実装を後半でやっていきます。
まだ前半を見てらっしゃらない方は、下記のリンクからご覧ください。
https://qiita.com/Prog_taro/items/9dc5fe39eb6149acabd4

Routeを作成

config/routes.rb
get '/post/hashtag/:label_name', to: 'hashtags#index'

あまり日本語でURLを作るべきではないと思うのですが、今回はわかりやすくするためにタグの名前でURLを作成する事にしました。

ハッシュタグコントローラーを作成

$ touch app/controllers/hashtags_controller.rb

もちろん rails g コマンドで作成しても良いですが、今回は素直に作成しました。

ハッシュタグコントローラーを編集

app/controllers/hashtags_controller.rb
class HashtagsController < ApplicationController
  before_action :authenticate_user!
  def index
    @label = params[:label_name]
    hashtag = Hashtag.find_by(label: @label)
    if hashtag.nil?
      redirect_to root_path, alert: "##{@label}のタグがついた投稿は存在しません"
    else
      @posts = hashtag.posts.includes(:photos, :user, :likes, :comments).recent
    end
  end
end

上記のコードを説明させていただきます。

app/controllers/hashtags_controller.rb
before_action :authenticate_user!

これはログインしているユーザーしかこのページを見られないようにするためのdeviseを入れないと使えないメソッドです。
僕の場合、入れているので使用することができます。
アプリの設計上、ログインしているユーザーにしか見れないようにしたかったので導入しました。

app/controllers/hashtags_controller.rb
@label = params[:label_name]

クリックしたハッシュタグをビュー側にも表示させたいという意図があったためインスタンス変数にパラメータで渡ってきた:label_nameを入れています。

app/controllers/hashtags_controller.rb
hashtag = Hashtag.find_by(label: @label)

このコードはハッシュタグの名前がパラメータで渡ってきた名前と同一のもの、つまり、DBに登録されているハッシュタグの中から該当のハッシュタグを取り出しているコードです。

例えばパラメータで "こんにちは" というものが送られてきたら、DBに登録されているハッシュタグから "こんにちは" と同一のものを取り出すということです。

なぜ同一のものを取り出せるのかというと、前半部分を書いた記事でハッシュタグはuniqにしているからです。

app/controllers/hashtags_controller.rb
if hashtag.nil?
  redirect_to root_path, alert: "##{@label}のタグがついた投稿は存在しません"
else
  @posts = hashtag.posts.includes(:photos, :user, :likes, :comments).recent
end

この部分は先ほど書いたfind_byで該当ハッシュタグがない状態、つまりNilのことを許容しているのですが、Nilだった場合にエラーにならないよう書いている部分です。
find_byがNilを許容していることについては下記をご覧ください。
https://railsdoc.com/page/find_by

else の中身について説明します。

app/controllers/hashtags_controller.rb
@posts = hashtag.posts.includes(:photos, :user, :likes, :comments).recent

後ほどViewでも使う予定なのでインスタンス変数に入れています。
hashtag.postsとするだけでも該当ハッシュタグがついた投稿一覧が出るのですが、N+1問題が発生しているので .includs をつけています。

N+1問題についてものすごく簡潔に説明すると、DBにアクセスする回数が多くなれば多くなるほど接続に時間がかかってパフォーマンスが落ちる!という感じでしょうか。
(僕も初心者なので詳しくはしっかりと調べてみることをお勧めします)
もっと詳しく知りたい方は良い記事がありますので、下記を参照してください。
https://qiita.com/TsubasaTakagi/items/8c3f4317ad917924b860

一番最後の .recent は .order をscopeにしてまとめたものです。

Postモデルに追加

app/models/post.rb
scope :recent, -> { order(created_at: :desc) }

基本的にorderはスコープにしてまとめた方が良さそうですね。

Viewを作成

いよいよハッシュタグ別のViewを作成するんですが、僕はもともとあった投稿一覧画面をそのまま引用しました。
特別にそのページだけ仕様を変えたい場合は変えるべきですが、僕の場合はそのまま利用したのでここでの詳しいご紹介は割愛させていただこうと思います。
皆さんも特別何か変更を加えるつもりがない場合は、使用している変数などを変更した上で、再利用しても良いと思います。

変更した場所のみ簡潔にまとめさせていただこうと思います。

app/views/hashtags/index.html.erb
<h2 class="text-center text-secondary mt-5"><%= "#" + @label %>のタグを含む投稿一覧</h2>

Bootstrapを使用しているのでclassを付与しています。
先ほどインスタンス変数に入れた該当ハッシュタグの名前を表示させました。
こうする事によって、ユーザー目線でよりわかりやすくなるのではという意図です。

app/views/hashtags/index.html.erb
<% @posts.each do |post| %>

....中身は省略....

<% end %>

投稿知覧を表示するためにeachを使っていたのですが、元の変数を先ほどインスタンス変数に入れた該当タグの全投稿に変えました。

僕が変更したのはこれぐらいです...笑
ユーザー目線で考えると、チラチラ画面が変わってたら目が疲れるかな?という意図でわざとあまり変更は加えませんでした。

最後に...

初心者なりに書いて見ました!参考になった方が1人でもいらっしゃれば幸せです。
アウトプットにもなりましたし、またテーマを思いついたら書いてみようと思います。

間違っている部分などがありましたら、ご指摘いただければ加筆修正させていただきますのでお願いします!

ここまで読んでいただいて本当にありがとうございました。

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

【cloud9】Railsチュートリアルやってたら、cloud9で容量足りなくなって更新できなくなったので容量増やした【Rails】

症状

Railsチュートリアルをやっていたら、下記エラーが表示されてファイルが更新できなくなってしまいました。

Failed to write to '更新対象のファイルの中身'. ENOSPC: no space left on device, write .

翻訳すると、「書き込みに失敗しました。デバイスにスペースが残っていません」
容量が足りなくて、ファイルの更新ができなくっていると推測。

前半で作った「hello_app」「toy_app 」は既に削除していたので、EBS ボリューム(Amazon Elastic Block Storage)を増やしていこうと考えました。
念のため、df -h コマンドで、現在の容量をチェックし、100%になっていることを確認しました。

df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/xvda1      9.7G  9.7G     0 100% /

解決策

Railsチュートリアルの2. EBS ボリュームを増やす方法を確認しながらEBSボリュームを増やして、ファイルを更新できるようにしました。

Railsチュートリアルの手順を下記に引用し、実際にやっていきます。

1.Amazon EC2 コンソールを開きます。
2.「ボリューム」を選択し、変更するボリュームを選択します。(複数あって分からない場合は、「インスタンス」の「実行中のインスタンス」の中からaws-cloud9から始まる Name のインスタンス ID をコピーし、ボリューム内で検索するとよいでしょう。)
3.上部にある「アクション」ボタンから「ボリュームの変更」を選択し、サイズを AWS が定める最大無料枠に設定し、変更します。(執筆時点では 30 でしたが、念のため確認しておくことをオススメします)
4.「インスタンス」にいき、該当のインスタンスを選択後、画面上部にある「アクション」ボタンから「インスタンスの状態」→「再起動(停止中なら開始)」をします。
5「Cloud9」に戻り、ターミナルからボリュームの拡張をします。現在のインスタンスに割り当てられているブロックデバイスの情報を確認するには、lsblkコマンドで表示します。ルートボリュームである/dev/xvdaは拡張されていますが、/dev/xvda1はまだ元のままです。

1から3でコンソールを対象のボリュームを選択し、アクションを押したの下記です。
image.png

キャプチャ.JPG

4.「インスタンス」に行き、街頭のインスタンスを再起動しました。
キャプチャ13.JPG

lsblk

xvda    202:0    0   30G  0 disk 
└─xvda1 202:1    0   10G  0 part /

5のコマンドを打とうとすると、「容量が足りないよ」と怒られてしまいました。
容量が足りないから増やそうとしているのに、その命令が出せないというパラドックス状態に。。。

 sudo resize2fs /dev/xvda
sudo: unable to resolve host ip-ホスト名: Resource temporarily unavailable
resize2fs 1.44.1 (24-Mar-2018)
resize2fs: Device or resource busy while trying to open /dev/xvda
Couldn't find valid filesystem superblock.

詰んだと思って放置して、後日確認したらボリュームが追加されていました。

ターミナル
df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/xvda1       30G  9.2G   20G  32% /

おそらくですが、ボリュームが変更ほやほやだったため、状態が黄色状態でうまくボリュームの変更が未完了できていなかったようです。
とりあえず、cloud9でボリューム追加できました!

参考

困ったときのヒント集-Railsチュートリアル
https://railstutorial.jp/help#volume-up-aws-ebs

No space left on deviceで、Volume増やしたけど、growpartコマンドすら実行できない状況を解決(docker containerを削除した)
https://qiita.com/gymnstcs/items/f535bdf8f85513580577

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

[Rails]ActiveStorageで画像投稿機能を作成しよう!

前提条件

railsに関しての基礎的な知識があることのみです

事前準備

今回の画像投稿機能を作成するにあたり以下のものを準備します。
まずはそのツールに関しての説明をします
・ActiveStorage
・ImageMagick
・MiniMagick
・ImageProcessing

ActiveStorageとは

ActiveStorageとは「gem」のことです
インストールすることで、画像やファイルのアップロードを簡単にするメソッドを使用できたり、
画像を保存するテーブルを簡単に作成できるようにします。

ImageMagic

ImageMagicはgemではなく、ソフトウェアです。
画像の作成、サイズ変更、保存形式の変更を行います。
Homebrewからインストールします。

ちなみに、こいつ単体ではRails内で使用できません。
使用するためにはMinMagicが必要です。

MiniMagick

こいつは、ImageMagickがRails内で使用できるようにするためのgemです。
ただ、こいつも完璧ではないんですよね、、、↓

ImageProcessing

MiniMagickでは提供できない画像サイズを調整する機能を持ちます

実際にインストールをして行こう

ここからはただただ無心で進めましょう

①ImageMagickのインストール

bundle install imagemagick

②MinMagickとImageProcessingのインストール

Gemfile
gem 'mini_magick'
gem 'image_processing', '~> 1.2'

もちろん、記載するだけでなく
ターミナルでこれを打たないと意味ないですよ!!

bundle install

③ActiveStorageのインストール
※以下は一旦rails sでサーバは立ち上げた後に行ってください。

% rails active_storage:install
% rails db:migrate

DBに、「active_storage_attachments」と「active_storage_bolbs」が作成されていれば準備完了です
スクリーンショット 2021-04-02 23.54.55.png
(SequelProというツールでDBはみれますよ!!!調べてみてください)

実装していこう

ようやく準備が終了!!
ここからが本番。

まずは今回、Messageモデルに対して画像を保存させたいという前提で話を進めます。

MessagesテーブルとActiveStorageテーブルで管理された画像ファイルを1対1でアソシエーションします。(つまり1メッセージにつき1枚だけ添付可能とする)

models/message.rb
class Message < ApplicationRecord
  has_one_attached :image #ここはファイル名記載、なんでもOK!
end

:imageはファイル名なので:photoでもいいし、:pictureでもOKです

これでテーブル同士はつながりました。

ただし、画像を保持するカラムはMessagesテーブルにはないので(だからこそ、上記でアソシエーションした)、imageという名前でアクセスできるようになった画像ファイルの保存を許可する実装を行うために、ストロングパラメータにmergeしてあげましょう。

messages_controller.rb
 private
  def message_params
    params.require(:message).permit(:content, :image).merge(user_id: current_user.id)
  end

これでよし!!!

あとは画像を表示させるだけ

あとは、viewファイルで表示すれば完成です!!

たとえば、こんな感じです

image.html.erb
 <%= image_tag message.image, class: 'image_message' %>

ちなみ、このままでは画像なしの場合にエラーが発生しますので
attached?メソッドを使用するといいです

image.html.erb
<%= image_tag message.image, class: 'image_<%= image_tag message.image, class: 'message-image' if message.image.attached? %' if message.image.attached? %>

さて、ここまでで実際に投稿機能を実装してテスト投稿してみた方は思ったでしょう、、、、
サイズがバラバラじゃねーか!!!と、、、、.

そんなときは、variantメソッドで高さと幅を決めましょう!

モデル.ファイル名.variant(resize: '幅x高さ')

こんな感じで使ってみましょう↓

image.html.erb
<%= image_tag message.image.variant(resize: '500x500'), class: 'message-image' if message.image.attached? %>

終わりに

初めて使う方は難しく感じるかもしれませんが、触っているうちに慣れてきて便利さに気づくかと思いますので是非当記事を参考にしながら練習してみてください。

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