20200524のRailsに関する記事は25件です。

Rails6.0でselectboxの複数選択をおしゃれにするJavaScriptライブラリ「select2」の導入方法

はじめに

皆様、こんにちは!
佐久間まゆちゃんのプロデューサーの@hiroki_tanakaです。

先日、Rails6.0系でselectboxの複数選択をおしゃれにするプラグインのselect2を導入することがありました。
その際にRails5系までの導入方法との違いに少しハマったので、調べたことをまとめました。

利用環境

  • Ruby 2.6.6
  • Rails 6.0.2

select2とは

select2とはHTMLのselectboxのデザインをおしゃれにするJavaScriptのライブラリです。
公式サイトはこちらです。→select2
単一選択のselectboxのUIだけでなく、複数選択のselectboxも簡単に実装する事ができるプラグインです。

公式サイト上のサンプル

  • select2導入前
    image.png

  • select2導入後の複数選択プルダウン
    image.png

Rails6.0での導入方法

Rails5系でのselect2の導入はGemを使用しての導入となっていましたが、Rails6.0からはGemではなくWebpacker使用するようになりました。
1つずつ手順を紹介したいと思います。

※Rails5でselect2の導入は下記のページが非常に詳細に説明しています。
【Rails5】Select2で複数選択可能なセレクトボックスを作る

1. yarnでselect2に必要なライブラリ導入

下記のコマンドを実行して、Railsアプリケーションにselect2を導入します。
この時、select2だけではなくselect2の導入に必要なjQuery(及びpopper.js)とselect2のUI部分に当たるbootstrapも併せて導入します。

$ yarn add jquery
$ yarn add popper.js
$ yarn add bootstrap
$ yarn add select2

2. Rails上でjQuery・popper.jsを使用できるように設定

Railsアプリケーションのwebpack/environment.jsにjQueryをRailsのどのファイルからも呼び出せるように設定します。

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

// jQueryとBootstapのJSを使えるように
const webpack = require('webpack')
environment.plugins.prepend(
    'Provide',
    new webpack.ProvidePlugin({
        $: 'jquery',
        jQuery: 'jquery',
        Popper: 'popper.js'
    })
)
module.exports = environment

また、packs/application.jsのマニュフェストにJQueryを追加します。

app/javascript/packs/application.js
require("jquery")

3. Rails上でbootstrapを使用できるように設定。

下記の2つの設定を行い、Railsアプリケーションでbootstrapを使用できるように設定します。

app/javascript/packs/application.js
import 'bootstrap';
import '../stylesheets/application';
app/javascript/stylesheets/application.scss
@import '~bootstrap/scss/bootstrap';

4. erbファイルでwebpackerを使用するように設定。

Railsアプリケーションの全てのViewファイルでwebpackerに導入したbootstrap・jQueryが使用できるように大元のlayouts/application.html.erbに設定します。

app/views/layouts/application.html.erb
<head>
<%= stylesheet_pack_tag "application", media: "all" %>
<%= javascript_pack_tag 'application' %>
</head>

5. selectboxをerb上に定義し、select2を使用するようにJSファイルに記載。

アプリケーションのerb上に複数選択を行うselectboxを定義します。
この時、select_tagはmultiple: trueとoption設定すれば、複数選択可能なselectboxとなります。

そして、該当のselectboxがselect2を使用するようにerbファイルに対応するJSファイルに記載します。

app/views/test.html.erb
<%= javascript_pack_tag 'test' %>
<%= select_tag('animal', options_for_select([['いぬ', 'dog'], ['ねこ', 'cat'], ['とり', 'bird'], ['うし', 'cow'], ['へび', 'snake']]), class: "form-control", multiple: true) %>
app/javascript/packs/test.js
$(function () {
    $('#animal').select2();
});

6. 完成!!

image.png

おまけ:select2のoption利用

select2には様々なoptionが用意されています。→select2 Options
これらのoptionはjQueryで設定することが可能です。
下記はoption設定の一例です。

app/javascript/packs/test.js
$(function () {
    $('#animal').select2({
        width: 'resolve' // 幅をページサイズに併せて動的に変更する。
        theme: "classic" // クラシックUIに変更する。
        debug: true // ブラウザのコンソールにデバッグメッセージを出力する。
    });
});

おわりに

yarnを使用することでselect2の導入が更に簡単になったように感じます。
ただ、select2の内部挙動に関してはわからないことが多いので理解を深めたいです。

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

ActiveModel::Serializerのテストでつまづいたこと

はじめに

ActiveModel::SerializerのRspecでテストの書き方の例を挙げました。
ですが、他のSerializerのテストを書く時につまづいたことがあるので、投稿します。

ソースコード

今回の例は、ArticleとCategoryが多対多の関係にあり、article_category.rbという中間モデルを持っているとします。

article.rb
class Article < ApplicationRecord
  has_many :article_categories
  has_many :categories, through: :article_categories
end
article_serializer.rb
class ArticleSerializer < ActiveModel::Serializer
  attributes :id, :title
  has_many :categories
end

このSerializerのテストを書くとこんな感じ

article_serializer_spec.rb
require 'rails_helper'

RSpec.describe ArticleSerializer, type: :serializer do
  context "新たに記事が作成された時" do
    let(:article) { create(:article) }
    let(:category) { create(:category) }
    let(:article_category) do
      create(:article_category, category: category, article: article)
    end

    it "シリアライズされたJSONが作成されること" do
      serializer = ArticleSerializer.new(article)
      expect(serializer.to_json).to eq(article.to_json(:only => [:id, :title], :include => { :category })
    end
  end
end

テスト結果

テストしてみると、返却されたJSONにhas_many関係のcategoryが含まれておらず、空のままでした。なぜ、、、

解決方法

このテストの書き方が悪かったようで、このように書いたら通りました。

article_serializer_spec.rb
require 'rails_helper'

RSpec.describe ArticleSerializer, type: :serializer do
  context "新たに記事が作成された時" do
    let!(:article) { create(:article) }
    let!(:category) { create(:category) }
    let!(:article_category) do
      create(:article_category, category: category, article: article)
    end

    it "シリアライズされたJSONが作成されること" do
      serializer = ArticleSerializer.new(article)
      expect(serializer.to_json).to eq(article.to_json(:only => [:id, :title], :include => { :category })
    end
  end
end

変更点は、letlet!としたところです。
letのままだとexampleの中で作られるオブジェクトは、articleだけです。
なぜかというと、letではそのオブジェクトがexampleの中に出てくるときにのみオブジェクトが作成されるからです。

というわけで、このような例ではlet!を使うといいですね!

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

【Rails】モデルの使い方がイマイチわからない…(クラスメソッドとか意味不m…)

経緯

現在、とあるプログラミングスクールに通っているのですが、検索機能(検索窓)を実装する際に、処理をモデルとコントローラーを使い分けるように言われました。
えー… 全部コントローラーでいいじゃん…(もちろん、今では積極的に分けて使用していますよ!)

・モデルからデータを取得したり、保存したり単純な処理のみ記載
・モデル取得した値に複雑な処理を行うものを記載
というイメージで使い分けています。

ただ、何故モデルで設定した『処理のカタマリ』をコントローラーで使えるのか理解できなかったので使いたくなかった、、いや使えなかったんですよね。
(この記事は検索機能の解説をするための記事ではありません。あくまでモデルの使い方について私の頭の整理です。)

検索機能の実装

models/tweet.rb(モデル)
class Tweet < ApplicationRecord
  validates :text, presence: true
  belongs_to :user
  has_many :comments

  def self.search(search)
    return Tweet.all unless search
    Tweet.where('text LIKE(?)', "%#{search}%")
  end

end

※2〜4行目は必要のない記載ですが、あえて「モデルに書いてるよ」ってわかるように残してます。
また、見やすいように謎の改行が入っておりますがご容赦ください。

controllers/tweets_controller.rb(コントローラー)
class TweetsController < ApplicationController

  def search
    @tweets = Tweet.search(params[:keyword])
  end

end


理解不明ポイント

①コントローラーの「search」メソットって何?(リファレンスに載ってないぞ??)

リファレンスになんぞ載っていいる訳ないのです。
なぜなら「モデルで自作したメッソド」だから!!

②モデルの「self」ってなに?(ググると、当たり前のように「クラスメソッド」って言われますが…だから何??)

  • ここで詳しい説明はしませんが、こいつにはクラス名が代入されます。 (代入という表現はわかりやすくするために使用しています)
  • tweet.rb(tweetモデル)の一行目を見てください。クラス名、なんだかわかりましたよね?
  • つまり、「self.search(search)」は「「Tweet.search(search)」なんです。(どっかで見たような、)

③何故モデルで設定した『処理のカタマリ』をコントローラーで使えるの?(いよいよ本題です)

なんとなく分かってきましたかね??

  • コントローラーで使用している「Tweet.search(params[:keyword])」はモデルで自作したメソッド「self.search(search)」と同じなんです。

メソッドの正体

我々がよく使っている「findメソッド」や「includeメッソド」等の様々なメソッドって実は、
今回「searchメソッド」を自作したようにRailsのActiveRecordが作ってくれているんです!!

各モデルがActiveRecordを継承しているから、コントローラーでメソッドを使えているんですね!
(厳密には class Tweet < ApplicationRecord < ActiveRecord::Base)
tweet.rb(tweetモデル)の一行目を見れば記載がありますね。

アイツ

さて、長くなってきましたが一つ解決してないヤツがいますよね。
そう、結局「self = クラスメソッド」って何だったのか。

クラスメソッドは読んで字の如く、「クラス」に対して使用できるメソッドです。
「クラス」って何だったか思い出せますか??
わからない方はtweet.rb(tweetモデル)の一行目を見てみてください。

私もこれ以上はまだ理解できてません!!笑

謝辞

ちょっとわかりにくい説明だったかもしれませんが、プログラミング歴2ヶ月なので許してください。
(自分の頭は割と整理できました。)
ここまで長々と書かせていただきましが、最後まで読んでいただきありがとうございます。

もし、解釈が間違っている場合は、教えていただけるととても嬉しいです。

どんどはれ。

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

[rails]よく使うバリデーションまとめ

バリデーションの日本語にするには下記参照#

deviseを日本語表記にする。
https://qiita.com/ryuuuuuuuuuu/items/48dec280cf8925968c65

deviseを日本語化する
https://qiita.com/you8/items/921e0dd1210eb0d158df

Railsのバリデーションエラーのメッセージの日本語化
https://qiita.com/Ushinji/items/242bfba84df7a5a67d5b

空でないこと

model
validates :title, presence: true

ちなみに、マイグレーションファイルに記載する下記の

null: false

も同じく空でないこと、という意味ですが
それぞれDB側への制限と、アプリケーション側への制限になるので
両方ともかけましょう!

重複禁止

model
validates :email, uniqueness: true

長さ

model
validates :title,    length: { minimum: 1 }       # 「1文字以上」
validates :title,    length: { maximum: 75 }      # 「75文字以下」
validates :title,    length: { in: 1..75 }        # 「1文字以上75文字以下」
validates :password, length: { is: 8 }            # 「8文字のみ」

正規表現についての参考リンク

半角、全角縛りや@とドメインを含むなどの細かい条件のために必要です。

正規表現を使い際に注意すること
https://qiita.com/kokorinosoba/items/78811d7e2b6bc424b1b1

正規表現10選!!とにかくよく使うパターンをまとめました
https://complesso.jp/9916/

追加したい
[Rails]「jQueryValidationプラグイン」を使用してフォームのバリデーションを実装
https://qiita.com/NT90957869/items/84ca64d145f8ef9c4fdd

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

忘れがちなrubyの基礎知識を復習

はじめに

改めてrubyの基本的な記法を復習するための記事になります。

・あるオブジェクトを文字列に変換するto_sメソッド

# 文字列→文字列
'1'.to_s   # => "1"

# 数値→文字列
1.to_s     # => "1"

# nil→空白の文字列
nil.to_s   # => ""

# 真偽値true→文字列の"true"
true.to_s   # => "true"

# 真偽値のfalse→文字列の"false"
false.to_s   # => "false"

メソッドの呼び出し方

# 通常の書き方
オブジェクト.メソッド(引数1, 引数2, 引数3)
# カッコを省略しても良い
オブジェクト.メソッド 引数1, 引数2, 引数3
# 引数がない場合
オブジェクト.メソッド

変数名の作り方

# 変数名はスネークケースが望ましい
first_name = user.first_name

# キャメルケースは慣習的に使用しない
firsfName = user.first_name

# 数字から始まる変数はエラーになり使用できない
2_discount_price = 200

文字列について

シングルクオート('')を使用しても、ダブルクオートを使用しても("")文字列を表現することができる。
使い分けとしては、基本的にはシングルクオートを使い、式展開する場合はダブルクオートを使用する

# 文字列
'これは文字列'
"これは文字列"

# 式展開する場合
i = '文字列'
"これは#{i}"  # => これは文字列

論理演算子||と&&

# &&はANDの論理演算
# 条件1も条件2も真であれば真、それ以外は偽となる
条件1 && 条件2

t1 = true
t2 = true
f1 = false
t1 && t2      # => true
t1 && f1      # => false

||はORの論理演算

## 条件1も条件2のいずれかが真であれば真、両方偽であれば偽となる
条件1 || 条件2

t1 = true
t2 = true
f1 = false
f2 = false
t1 || t2      # => true
t1 || f1      # => true
f1 || f2      # => false

?で終わるメソッド

?で終わるメソッドは慣習的に真偽値を返すメソッドになります。

# 空文字列であればtrue、文字が入っていればfalseを返すempty?メソッド
''.empty?           # => true
'あいうえお'.empty?   # => false
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】fields_forが表示されない

今回は、「fields_for」で「file_field」を使用しようとしたところ、ビューに反映されずに苦戦したので、備忘録として解決した方法を記載します。
同じ悩みを抱えた方の一助になると幸いです。

※この記事ではfields_for とaccepts_nested_attributes_for を使ったフォーム作成手順を解説するものではありません。

今回登場するモデル

・(親)postモデル
・(子)imageモデル

postモデルとimageモデルaccepts_nested_attributes_forでアソシエーションしております。

想定

ツイッターやFBのようなSNSを作成。
「form_for」を用いて投稿フォームを作成するところです。

文章 →postモデル
写真 →imageモデル
に保存したく、以下のようにビューを作成しました。

間違えたコード

(わかりやすいように関係箇所のみ抜粋してます)

haml
.form__contents
  = form_for @post, id: "new_post" do |f|
    .title
      = f.text_field :title
    .text
      = f.text_area :text
    .image
      = f.fields_for :images do |i|
        = i.file_field :image
    = f.submit "投稿!"

よし、コーディング完了!!いざビューへ!!
…あれ、、「= f.fields_for :images do |i| 」以下が反映されてないぞ…
しかもエラーも出てないから何が悪いのかわからない…調べた通りやったのに…

上手く行ったコード

haml
.form__contents
  = form_for @post, id: "new_post" do |f|
    .title
      = f.text_field :title
    .text
      = f.text_area :text
    .image
      = f.fields_for :images, @post.images.build do |i|
        = i.file_field :image
    = f.submit "投稿!"

まとめ

私はてっきり「fields_for」では保存したいモデルを書けば「file_field」で記載したカラムに保存してもらえるとばかり思っていたのですが、

「fields_for」の第二引数に子モデルのインスタンスも渡してあげないとダメみたいでした。

なるほど…たしかに「form_for」でもインスタンス渡してあげてるんだから当たり前か。
(そもそも images.build インスタンス作れるって初めて知りました!)

どんどはれ。

参考させていただいたサイト

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

【環境構築 Mac】Ruby on Rails (+Webpackerでエラーの対処)

初めに

Ruby on Railsの環境構築を行いましたので、記録します。

【構築環境】
・Rails6
・Ruby 2.6.3

【マシンスペック】
・macOS Catalina
・バージョン 10.15.3
・iMac(retina 4K, 21.5-inch,2019)
・プロセッサ 3 GHz 6コアIntel Core i5
・メモリ 8GB

【使用エディター】
VScode
(https://azure.microsoft.com/ja-jp/products/visual-studio-code/)

構築手順

Command Line Toolsのインストール

こちらでは、AppleIdが必要になります。
Id・パスワードを忘れている場合は事前に準備してください。

①Appleのdeveloperアカウントページにログイン
https://developer.apple.com/account/#/welcome

②See more downloadsからダウンロードリストページへ
https://developer.apple.com/download/more/

→OSに対応したCommand Line Toolsをダウンロードしてください。

Homebrewのインストール

①Homebrewの公式サイトへ行き、記載されているコマンドを「ターミナル」に貼り付けてください。
(Homebrewの公式サイト)https://brew.sh/index_ja

※私の場合は以下のコマンドでした。

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"

②Homebrewのインストールの確認
インストールが無事されたか不安なので、確認をします。

brew -v

※私の場合は以下のコマンドでした。

Homebrew 2.2.17
Homebrew/homebrew-core (git revision 572fc; last commit 2020-05-24)

rbenvのインストール

①rubyのバージョン管理ができるようインストールします。

brew install rbenv ruby-build

②インストールが完了したら、以下のコマンドで確認してみてください。

rbenv -v

※私の場合は以下のコマンドでした。

rbenv 1.1.2

Rubyのインストール

ここからは、Rubyをインストールしましょう。
※Rubyについては、使用者によりは、もうインストールされているかもしれません。

①インストールされているか確認します。

ruby -v

※私の場合は以下のコマンドでした。

ruby 2.6.3p62 (2019-04-16 revision 67580) [universal.x86_64-darwin19]

もうインストールしてたいましたが、もしインストールされていない様でしたら、以下でインストールしてください。

②インストールされていない場合
以下のコマンドで、インストール可能なRubyのバージョンを確認します。

rbenv install --list

確認できたら、以下を実行、
数字は「rbenv install --list」で実行されたバージョンを指定します

rbenv install ●●●●
rbenv global ●●●●
rbenv rehash
ruby -v

バージョンがインストールされているか確認のため「ruby -v」を行いました。

Bundlerのインストール

①以下のコマンドを実行して、インストールしてください。

gem install bundler

②確認します。

bundle -v

my SQLのインストール

①my SQLをインストールして起動します。

brew install mysql

②my SQLを確認してください

mysql.server start

Railsのインストール

①ディレクトリを制作しましょう
●は、任意のファイル名で記入してください。

mkdir ~/●●●●●●●

②制作したフォルダーに移動

cd ~/workspace

③Gemfileを作成する

bundle init

④Gemfileの中を編集・コメント解除
「mkdir ~/●●●●●●●」で制作したフォルダには「Gemfile」があります。
エディターソフトで、それを起動してください。

ファイルの中には# gem "rails"がメモ表記になっているので、コメント解除をしてください。

⑤Railsのインストール

bundle install --path=vendor/bundle

⑥Railsがインストールか確認

bundle exec rails -v

※私の場合は以下のコマンドでした。

Rails 6.0.3.1

Railsでテストファイルを作成

①制作したいファイル先を指定

cd desktop
※私の場合はデスクトップ上に制作しました
また、こちらの制作時はRailsのインストール先のパスが異なります。
私は、新しくvscodeで新しくターミナルを制作していますのでご注意ください。

②Railsで新規ファイルを制作
●は任意のファイル名です。

rails new ●●●●●

しかし

私はここでエラーが発生!!
原因は「Webpackerでエラー」でした。
以下の作業を行います。

Webpackerのインストール

①yarnがインストール

brew install yarn

②下記のコマンドを実行してください。

rails webpacker:install

でも「yarn」がインストールされていない!
と言われているので下記のコマンドを実行します。

Railsの起動

①ブラウザを立ち上げるコマンドを実行する
以下のコマンドを実行してください

rails s

②ローカルサーバを起動

http://localhost:3000

→無事に起動しました。
よかった!

参考記事

Ruby初学者のRuby On Rails 環境構築【Mac】
Homebrewのインストール
Rails6 Webpackerでエラーが出た

参考記事様には、とても助かりました。
ありがとうございます。

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

【Rails】ぼっち演算子について

ぼっち演算子「&.」

レシーバであるオブジェクトが
・nilの場合nilを返す
・nilでない場合、その後の処理を行う

書き方

ぼっち演算子の使い方は
「オブジェクト&.メソッド」
になります。

sessions_controller.rbを例に使い所をみていきます。

app/controller/sessons_controller.rb
class SessionsController < ApplicationController

  def new; end

  def create
    user = User.find_by(email: params[:session][:email].downcase)
    if user&.authenticate(params[:session][:password])
      log_in user
      redirect_to user
    else
      flash.now[:danger] = 'Invalid email/password combination'
      render :new:
    end
  end

  def destroy
    log_out
    redirect_to root_url
  end
end

railsチュートリアルでは以下のように書かれています。

app/controller/sessons_controller.rb
# ...
def create
   user = User.find_by(email: params[:session][:email].downcase)
   if user && user.authenticate(params[:session][:password])
# ...

Railsチュートリアルの書き方はuserが存在する場合、&&以降の処理を実行するという流れです。userが存在しなけれはnilが返されそれ以降の処理は実行されません。
どちらにするかは好みかと思われますが、ぼっち演算子を使った方が記述が簡単かもしれませんね。

その他メモ

・Ruby2.3で追加された演算子
・「&.」の姿が膝を抱えている人に見えることがからぼっち演算子という名前がついたとのこと
・オブジェクトさんがいなかったら(nil)、メソッド使って遊ぶことができないから寂しくてnilを返す、ぼっちな演算子。

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

100日後に1人前になる新人エンジニア(4日目)

100日後に1人前になる新人エンジニア(4日目)

先日の記事はこちらから
100日後に1人前になる新人エンジニア(3日目)

どうもこんばんは。早くも週末が終わってしまいますね。
今日も今日とて更新をしていきます。
今まであまりRailsについて書いてこなかったので
今日はRailsのFormに関して書いていこうと思います。

Railsのフォーム

なんかいくつかの種類があるんだなあって感じで学んできたけど
いい機会なのでしっかりまとめてみようと思います。

form_for
form_tag
form_with

この3つですね。とりあえずTutorialでは言われた通り書いてみて
うまくいったなって感じでしたが、それではダメだと思ったので一つずつ見ていきます。

form_for

関連するモデルが用意されている場合はform_forでモデルを渡す。

<%= form_for @user do |form| # @userというインスタンス変数を渡している %>
  <%= form.text_field :email # 受け取ったモデルから作ったformを利用  %>
  <%= form.submit %>
<% end %>

この場合だと関連するモデルは@user
formにこのモデルが紐付けられてるってことですね。

form_tag

関連するモデルがない場合

<%= form_tag users_path do # user_pathというURIを渡している %>
  <%= text_field_tag :email %>
  <%= submit_tag %>
<% end %>

こんな感じですね。formに対してusers_pathと言う形でurlを渡しています。
これによってパラメタを送信しているってことなんですね。

form_with

うーん二つ使い分ける必要があるのね〜。
と言うことでできたのがこのフォームの形式。どちらも対応しています。
なのでRails5.1以降ではformは基本的にこれを使えば良いみたいです(そうだったのね...)

例えば関連するモデルがある場合(上記ではform_for)

<%= form_with model: @user do |form| %>
  <%= form.text_field :email %>
  <%= form.submit %>
<% end %>

関連するモデルがない場合は

<%= form_with url: users_path do |form| %>
  <%= form.text_field :email %>
  <%= form.submit %>
<% end %>

ハイハイなるほどねー。1つの形式で兼用できるわけです。
また、URL: @userがDBに存在するときは、updateアクションに、ないときは、createアクションに飛びます。つまりPOSTなのかPATCHなのかをフォームが判断して送ってくれるってこと。

これすごいよね。Javaやってた僕からするとびっくり!

モデルはかなずしもフィールドに対応しなくてもいい

<%= form_with model: @user, local: true do |form| %>
  <%= form.text_field :email %>
  <%= form.check_box :send_welcome_email %>
  <%= form.submit %>
<% end %>

上記でいうとこの:send_welcome_emailは@userモデルに対応していないが、
それでも問題はない。値はparams[:user][:send_welcome_email]で取り出せる

form_withのlocalについて

<%= form_with model: @user, local: true %>
<% end %>

local: trueってなんやねん。
という疑問をもったので調べました。

form_withではデフォルトの状態ではajaxでの通信がおこなわれる。
それをキャンセルするためのオプションが local: true
なんだって。ふーん。
いまいちわかり切れていないのでここは復習しておきます。

とりあえずformの基本的なところを書いていきました。
基本的にはform_withで行けばいいみたい。
あとはリファレンスを読んで知識を深めていきまーす。

以上

1人前のエンジニアになるまであと96日

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

【開発ログ⑯】テーブル変更後のHeroku再デプロイ

前提について

はじめまして、
プログラミングスクールに通ういりふねと申します。この記事は、スクールの課題である個人アプリの開発の記録を書くことで、自身のアウトプットに利用しています。もし、読んでいただけた方がいましたら、フィードバックをしていただけたら嬉しいです。

開発するのは「有給休暇管理ツール」です。仕様は過去記事をどうぞ。

アプリはデプロイまで行いますが、サービスとして提供するものではありません。あくまでも自学習の一環ですので、ご理解下さい。では本題へどうぞ。

今回の実施内容

前回までで有給休暇管理ツールのindex画面にあるリンクボタンには全てリンク先が設定できました。その後記事にはしていませんが、デプロイまで完了し、無事にスクールの発表会が終了しました。今回はデプロイ後にテーブルのカラムを追加し、再デプロイまでの流れを書きます。

  • ローカルの編集
  • 本番環境でのマイグレーション
  • ビューの確認

開発環境

前提として開発環境を書くことを最近覚えました。

  • Rails 5.2.4.2
  • Ruby 2.5.1
  • データベース postgreSQL
  • デプロイ Heroku

ローカルでの編集

今回はHolidayテーブルに登録日を表す「registration_date」カラムを追加します。これまで有休の付与や消化のデータを取り出すためにデフォルトの「created_at」を使用していましたが、これを止めます。
理由は、先々の消化予定も入力できるようにしたいためです。このサイトで有給管理をする担当者を想定したときに従業員が有給を取る当日に合わせてデータ入力するのはやっぱり手間なので。

まずは、マイグレーションファイルをロールバックします。

$ rails db:rollback

マイグレーションファイルを編集します。

models/*****_create_holidays.rb
class CreateHolidays < ActiveRecord::Migration[5.2]
  def change
    create_table :holidays do |t|
      t.date :registration_date, null: false
〜中略〜
  end
end

再度マイグレーションを行います。

$ rails db:migrate

この他、モデルファイルに記述していた「created_at」を使用した日付の検索メソッドや有休登録画面に登録日のフォームを設置するなど必要な変更を加えていきます。複数ファイルの修正になるので、今回は割愛します。盲点だったのがコントローラーのストロングパラメーターへの追記忘れでした。created_atからの置き換えばかり意識していたので、すっかり忘れていました。何度か有休データが保存できずに焦りましたが、binding.pryを使用して原因を特定しました。

Herokuへのマイグレーション

変更したテーブルやビューを本番環境に反映させるためにHerokuから再デプロイをします。初めはHerokuからマニュアルデプロイでいいかなと思って実行しました。
image.png

しかしながら、エラーが!!(余談ですがこのエラー画面めっちゃ怖い。)
picture_pc_f8886f63bd354c264487153ad2c5c567.png

恐らく、テーブルに登録日カラムが反映されていないので、先程修正したビューファイルや日付検索メソッドたちがエラーとなっているのでしょう。
そこで、次はローカル環境と同じようにロールバックとマイグレーションを実行してみました。

$ heroku run rails db:rollback

結果の画面は以下のとおりです。少し見えにくいですが、「DROP TABLE "Holidays"」の記述があるので、どうやらロールバックは成功したようです。
スクリーンショット 2020-05-24 9.40.46.png

続けて、同じ要領でマイグレーションも実行してみます。

$ heroku run rails db:migrate

こちらも結果は写真のとおりです。同じく見えにくいですが、「create_table(:holidays)」という記述と登録日カラムの「registration_date」が追加されていることが確認できました。
スクリーンショット 2020-05-24 9.41.11.png

ビューの確認

本番環境でビューを確認します。新しいフォームの「登録日」が追加されていることが確認できます。フォームを追加したせいでビューが乱れています(泣)。今後ビューも手直しを入れる予定なので、その際に再度整えていきたいと思います。
スクリーンショット 2020-05-24 20.01.58.png

次に登録後の消化履歴の画面です。こちらも問題なく表示されています。
image.png

今日の積み上げ

難航するかと思っていたテーブルのカラム追加ですが、思いの外、スムーズに終わりました。ただ、ロールバックを行うと本番環境であれ、レコードをは全てなくなったので、これが実際に提供されているサービスだと思うとゾッとします。
やはり、機能の洗い出しやデータベース設計は、めちゃくちゃ大切だということがわかりました。

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

【RSpec】ArgumentError: wrong number of argumentsエラーが出たら、変数の命名を気にした方がいいかもしれないのですね

はじめに

Controller specsに関する記事です。
共通化を行うために変数定義を行った際、命名を適当に行ったら沼ったので備忘録として残しておくことにします!

環境

ruby 2.6.5
rails 5.2.4.2
rspec 3.7
capybara 2.15
factory_bot_rails 4.11

エラー内容

エラー修正前のコード

spec/controllers/posts_controller_spec.rb
require 'rails_helper'

RSpec.describe PostsController, type: :controller do

  context "ログインを必要としないアクション" do
  .
  .
  .
  end

  context "ログインを必要とするアクション" do

    let(:user) { FactoryBot.create(:user) }
    let(:login_user) { login(user) }
    let(:post) { FactoryBot.create(:post) }
    let(:post_params) { FactoryBot.attributes_for(:post) }

    describe "createアクション" do

      context "ログイン済みユーザーの場合" do
        it "投稿を作成する" do
          login user
          expect {
            post :create, params: { post: post_params }
          }.to change(user.posts, :count).by(1)
        end
      end

      context "ログインしていないユーザーの場合" do
      .
      .
      .
      end

    end
  end
end

 前提
  ➡︎テスト用データ作成のためにFactoryBotを使用してます。(postは関連付け済み)
  ➡︎ログイン用にrails_helper.rbファイルに、login(user)メソッドを定義してます。

エラー内容

Failures:
  1) PostsController ログインを必要とするアクション createアクション ログイン済みユーザーの場合 投稿を作成する
    Failure/Error: post :create, { post: post_params }

    ArgumentError:
      wrong number of arguments (given 2, expected 0)
   # ./spec/controllers/posts_controller_spec.rb:85:in `block (5 levels) in <main>'

呼び出し側(give)の引数の数が2、メソッド側(expected)の引数の数が0となっています。

つまり「引数が2つ呼び出されているのに、それに当たるメソッド側の引数が存在しない」ということで怒られています。

エラー地点

post :create, params: { post: post_params }

何故この記述がエラーになるかというと、私が勝手にパラメータのキーとして渡しているつもりになっていた上記の「post:」部分が、実はキーとしてではなく投稿の共通化をするために定義したpost変数だと見なされていたことが原因でした。

2つのgivenは「post:」と「post_params」のことを指していたんですね…。

なので、「post:」部分をキーとして認識してもらえるように共通化の方のpost変数の命名を変えてあげます。

解決策

コード修正後

spec/controllers/posts_controller_spec.rb
require 'rails_helper'

RSpec.describe PostsController, type: :controller do

  context "ログインを必要とするアクション" do

    let(:user) { FactoryBot.create(:user) }
    let(:login_user) { login(user) }
    - let(:post) { FactoryBot.create(:post) } #削除
    + let(:new_post) { FactoryBot.create(:post) } #変数名変更
    let(:post_params) { FactoryBot.attributes_for(:post) }

    describe "createアクション" do
      context "ログイン済みユーザーの場合" do
        it "投稿を作成する" do
          login user
          expect {
            post :create, params: { post: post_params }
          }.to change(user.posts, :count).by(1)
        end
      end
    end
  end
end

post変数をnew_post変数へ書き換え。

spec実行

$ bin/rspec spec/controllers

1 examples, 0 failures

通りました!

今回のエラーで、変数の命名には気をつけようと改めて感じさせられました…笑

参考

 https://qiita.com/yikegaya/items/98f0c12f5c25ee4731a1

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

本番環境(AWS)へ初期データ投入

背景

初めてのポートフォリオ作成時に、大量に存在する初期データを本番環境に流すのになかなか手こずったため、備忘録として記録しています。

DB内の初期データをseed.rbに移行する( gem seed_dump )

自分の場合、開発環境ではmysqlDBにsequel proを使って直接初期データを記入していたため、seed_dumpというgemを使って、db/seed.rbにデータを移す必要がありました。seed.rbに初期データを記入することによって、本番環境でも同様にデータを扱うことができるため、まずはこの作業を行う必要がありました。

Gemfile
gem 'seed_dump'
tarminal
$ bundle install

インストールできたら、今回はTweesテーブルに書いてあるデータをすべて移したかったため、MODELS=モデル名で書き出すテーブルを指定します。また、FILE=db/seeds/tweet.rbとして、作るファイル名を指定しました。

tarminal
$ bundle exec rails db:seed:dump  MODELS=Tweet FILE=db/seeds/tweet.rb

これで、アプリ名/db/seedsの中に、tweet.rbファイルが出来ています。開いてみると中身は,

seed.rb
Tweet.create!([
  {name: "hoge", content: "hugahugahuga", image: "htps://piyo.jpeg"},
 {name: "hoge2", content: "huga2huga2huga2", image: "htps://piyo2.jpeg"},
・・・・・
])

のようにデータが書き写されていると思います。正常に動作するか確認するため、僕はsequel pro などでmysqlのtweetsテーブルのデータを消去した後

tarminal
rails db:seed: tweet

としたところ、正常にDB内にseed.rbの内容が書き込まれました!

本番環境へ投入

今回はAWSでデプロイしたため、AWSでのやり方を説明します。
まずは忘れずに、変更内容をGitHubにプッシュしておきましょう。

sshでログイン後、

tarminal(EC2サーバー)
$ cd /var/www/アプリ名
$ git pull origin master

で最新の状態にしておきます。その後、

tarminal(EC2サーバー)
$ cd /current
$ bundle exec rails db:seed: tweet RAILS_ENV=production

と入力することで、本番環境にもseed.rbの内容を反映することが出来ます。
注意点として、/var/www/アプリケーション名/currentに移動してからでないと、正常に実行できません。

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

Ruby on Rails Elastic beanstalkへのデプロイ(IAM権限変更編)

概要

Ruby on Rails で作ったアプリケーションをデプロイ環境の構築をElasticBeanstalk(以下EB)を使用して、最短で行います。
IAM権限変更編・環境構築編・EBデプロイ編で分けます。
あくまで、パッとデプロイすることに重点を置くので、厳しい管理が必要な方の場合はご了承ください。

目次

IAM権限変更編
環境構築編
EBデプロイ編

IAM権限変更編

ユーザーの作成 → 必要な権限の付与

root権限で実行するのはセキュリティ上よろしくないので、適当なuserを作成して以下の権限を振っていきましょう。
・AWSElasticBeanstalkFullAccess
・AmazonRDSDataFullAccess
・AWSCloudFormationFullAccess
・AWSCloud9Administrator(cloud9使用の方)
EBはEC2、S3へのアクセス権限は含まれていますが、RDSへの権限は含まれませんので、追加で権限を振ります。また、cloudformationはEBのデプロイ環境の構築後の管理・運用時に(インフラのver管理とか、全体構成を見るのにデザイナーで見るとか)使うことがありますので、予め割り振っておくことといいかもです。
cloud9を使用してデプロイされる方はAWSCloud9Administratorもふっておきましょう

1.jpg

また後程、AWSのCLI(command line interface)をinstallしてコマンド上でデプロイしていきますので、その際のアクセスキー、シークレットアクセスキーの取得もしておきましょう。
2.jpg

EBの権限範囲についてはこちら

AWS CLI install方法

AWSの公式ガイドに従います。
ターミナルで以下をコピペするだけです。

pip install --user virtualenv
virtualenv ~/cli-ve
source ~/cli-ve/bin/activate
pip install --upgrade awscli
aws --version
deactivate
brew install awsebcli
#eb コマンドが使えることを確認
eb --version

EBのコマンドライン作成・管理

シークレットキーの入力

$aws configure
AWS Access Key ID [****************225N]: #IAMで取得したAccess Keyをコピペ
AWS Secret Access Key [****************ERNe]: #IAMで取得したSecret Access Keyをコピペ
Default region name [ap-northeast-1]: #そのままenterでOK
Default output format [json]: #そのままenterでOK

これでEBのデプロイまでの準備が整いました。
お疲れ様です。次回EBのデプロイをやっていきます。

EBデプロイ編

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

Ruby on Rails Elastic beanstalkへのデプロイ(環境構築編)

概要

Ruby on Rails で作ったアプリケーションをデプロイ環境の構築をElasticBeanstalk(以下EB)を使用して、最短で行います。
IAM権限変更編・環境構築編・EBデプロイ編で分けます。
あくまで、パッとデプロイすることに重点を置くので、厳しい管理が必要な方の場合はご了承ください。

目次

IAM権限変更編
環境構築編
EBデプロイ編

環境構築編

開発環境について

Ruby・・・2.6.3
Rails・・・5.0.7.2
Bundler・・・2.1.4以上
OS・・・amazon Linux(cloud9)
Railsは、5.2以降はSECRET_KEYのver管理のために少し面倒だったこと、6.0以上はまだまだ新しく(自分が追いつけていない点もあるのですが)わざわざverを上げるメリットがなかったため、ver5.0.7.2を使用しています。

基本、Linuxなので、Macでも同様の操作ができるかと思います。
ただ、cloud9の無料枠ではrbenv、Rubyのver変更等で容量が必要になり、10GBほど拡張しました。
デプロイできたらすぐたたんでOKですが、実際1か月でも500前後ってところでしょうか。
拡張方法はこちら

環境構築

  1. rbenvのinstall
git clone https://github.com/sstephenson/rbenv.git ~/.rbenv

2.buildをpluginとして入れる

mkdir -p ~/.rbenv/plugins

3.ruby-build を~/.rbenvに インストール(clone)する

cd ~/.rbenv/plugins
git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build

4.PATH に追加 → .bash_profileにrbenv initを追加 → pathに追加した情報の有効化

echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
exec $SHELL -l

5.rbenvの確認 → インストールできるリストを確認

rbenv -v
rbenv install --list

6.指定のverを選択(今回は2.6.5)

rbenv install 2.6.5

7.installしたversionに環境全体globalに設定(他のアプリがある場合はlocalにしてください)

rbenv global 2.6.5

8.設定したrbenvを再読み込み

rbenv rehash

9.bundlerのverを指定してinstall

gem install bundler -v 2.1.4

10.railsのver指定でrails new

rails _5.0.7.2_ new myapp

11.gemの追記(開発に必要なものここで入れて事前にデプロイの確認を行うと安心できる)
pg, sqlite 1.3.6以上(pgは、herokuにも対応できるように。sqliteはcloud9の場合1.3.6以上を明記する。dotenv-railsは環境変数を使うので今回入れます、。)

gem 'sqlite3','~> 1.3.6'
gem 'pg'
gem 'dotenv-rails'

12.bundle install

myapp
bundle install --path vendor/bundle

13.gem fileに追記, pg, sqlite 1.3.6以上(pgは、herokuにも対応できるように。sqliteはcloud9の場合)

Gemfile
gem 'sqlite3','~> 1.3.6'
gem 'pg'
gem "dotenv-rails"

14.コア4つで高速install化設定しつつinstall(bundle configに入るため、-j4は今後入力不要)

myapp
bundle install -j4

15.アプリの動作確認

myapp
rails g scaffold message subject body:text
rails db:create
rails db:migrate
rails s

ここでrails のlocalserver への接続確認をしておくこと。
お疲れ様でした。

次はIAMでEBの権限を持ったuserを作成していきます。
Root権限でEBを操作するのはよろしくないですし、Rootのアクセスキーを作成するのも、推奨できないので。

IAM権限変更編

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

Ruby on Rails Elastic beanstalkへのデプロイ(EBデプロイ編)

概要

Ruby on Rails で作ったアプリケーションをデプロイ環境の構築をElasticBeanstalk(以下EB)を使用して、最短で行います。
IAM権限変更編・環境構築編・EBデプロイ編で分けます。
あくまで、パッとデプロイすることに重点を置くので、厳しい管理が必要な方の場合はご了承ください。

目次

IAM権限変更編
環境構築編
EBデプロイ編

EBへデプロイ

1.まずは初期設定を行います。
eb init (再設定の場合は eb init -i)

myapp
Select a default region
1) us-east-1 : US East (N. Virginia)
2) us-west-1 : US West (N. California)
3) us-west-2 : US West (Oregon)
4) eu-west-1 : EU (Ireland)
5) eu-central-1 : EU (Frankfurt)
6) ap-south-1 : Asia Pacific (Mumbai)
7) ap-southeast-1 : Asia Pacific (Singapore)
8) ap-southeast-2 : Asia Pacific (Sydney)
9) ap-northeast-1 : Asia Pacific (Tokyo)
10) ap-northeast-2 : Asia Pacific (Seoul)
・・・
22) af-south-1 : Africa (Cape Town)
(default is 3): 9 #Tokyoを選択
Enter Application Name
(default is "myapp"): 
Application myapp has been created.

It appears you are using Ruby. Is this correct?
(Y/n): 
Select a platform branch.
1) Ruby 2.7 running on 64bit Amazon Linux 2
2) Ruby 2.6 running on 64bit Amazon Linux 2
3) Ruby 2.5 running on 64bit Amazon Linux 2
4) Puma with Ruby 2.6 running on 64bit Amazon Linux
5) Puma with Ruby 2.5 running on 64bit Amazon Linux
6) Puma with Ruby 2.4 running on 64bit Amazon Linux
7) Passenger with Ruby 2.6 running on 64bit Amazon Linux
8) Passenger with Ruby 2.5 running on 64bit Amazon Linux
9) Passenger with Ruby 2.4 running on 64bit Amazon Linux
・・・
17) Passenger with Ruby 2.0 running on 64bit Amazon Linux (Deprecated)
18) Passenger with Ruby 1.9.3 running on 64bit Amazon Linux (Deprecated)
(default is 1): 4 
#cloud9なので、Amazon Linuxですが大切なのは、PumaとRuby 2.6(今回のversion)を選ぶこと

Do you wish to continue with CodeCommit? (y/N) (default is n): <EnterOK>
Do you want to set up SSH for your instances?
(Y/n): <EnterOK>

Select a keypair.
1) cloudformation
2) [ Create new KeyPair ]
(default is 1): <これ用にキーペアを作るか、事前にあるkeyを使うかは自由です。>

これで初期設定はOKです。
デプロイに必要なEC2まわりの作成をしていきましょう。(ここkも良しなにやってくれると助かるのですが。)

2.必要なVPC,subnet,securitygroupの作成
2-1.VPC作成
AWSのコンソールメニューからVPC を選択。
Create VPC をクリック。
以下の通り入力・選択する
Name tag: myapp-vpc (任意の名前)
IPv4 CIDR block: 10.0.0.0/16 (任意のネットワークを指定)
Create をクリック。

2-2.サブネット(Subnet)の作成
左メニューから サブSubnetを選択。
1つめのSubnetを作る。 Subnetの作成 ボタンをクリック。
以下の通り入力。
名前タグ: myapp-subnet-1a (任意のSubnet名)
VPC: myapp-vpc を選択.
アベイラビリティーゾーン: ap-northeast-1a (VPCを作成しているリージョンから一つ選ぶ)
IPv4 CIDRブロック: 10.0.0.0/24 (AZごとにVPCのCIDRの範囲で指定)
2つめのSubnetを作る。ふたたび サブネットの作成 ボタンをクリック。
以下の通り入力。
名前タグ: myapp-subnet-1c (任意のSubnet名)
VPC: myapp-vpc を選択.
アベイラビリティーゾーン: ap-northeast-1c (VPCを作成しているリージョンから一つ選ぶ)
IPv4 CIDRブロック: 10.0.1.0/24 (AZごとにVPCのCIDRの範囲で指定)

2-3.インターネットゲートウェイ(IGW)の作成
左メニューから を選択。
IGWの作成 ボタンをクリック。
Nameタグ: myapp-gateway
作成 ボタンをクリック。
リストからゲートウェイ myapp-gateway を選択し、アクションから VPCにアタッチ を選択。
VPC: myapp-vpc を選択
アタッチ をクリック。
左メニューから ルートテーブル をクリック。
VPC IDを参考に、 myapp-vpc に紐づいているルートテーブルを選択。
ページ下部のタブから Routes を選択し、 Edit routes をクリック。
Add route をクリックし、以下を入力
Destination: 0.0.0.0/0
Targetから Internet Gateway を選択し、続けて myapp-gateway を選択。
Save routes をクリックして保存。

2-4.セキュリティグループの作成(2つのリージョン用に2つ、RDS用に1つ作成します。)
左メニューから セキュリティグループ を選択
Create security group をクリックして以下のように入力.
Security group name: myapp-security-group
Description: (なんでもいいです)
VPC: myapp-vpc を選択。
Create をクリックしてセキュリティグループを作成する。
リストから今作ったセキュリティグループを選択し、画面下のタブから Inbound Rules をクリック。
Edit rules をクリック。
ルールの追加 をクリックして以下のように入力。
タイプ: HTTP
説明: HTTP
Save rules をクリックしてルールを保存する。これを再度繰り返し、もう一つ作成。

RDS用のセキュリティグループは今作ったセキュリティグループの二つからのアクセスを許可するようにします。
Inbound Rulesにセキュリティグループからのインバウンド(アクセス)を許可します。先ほどのセキュリティグループ二つを選択して追加しましょう。
3.jpg

以上でVPC,subnet,securitygroupの作成は終わり。

4.EBへデプロイ
あと少しです。デプロイしていきましょう。
ターミナルに戻って、以下のコマンドでデプロイ時の設定(RDSの作成、ALBの設定も含め)して構築します。

eb create <EBの環境名> --instance_type <EC2のスペック> --database.engine <DBの種類> --database.username <DBusername> --elb-type application --vpc
#例)eb create rails-app --instance_type t2.medium --database.engine mysql --database.username admin --elb-type application --vpc
Enter an RDS DB master password: 
Retype password to confirm: 

Enter the VPC ID: <作成したVPCのID>
Do you want to associate a public IP address? (Y/n): <Enter>
Enter a comma-separated list of Amazon EC2 subnets: <作成した2つのSubnetのID>
Enter a comma-separated list of Amazon ELB subnets: <作成した2つのSubnetのID>
Do you want the load balancer to be public? (Select no for internal) (Y/n): 
Enter a comma-separated list of Amazon VPC security groups:<作成した2つのセキュリティグループのID>

これでデプロイ環境の構築がEBのコンソール画面で始まります。
追加で、作成されたRDSの設定を追加します。(設定するパラメータはRDSのコンソール→各RDS画面で確認できます。)

eb setenv RDS_DB_NAME=◎◎ RDS_USERNAME=◎◎ RDS_PASSWORD=◎◎ RDS_HOSTNAME=◎◎ RDS_PORT=◎◎
例)eb setenv RDS_DB_NAME=myapp RDS_USERNAME=admin RDS_PASSWORD=123456 RDS_HOSTNAME=database-1.cfwrsdfe64.ap-northeast-1.rds.amazonaws.com RDS_PORT=3306

デプロイしてみましょう。

eb deploy

ここで、EBのコンソールでURLを確認してみましょう。

4.jpg

An unhandled lowlevel error occurred. The application logs may have details.
という表示がでました。これはRubyで本番環境時のシークレットキーを作成、設定していないためおきます。
ということで、ここにRubyの本番環境設定をしていきましょう。

5.rubyの環境変数およびシークレットキーの出力EBへの設定

#シークレットキーの出力
rails credential:edit
<シークレットキー>
#EBへ設定を反映
eb setenv SECRET_KEY_BASE=<シークレットキー>

本番環境時のCSSprecompileが必要なので・・

RAILS_ENV=production bundle exec rake assets:precompile
myapp/config/environments/production.rb
config.assets.compile = true

6.再度デプロイ

eb deploy

お疲れ様です。これでデプロイ完了です。

まとめ

今回AWS elastic beanstalkを使ってRubyのアプリケーションのデプロイをしました。
簡単にALB、Autoscallingなどのリソースも含めて冗長的な構成をすぐ作れる事、elastic beanstalkの環境ですべてのリソースの管理できるのもは非常にいいサービスに感じました。
一方で、RDSがデフォルトで作成されなかったり、環境の削除の際はS3が残る点(バケットポリシーの関係で)は不便に感じました。

その他

いくつか、デプロイ後に触ること、エラー時の対応について追記します。
1.初期の設定では毎度DB作成・マイグレーションされる
Elastic Beanstalk>環境>myapp-env>設定
RAILS_SKIP_ASSET_COMPILATION(false → true)
RAILS_SKIP_MIGRATIONS(false → true)

2.エラーについて
エラーがはかれる場合は以下のコマンドで現状のエラー内容がわかるので、対応しましょう。
eb logs

その他ebコマンドについてはこちら
が参考になりました。

参考記事

以下の記事を参考にさせていただきました。
RailsアプリケーションをElastic Beanstalkにデプロイするまで
https://qiita.com/hiroeorz@github/items/c9dcdb9c648d7e8eae7f#rails%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E4%BD%9C%E6%88%90%E3%81%A8%E8%A8%AD%E5%AE%9A%E7%AD%89

Railsのバージョンを指定してinstallする方法
https://qiita.com/tanakayo/items/7b85261924eca1a5a3d6

production環境でsecret_tokenをセットする(rails)
https://qiita.com/takusemba/items/2ad25d3d0a007757c194

Rails5をproduction(本番環境)で起動する時に嵌ったこと
https://qiita.com/qqhann/items/7cd01f4b5cff4a31e053

aws EB CLI 公式ref
https://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/eb3-cmd-commands.html

Elastic Beanstalkで使うコマンドまとめ
https://qiita.com/yoshito410kam/items/712e96be87477aafdc89

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

Rails6 API をGKEにデプロイして動作確認する

今回Rails6 APIをGoogle Kubernetes Engineにデプロイしたので手順のみメモ
ちょっとやり方は特殊かもしれません

構成 (一部のみ)

├── .docker
│   ├── dev
│   │   ├── .bashrc
│   │   ├── Aptfile
│   │   └── Dockerfile
│   └── prod
│        ├── .bashrc
│        ├── Aptfile
│        └── Dockerfile
│   
├── dip.yml
├── docker-compose.development.yml
└── docker-compose.production.yml

手順

rails 導入

Rails 6: Docker/docker-compose/dipでrails new力を取り戻すを参考にdipを使ってrails new します。

Dockerfileとdocker-composeの作成

構成に従ってDockerfileとdocker-compose.production.ymlを作成。
今後dev環境はdipを、production環境はdocker-compose -f docker-compose.production.ymlを使っています(今後はproduction環境をもっとシンプルなものにしたい)。

build

$ docker-compose -f docker-compose.production.yml build

ローカルでの確認

$ docker-compose -f docker-compose.production.yml up

localhostで確認

push

$ docker-compose -f docker-compose.production.yml push

GKEにデプロイ

GCPからKubernetes Engineに移動
5.1 クラスタを作成
5.2 ワークロードからデプロイを選択
5.3 既存のコンテナイメージのイメージパスから「選択」→たった今となっているイメージを選択
キャプチャ1.PNG

公開

  1. デプロイ後のボタンから公開を選択  すでに同様のimageを公開などして表示されない場合などはServicesのサービスを削除する
  2. ポート番号を指定して公開
     例えばポート番号を3000に設定している場合は既存の80→3000に変更します
    キャプチャ.PNG

  3. エンドポイントを選択かURLにエンドポイントを入力して動作を確認
    Railsの初期画面が表示されます。
     キャプチャ.PNG

以上

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

Day18~22 中間試験~基礎カリキュラム本試験

本試験で学んだことについて

本試験は5/22に突破。

学んだことは詳細は後日まとめる。

CSS上のwidth 100%と100vw、またheight 100%と100vhについて、詳しくまとめておきたい。

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

CircleCI config.yml ひな型 Rails 6 / PostgreSQL / Rspec

コピペ元を改造して作りましたが、コピペ元がどこだったかは忘れました。

現在のCircleCI公式でのサンプルとはだいぶ違います。

config.yml
version: 2.1
orbs:
  ruby: circleci/ruby@0.1.2 

jobs:
  build:
    docker:
      - image: circleci/ruby:2.6.6-buster-node-browsers
        environment:
          RAILS_ENV: test
          PGHOST: 127.0.0.1
          PGUSER: circleci
          TZ: "/usr/share/zoneinfo/Asia/Tokyo"
      - image: circleci/postgres:11.7
        environment:
          POSTGRES_USER: circleci
          POSTGRES_DB: blog_rails6_test
          POSTGRES_HOST_AUTH_METHOD: trust # パスワードなし
          TZ: "/usr/share/zoneinfo/Asia/Tokyo"
    steps:
      - checkout
      - restore_cache:
          keys:
            - blog-bundle-v1-{{ checksum "Gemfile.lock" }}-{{ checksum "yarn.lock" }}
            - blog-bundle-v1-
      - run:
          name: Bundler and Yarn
          command: |
            gem install bundler -v '2.1.4' -N
            bundle -v
            bundle install --jobs=3 --retry=3 --path vendor/bundle
            yarn install
      - save_cache:
          paths:
            - ./vendor/bundle
            - ./node_modules
          key: blog-bundle-v1-{{ checksum "Gemfile.lock" }}-{{ checksum "yarn.lock" }}
      - run:
          name: DB Initializing
          command: |
            dockerize -wait tcp://localhost:5432 -timeout 1m
            bundle exec rake db:schema:load
      - run:
          name: rspec
          command: |
            bundle exec rspec --format RspecJunitFormatter \
                              --out test_results/rspec.xml \
                              --format documentation
      - store_test_results:
          path: test_results

以下、自分向け解説。

orbs とは何だかわからない。あとで調べる。

orbs:
  ruby: circleci/ruby@0.1.2 

E2Eテスト(headless Chrome)を使う場合は、「-node-browsers」を選ぶこと。

      - image: circleci/ruby:2.6.6-buster-node-browsers

PostgreSQLをパスワードなしで使う場合はこの環境変数が必要。

          POSTGRES_HOST_AUTH_METHOD: trust # パスワードなし

Webpackerを使っている場合は、node_modulesのキャッシュを作る。Gemfile.lockに加えてyarn.lockの変更で更新されるようにする。

      - restore_cache:
          keys:
            - blog-bundle-v1-{{ checksum "Gemfile.lock" }}-{{ checksum "yarn.lock" }}
            - blog-bundle-v1-
# 中略
      - save_cache:
          paths:
            - ./vendor/bundle
            - ./node_modules
          key: blog-bundle-v1-{{ checksum "Gemfile.lock" }}-{{ checksum "yarn.lock" }}

Bundlerのバージョンを上げているときはインストールが必要。

            gem install bundler -v '2.1.4' -N

PostgreSQLが立ち上がるのを待つ。本当に必要かどうかわからない。

            dockerize -wait tcp://localhost:5432 -timeout 1m

RSpec JUnit Formatter の形式でログを出力し、store_test_results で保存する。すると、CircleCIのサイトで次のリンクから結果が見えるようになる。

circleci-test-results.png

      - run:
          name: rspec
          command: |
            bundle exec rspec --format RspecJunitFormatter \
                              --out test_results/rspec.xml \
                              --format documentation
      - store_test_results:
          path: test_results

GemfileでRSpec JUnit Formatterを入れておく。

group :test do
# 略
  gem 'rspec_junit_formatter'
end

READMEにバッジを表示する

README.md
[![blog-rails6-vuejs](https://circleci.com/gh/kazubon/blog-rails6-vuejs.svg?style=shield)](https://app.circleci.com/pipelines/github/kazubon/blog-rails6-vuejs)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

EC2でデプロイした本番環境にELBを使ってssl化をする際の詰まったところ・注意点

下記URLを参考にELBを設定したのですが10日ほどつまづいたのでメモします.
https://recipe.kc-cloud.jp/archives/11084

一番簡単なパターンのELB(+ACM発行証明書)→EC2の形

初学者はとりあえず一番簡単なパターンのELB(+ACM発行証明書)→EC2の形でssl化を行うのが良いかと思います。

構成は次の通り。
image.png

注意点

ACMで証明書を発行する際に入力するドメイン名はアプリ名.confに書いたドメイン名と同じにする必要がある。

つまり、取得したドメイン名はaaaa.comだけど、アプリ名.confにwww.aaaa.comと書いたらACMの方にもwww.aaaa.comをつける必要があります。

ACMで証明書を発行するドメイン名とnginx周り&Route53周りのドメイン名が異なると

NET::ERR_CERT_COMMON_NAME_INVALID

というエラーが表示されます。

image.png

ELB(ロードバランサー)用のセキュリティグループのインバウンドルールのソースは0.0.0.0/0、::/0にする。

下記画像のようにしてください。

image.png

ソースの部分でマイIPを指定してしまうと自分だけがアクセスできて第三者がアクセスできなくなります。

ACMでSSL化の証明書を発行した場合はnginxでリダイレクトさせようとするとうまくいかないので、上記のようにELBでリダイレクトさせるのが良いです。

サブネットは2つ以上作成する必要がある。

nginx.confの設定はそのままで良い。

ssl_certificate "/etc/pki/nginx/server.crt";
ssl_certificate_key "/etc/pki/nginx/private/server.key";

これは証明書までのパスを書き込むので、ACMで発行している場合EC2にはないのでnginx.conf内に書かなくて良い。

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

【Railsチュートリアル】第2章のまとめ


はじめに

この記事ではRails チュートリアルの第2章
についてまとめた記事です。
ベストプラクティスや間違いがあれば
チュートリアルをやりながら書き直していく予定です。

今回知ったこと

・データモデルを作成できる。
・データモデルを作成するときはscaffoldジェネレータを使う。
・データモデルを作成したらマイグレーションを必ず行う。
・データモデルはModelsにhas_manyとbelongs_toを使うことで関連付けできる。

・Railsにはルーティングという仕組みがある。
・ルートURLにアクションを指定すると表示するページを操作できる。
・modelsを編集することで簡単な入力のサニタイズが可能

データモデルを作成

データモデルを作成するときはscaffoldジェネレータを使う。

nameカラム,emailカラムをもったUserというデータモデルを作成する。
rails generate scaffold User name:string email:string

データモデルを作成したらマイグレーションを行う。
rails db:migrate

ルーティングという仕組み

インフラ屋でIPアドレスのルーティングを書いたことがある人は
ちょっとだけ親しみのある言葉かと思う。

リクエスト文字列に応じて
表示するページや動作を変更できる。

チュートリアルでは動作のことをアクションと表記している。

URL/show 表示
URL/new 新規作成
URL/edit 編集

入力のチェック・無害化

入力のサニタイズはmodelsを編集することで可能

チュートリアルではmicropostのデータモデルを編集した。

class Micropost < ApplicationRecord
  belongs_to :user
  validates :content, length:{maximum:140},
                      presence: true
end

Rubyとオブジェクト指向(OOP)

今回作成したデータモデルmicropostを操作するMicropostは
ApplicationRecord クラスを継承したクラス

まぁ、わからない人は2代目 ApplicationRecord という
認識でだいたい問題ないです。

ApplicationRecordというのがスーパークラス(ベースクラスともいう)

親:ApplicationRecord
子:Micropost

という感じ

エラー対応

gitでリモートリポジトリにpushしてたら
いろいろ行き詰ったのでメモ

SSH RSAキーを登録していないパティーン

アクセス拒否(publickey)
リモートリポジトリが読み込めませんでした。
Permission denied (publickey).
fatal: Could not read from remote repository.

対処方法

1:鍵を作成する。
2:作成した鍵をコピーする。
3:gitghubに公開鍵を登録する。
4:configファイルを作成し直す。(接続確認)
鍵がすでにあれば cat コマンドで表示する。
鍵があるリポジトリ内で以下のコマンドを叩き
GitHubに登録
cat ~/id_rsa.pub

リモートリポジトリにリポジトリがあるパティーン

リモートリポジトリにすでにoriginが存在しています。
fatal: remote origin already exists.

解決策
git remote rm origin originの削除
git remote add origin git@bitbucket.org:ユーザー名/アプリ名.git
git push -u origin master

削除しちゃって問題ないのかって?
今、自分の手元にあるリポジトリが最新であれば問題ないかと思う。
そもそも、リモートのほうが新しい状態って結構異常かと思う。

今回忘れてたこと・コマンド

git remote add origin リポジトリ
git push -u origin master

出力メッセージの英語翻訳(まとめ)

チュートリアルの最中に気になった文言

単語 日本語
On branch master 親ブランチを参照しています
No commits yet まだコミットされていません
Changes to be committed コミットされる変更
Changes not staged for commit 変更がステージングされていません
nothing to commit, working tree clean 作業ツリーにコミットするものは何もありません
discard changes in working directory 作業ディレクトリの変更を無視する
fatal: remote origin already exists. リモートリポジトリにすでにoriginが存在しています。
Permission denied (publickey). アクセス拒否
fatal: Could not read from remote repository. リモートリポジトリを読み込めませんでした。
GitHub found 6 vulnerabilities GitHubが6個の脆弱性をみつけたよ

herokuのインストール方法
source <(curl -sL https://cdn.learnenough.com/heroku_install)

スペルミスで発生したエラー文
Range unspecified. Specify the :in, :within, :maximum, :minimum, or :is option.

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

【Railsチュートリアル】第2章にあるGitのこと


はじめに

この記事ではRails チュートリアルの第2章
についてまとめた記事です。
ベストプラクティスや間違いがあれば
チュートリアルをやりながら書き直していく予定です。

今回知ったこと

・データモデルを作成できる。
・データモデルを作成するときはscaffoldジェネレータを使う。
・データモデルを作成したらマイグレーションを必ず行う。
・データモデルはModelsにhas_manyとbelongs_toを使うことで関連付けできる。

・Railsにはルーティングという仕組みがある。
・ルートURLにアクションを指定すると表示するページを操作できる。
・modelsを編集することで簡単な入力のサニタイズが可能

データモデルを作成

データモデルを作成するときはscaffoldジェネレータを使う。

nameカラム,emailカラムをもったUserというデータモデルを作成する。
rails generate scaffold User name:string email:string

データモデルを作成したらマイグレーションを行う。
rails db:migrate

ルーティングという仕組み

インフラ屋でIPアドレスのルーティングを書いたことがある人は
ちょっとだけ親しみのある言葉かと思う。

リクエスト文字列に応じて
表示するページや動作を変更できる。

チュートリアルでは動作のことをアクションと表記している。

URL/show 表示
URL/new 新規作成
URL/edit 編集

入力のチェック・無害化

入力のサニタイズはmodelsを編集することで可能

チュートリアルではmicropostのデータモデルを編集した。

class Micropost < ApplicationRecord
  belongs_to :user
  validates :content, length:{maximum:140},
                      presence: true
end

Rubyとオブジェクト指向(OOP)

今回作成したデータモデルmicropostを操作するMicropostは
ApplicationRecord クラスを継承したクラス

まぁ、わからない人は2代目 ApplicationRecord という
認識でだいたい問題ないです。

ApplicationRecordというのがスーパークラス(ベースクラスともいう)

親:ApplicationRecord
子:Micropost

という感じ

エラー対応

gitでリモートリポジトリにpushしてたら
いろいろ行き詰ったのでメモ

SSH RSAキーを登録していないパティーン

アクセス拒否(publickey)
リモートリポジトリが読み込めませんでした。
Permission denied (publickey).
fatal: Could not read from remote repository.

対処方法

1:鍵を作成する。
2:作成した鍵をコピーする。
3:gitghubに公開鍵を登録する。
4:configファイルを作成し直す。(接続確認)
鍵がすでにあれば cat コマンドで表示する。
鍵があるリポジトリ内で以下のコマンドを叩き
GitHubに登録
cat ~/id_rsa.pub

リモートリポジトリにリポジトリがあるパティーン

リモートリポジトリにすでにoriginが存在しています。
fatal: remote origin already exists.

解決策
git remote rm origin originの削除
git remote add origin git@bitbucket.org:ユーザー名/アプリ名.git
git push -u origin master

削除しちゃって問題ないのかって?
今、自分の手元にあるリポジトリが最新であれば問題ないかと思う。
そもそも、リモートのほうが新しい状態って結構異常かと思う。

今回忘れてたこと・コマンド

git remote add origin リポジトリ
git push -u origin master

出力メッセージの英語翻訳(まとめ)

チュートリアルの最中に気になった文言

単語 日本語
On branch master 親ブランチを参照しています
No commits yet まだコミットされていません
Changes to be committed コミットされる変更
Changes not staged for commit 変更がステージングされていません
nothing to commit, working tree clean 作業ツリーにコミットするものは何もありません
discard changes in working directory 作業ディレクトリの変更を無視する
fatal: remote origin already exists. リモートリポジトリにすでにoriginが存在しています。
Permission denied (publickey). アクセス拒否
fatal: Could not read from remote repository. リモートリポジトリを読み込めませんでした。
GitHub found 6 vulnerabilities GitHubが6個の脆弱性をみつけたよ

herokuのインストール方法
source <(curl -sL https://cdn.learnenough.com/heroku_install)

スペルミスで発生したエラー文
Range unspecified. Specify the :in, :within, :maximum, :minimum, or :is option.

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

Ruby on rails を初心者向けに解説⑦ ~フラッシュの実装~

はじめに

今回は以前の記事の続きになります。

よろしければ、以前の記事も御覧ください。

今回はフラッシュについてまとめていきます。

Ruby on rails を初心者向けに解説①

Ruby on rails を初心者向けに解説② ~リンクの作成~

Ruby on rails を初心者向けに解説③ ~データベースの作成~

Ruby on rails を初心者向けに解説④ ~命名規則とform_Tagの使い方について~

Ruby on rails を初心者向けに解説⑤ ~データベースの編集と削除~

Ruby on rails を初心者向けに解説⑥ ~バリデーションの作成~

フラッシュとは

具体例を探しに、Twitterにで試してみました。

image.png

この入力されたユーザー名が~の部分がフラッシュです。

フラッシュとはページ上に一度だけ表示されるものであり、ページを更新したり別のページに移動したりするとフラッシュは表示されなくなります。

image.png

このフラッシュを実装してみましょう。

フラッシュの実装

railsでフラッシュを表示するためには、特殊な変数flashが用意されています。

アクションで変数flash[:notice]に文字列を代入すると、viewファイルで使用することができます。flashは一度使用された後は自動的に削除されることになっています。

また、フラッシュは色々な場所で共通して使用するので、application.html.erbファイル内で使用すると便利です。

application.html.erbファイルに書かれたものは、全てのviewファイルに共通して表示されるようになります。

views >> layoutsフォルダの配下にあるapplication.html.erbファイルに以下のように記入してフラッシュが表示できるようにしましょう。

application.html.erb
<% if flash[:notice]%>
  <div class="flash">
    <%= flash[:notice]%>
  </div>
<% end %>

これで、フラッシュが存在するなら表示されるようになりました。

どうせなんで、cssも設定しておきましょう。

application.css
.flash {
    background-color: brown;
    color: white;
}

postsコントローラーを次のように書き直して、flash[:notice]にエラーメッセージを代入してみましょう。

posts_controller.rb
def create
  post = Post.new(content: params[:content])
  @content = params[:content]
  if post.save
    flash[:notice] = "投稿に成功しました"
    redirect_to("/posts/all")
  else
    flash[:notice] = post.errors.full_messages[0]
    render("posts/new")
  end
end

post.saveの部分で失敗した場合に、post.errors.full_messagesにエラーメッセージがリストとして格納されるため、その1つ目の値をflash[:notice]に格納しています。投稿に成功した場合は、その旨をflash[:notice]に格納します。

これでフラッシュを実装することができました。

実際に試してみましょう。

以下のnew.html.erbファイルを開いてみましょう。また、バリデーションは以下のようになっています。

new.html.erb
<%= form_tag("/posts/create") do  %>  
  <textarea name="content" cols="30" rows="10"><%= @content%></textarea>
  <input type="submit" value="送信">
<% end %>
post.rb
class Post < ApplicationRecord
    validates :content, {presence: true}
    validates :content, {length: {maximum: 20}}
end

image.png

試しに、値を何も入れずに送信を押してみましょう。バリデーションに弾かれ、エラーメッセージがflash[:notice]に格納されます。

image.png

次は、20文字以上入力して送信を押してみましょう。次のエラーメッセージが表示されます。

image.png

今度は、投稿に成功した場合を試してみます。次のようになります。

image.png

上手くいきましたね。

終わりに

今回の記事はここまでになります。

お付き合い頂きありがとうございました。

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

Ruby on rails を初心者向けに解説⑥ ~バリデーションの作成~

はじめに

今回は以前の記事の続きになります。

よろしければ、以前の記事も御覧ください。

今回はバリデーションについて学んでいきましょう。

Ruby on rails を初心者向けに解説①

Ruby on rails を初心者向けに解説② ~リンクの作成~

Ruby on rails を初心者向けに解説③ ~データベースの作成~

Ruby on rails を初心者向けに解説④ ~命名規則とform_Tagの使い方について~

Ruby on rails を初心者向けに解説⑤ ~データベースの編集と削除~

新しいコントローラーの作成

新しいコントローラーを作成していきましょう。

今回は、投稿を管理するpostsコントローラーを作成します。ターミナルで以下のコードを実行してください。

rails g controller posts all

all.html.erbファイルで、全ての投稿を表示するようにしましょう。

そのために、新しい投稿を作成するファイルを作成します。new.html.erbファイルをpostsファイルの中に作成しましょう。

image.png

このnew.html.erbファイルで、新しい投稿を作成していきます。

新しいモデルの作成

では、投稿を管理するデータベースを作成しましょう。今回は、まだデータベースを全く作成していないので、モデルから作成していきます。

モデルとは、データベースの情報を操作する仕組みであり、データベースとのやり取りを行うクラスとも言うことができるものでしたね。

モデルは通常、小文字から始まる単数形で命名します。なぜなら、モデルとはtableに対して一つしか存在しないからです。

 rails g model post content: string

このようにモデルを作成すると、同時にデータベースの設計図であるmigrationファイルが作成されるのでしたね。

以下のコードでマイグレーションファイルを実行しましょう。

rails db:migrate

データベースコンソールから、作成したtableを確認してみましょう。

rails dbconsole
.table

ar_internal_metadata schema_migrations

posts users

postsテーブルが作成されていますね。以下のコードで中身を見てみましょう。

.schema posts

CREATE TABLE IF NOT EXISTS "posts" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "content" varchar, "string" varchar, "created_at" datetime NOT NULL, "updated_at" datetime NOT NULL);

投稿を作成

new.html.erbファイルに、投稿を作成するコードを追加しましょう。

new.html.erb
<%= form_tag("/posts/create") do  %>  
  <textarea name="content" cols="30" rows="10"></textarea>
  <input type="submit" value="送信">
<% end %>

image.png

/posts/createというURLにpostリクエストを送っています。params[:content]に、textarea内部のデータが格納されて、送られます。

以下のようにルーティングしましょう。

routes.rb
post "posts/create" => "posts#create"

postsコントローラーのcreateアクションにルーティングされています。textareaのデータをpostsテーブルに格納するために、postsコントローラーを以下のようにコーディングします。

posts_controller.rb
def create
  post = Post.new(content: params[:content])
  post.save
  redirect_to("/posts/new")
end

これで、postsテーブルにデータを保存することができるようになりました。

以下のようにtextareaに記入して送信ボタンを押しましょう。

image.png

データベースを確認してみましょう。ターミナルで以下のコードを打ってください。

rails dbconsole
.header on
select * from posts;

id|content|string|created_at|updated_at
1|pocomaru||2020-05-23 10:37:51.509719|2020-05-23 10:37:51.509719

このように、投稿をデータベースに格納することができました。

バリデーションの設定

バリデーションとは、データベースにデータを保存する際にかける制約のことです。

例えば、何かのサイトにログインする際にメールアドレスやパスワードが空っぽでもログイン可能だとやばいですよね。

そんなことを防ぐために存在します。

バリデーションは、モデルに設定します。

実際に設定してみましょう。

空っぽの投稿を防ぐ

空っぽの投稿を防ぐバリデーションを考えます。

投稿を保存するのはpostsテーブルなので、このバリデーションはpostモデルのPostクラス内部に記入します。

postモデルはデフォルトでは以下のようになっています。

post.rb
class Post < ApplicationRecord
end

バリデーションは、以下の書式で書きます

validates :カラム名, {検証内容}

空っぽの投稿を防ぐバリデーションは以下のようになります。

post.rb
class Post < ApplicationRecord
end

バリデーションは、以下の書式で書きます

validates :カラム名, {検証内容}

空っぽの投稿を防ぐバリデーションは以下のようになります。

post.rb
class Post < ApplicationRecord
    validates :content, {presence: true}
end

これで、空っぽの投稿を防ぐことができました。

バリデーションに引っかかった場合、saveすることができなくなります。また、saveに成功スっればTrueが戻り値として帰ってきて、saveに失敗すればFalseが戻り値として帰ってきます。

postsコントローラーを以下のように書き換えましょう。

posts_controller.rb
def create
  post = Post.new(content: params[:content])
  if post.save
    redirect_to("/posts/all")
  else
    redirect_to("/posts/new")
  end

このようにコードを書き換えることで、saveが成功した場合には/posts/allにリダイレクトし、saveが失敗した場合には/posts/newにリダイレクトします。

これで、空っぽの投稿を排除するバリデーションを作成することができました。

次は、一定以上の文字数を削除するバリデーションを作成してみましょう。

一定以上の文字数を防ぐ

今回は20文字以上の投稿を防ぐバリデーションを設定してみましょう。

以下のようになります。

post.rb
class Post < ApplicationRecord
    validates :content, {presence: true}
    validates :content, {length: {maximum: 20}}
end

このvalidates :content, {length: {maximum: 20}}の部分により、20文字以上の投稿を制限することができるようになりました。

しかし、このようにバリデーションを設定するだけだと、問題があります。20文字以上の投稿をしたときに、textareaが空っぽになってしまうのです。

理由はpostsコントローラーにあります。バリデーションに引っかかり、redirect_to("/posts/new")が呼ばれたとき、ルーティングによりpostsコントローラーのnewアクションが実行されます。そうすると、インスタンス変数をnew.html.erbファイルに送ることができないため、頑張って書いたtextareaが空っぽになってしまうのです。

これを防ぐために、renderというメソッドを使います。

renderとはレンダリングすることができるメソッドであり、レンダリングとはブラウザにviewファイルを読み込ませて描画させることです。

renderメソッドをviewファイル内で使うと、複数のviewファイルの共通の部分を描画する部分テンプレートを使うことができます。

今回はコントローラー内部で使うことにより、アクションを介することなくレンダリングを行うことで、作成したインスタンス変数をviewファイルに渡すことができます。

postsコントローラーを次のように書き換えましょう。

def create
  post = Post.new(content: params[:content])
  @content = params[:content]
  if post.save
    redirect_to("/posts/all")
  else
    render("posts/new")
  end
end

@contentに、投稿の内容を格納した後、redirect_to の代わりにrenderを使ってnew.html.erbファイルを描画しています。

このようにすることで、インスタンス変数であ@contentをnew.html.erbに渡すことができます。

new.html.erbファイル内でこのインスタンス変数を表示するために、以下のように書き換えましょう。

new.html.erb
<%= form_tag("/posts/create") do  %>  
  <textarea name="content" cols="30" rows="10"><%= @content%></textarea>
  <input type="submit" value="送信">
<% end %>

textareaの初期値に@contentを渡しています。これで、バリデーションに引っかかったときに、その値を表示することができます。

実際に試してみましょう。

image.png

以下のように20文字以上入力して、送信を押してみましょう。

image.png

特に何も変わりません。

image.png

終わりに

今回はここまでになります。

お付き合い頂きありがとうございました。

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

Rails でセッションを特定のコントローラだけ無効にしたいとき

概要

クッキーを使ったセッションを特定のコントローラだけ無効にしたいときがあります。

例えば、管理画面Aでは active_record_store でセッション管理をしており、
管理画面Bでは devise token auth でセッション管理をしているときなどです。

この場合、管理画面Aでのみセッション管理が働いて欲しいのに、管理画面Bでも active_record_store によって
sessions テーブルにセッションデータの書き込みが発生してしまいます。

対策

セッションを無効にしたいコントローラーで下記の処理を記載すればOKです。

request.session_options[:skip] = true

参考
https://stackoverflow.com/questions/33318060/how-do-i-prevent-rails-from-creating-a-session

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

Rails の routing で namespace, module, scope, as の違い

概要

routing を書くときに紛らわしいメソッドをまとめました。

ルーティングの各名称

resources :users


名前付きルーティング      パス                     ディレクトリ
      ↓                ↓                         ↓

   Prefix Verb   URI Pattern               Controller#Action
    users GET    /users(.:format)          users#index
          POST   /users(.:format)          users#create
 new_user GET    /users/new(.:format)      users#new
edit_user GET    /users/:id/edit(.:format) users#edit
     user GET    /users/:id(.:format)      users#show
          PATCH  /users/:id(.:format)      users#update
          PUT    /users/:id(.:format)      users#update
          DELETE /users/:id(.:format)      users#destroy

それぞれのメソッドの対応表

名前付きルーティング パス ディレクトリ
namespace
module × ×
scope × ×
as × ×

きれいな routes ファイルを目指しましょう!

参考:
https://devblast.com/b/rails-5-routes-scope-vs-namespace

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