20200623のRailsに関する記事は21件です。

update_attributes is deprecated and will be removed from rails 6.1

備忘録です。

題名のとおりのwarningが出ました。

railsconsole
DEPRECATION WARNING: update_attributes is deprecated and will be removed from Rails 6.1 (please, use update instead)

Rails6.1からupdate_attributesではなくupdateに置き換わる(すでに使える)そうなので、書き換えたらwarningがなくなりました。

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

【Rails】 本番環境MySQLデータを開発環境に入れた後に消す方法

はじめに

本番環境にMySQLのデータを開発環境に入れる時には特にエラーもなくインプットすることができたのですが、消す時になってエラーが発生してハマってしまいました。
少し珍しいケースかもしれませんが、他の方の参考になればと思いまとめることにしました。

関連リンク

そもそも本番環境のMySQLのデータをどうやって開発環境に入れるのかという記事は下記をご参照ください。

エラー

開発環境でDB自体を削除するコマンドを実行したところ、、、

$ rails db:drop

エラーActiveRecord::ProtectedEnvironmentErrorが出ました。。。

このエラーの意味は、

本番環境のDBを操作しようとしているが問題ないですか?

という警告のようなもので、環境変数を入れると操作を続けることができるよ。と言ってます。

そもそも開発環境なんですけど、なんで本番環境と出るんですか??

rails aborted!
ActiveRecord::ProtectedEnvironmentError: You are attempting to run a destructive action against your 'production' database.
If you are sure you want to continue, run the same command with the environment variable:
DISABLE_DATABASE_ENVIRONMENT_CHECK=1
bin/rails:4:in `<main>'
Tasks: TOP => db:migrate:reset => db:drop => db:check_protected_environments
(See full trace by running task with --trace)

結論

先に結論から書いてしまいますが、

Rails5では MySQLに環境変数を格納しており、本番環境のデータをそのまま開発環境に入れたことにより、MySQLの環境変数に本番環境の変数が格納されてしまったため、上記のエラーがでてしまいました。

なので、解決する方法としては、MySQLの環境変数を本番環境のものから開発環境のものに書き換えればいいということです。

解決手順

MySQLに接続します。

$ mysql -h db -u root -p

存在するデータベースを確認します。

$ show databases;

対象のデータベースを指定します。

$ use *******;

データベースないのテーブルの一覧を表示します。

$ show tables;

テーブル一覧の中にar_internal_metadataがあると思います。
この中に、環境変数を格納しています。

+---------------------------------------------------+
| Tables_in_scm_development                         |
+---------------------------------------------------+
| ar_internal_metadata                              |
| ...                                               |
+---------------------------------------------------+

ar_internal_metadataの中身をみてみると、

$ select * from ar_internal_metadata;

見つけましたproductionの文字を。

+-------------+-------------+---------------------+---------------------+
| key         | value       | created_at          | updated_at          |
+-------------+-------------+---------------------+---------------------+
| environment | production  | 2020-01-10 09:37:29 | 2020-01-10 09:37:29 |
+-------------+-------------+---------------------+---------------------+

このproductiondevelopmentへ修正します。

$ update ar_internal_metadata set value='development'

もう一度、ar_internal_metadataの中身をみてみると、

$ select * from ar_internal_metadata;

環境変数はdevelopmentに変更できました。

+-------------+-------------+---------------------+---------------------+
| key         | value       | created_at          | updated_at          |
+-------------+-------------+---------------------+---------------------+
| environment | development | 2020-01-10 09:37:29 | 2020-01-10 09:37:29 |
+-------------+-------------+---------------------+---------------------+

MySQLから抜けて

$ exit

もう一度、DBを削除するコマンドを実行。すると成功しました!

$ rails db:drop

まとめ

つらつらと手順を書いたので、人によっては理解しづらいかもしれませんが、困っている誰かの役に立てばなーと思います。

参考

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

RailsでHerokuにデプロイしたときに一部ページだけ500エラーとなるとき

マイグレーションファイルは慎重に作成し、ミスったらやり直すくらいの覚悟じゃないとHerokuにpushしてheroku run rails db:migrateしたときに沼にハマるよという話。

発生している問題

ローカル環境ではキチンと動くのに、(SQLite->Postgresへの対応などの基本的な設定を済ませてから)Herokuにデプロイするも、一部のページだけが500(Internal Server Error)となる。フロントでは「We're sorry, but something went wrong.」なので、404の「The page you were looking for doesn't exist.」とは違って内部的なエラーが発生している。
スクリーンショット 2020-06-23 21.58.17.png

heroku logs --tailでログを見ても以下の500エラーと書かれただけで何が原因か全然分からないかった。

2020-06-23T09:27:34.223359+00:00 app[web.1]: [8ee3a40d-5258-46f4-8742-48c47f28b01f]   Category Load (1.2ms)  SELECT "categories".* FROM "categories"
2020-06-23T09:27:34.474847+00:00 heroku[router]: at=info method=GET path="/categories/1/show" host=my-app.herokuapp.com request_id=8ee3a40d-5258-46f4-8742-48c47f28b01f fwd="27.81.17.54" dyno=web.1 connect=1ms service=263ms status=500 bytes=1827 protocol=https

結論

汚いマイグレーションファイルを残したままpushしてheroku run rails db:migrateしていないか疑え!

以下の記事の【1】と同じだった。
https://qiita.com/kaorioka09jm/items/9167ba77d1edf7addac2

ローカル開発中にDB作りを試行錯誤したことが原因

Herokuにデプロイした全ページが500とかならheroku run rails db:migrateしてないなど他の理由もあるが、一部のページだけ表示されない場合はDBのマイグレーションが上手くいっていない場合が多いようだ。

結局、ローカルのマイグレーションファイルを削除したり、作り直したりしても、一度Herokuにpushしてしまったマイグレーションファイルがあると、データベースをResetしてもDestroyしても、そこからheroku run rails db:migrateしてもデータベースは綺麗にならない。

そのため筆者の場合はHerokuからアプリを削除して再度pushし直す羽目になった。

マイグレーションファイルの注意点

  • マイグレーションファイルは一度しかrails db:migrateできない
  • 生成されるschema.rbを直接編集しちゃダメ(と思われる)
  • テーブルの削除なども都度マイグレーションファイルを作ってやること

そのため以下のようなマイグレーションファイルの生成は慎重に行う必要がある。もし間違ってカンマを入れたり本来integerのデータ型を間違ってtextに指定してしまったなどだけで、変なマイグレーションファイルが生成される。

// 例
rails g migration CreatePostCategoryRelations post_id:integer category_id:integer
// 間にカンマを入れたり、コロンの位置が違ったり、integerの綴りが違ったりと間違えがち

それを挽回するために別のマイグレーションファイルを作って‥なんてやってローカルでDBをぐちゃぐちゃ構築しても、それをpushした後にheroku run rails db:migrateを実行すると過去のマイグレーションファイルを順に実行するのでおかしくなる。

今回はPosticoの使用により、DBの中のあるテーブルのcategory_idカラムがStringになっていたことに気付けたので、Heroku側のDB生成が上手くいってないことに気付けた。

DBがおかしいと気付くには、rails db:migrateした際のログをめんどうでもちゃんと読んで確認するのも役立つと思う。

  • キチンと標準のテーブル+マイグレーションファイルで指定したテーブルが作成されているか?
  • 各テーブルのカラムのデータ型は正しいか?

テーブルの削除

Heroku上に正しいマイグレーションファイルをpushするには、まずローカルのマイグレーションファイルを綺麗にする必要がある。しかし、間違った記述のあるマイグレーションファイルを削除し、正しいマイグレーションファイルを作成してrails db:migrateしても、以下のように怒られて上書きはできない。

rails aborted!
StandardError: An error has occurred, this and all later migrations canceled:
SQLite3::SQLException: table "post_category_relations" already exists

そのためテーブルの削除用のマイグレーションファイルを作成してrails db:migrateし、再度新たなテーブル作成用のマイグレーションファイルを作成してrails db:migrateする必要がある。

$ rails generate migration RemoveMyTable
20200623XXXX_remove_my_table.rb
class RemoveMyTable < ActiveRecord::Migration[6.0]
  def change
    drop_table :my_table
  end
end

https://qiita.com/kanuu/items/a9223712ee0ff8d19d56

その後、テーブルの削除などに使った余分なマイグレーションファイルを削除する。こうして綺麗なマイグレーションファイルだけが残ったので、これをまっさらなHerokuにpushしてからheroku run rails db:migrateをしてやると綺麗なデータベースができる。

考えたこと

SQLiteとPostgreSQLの互換性の問題ではないか

Herokuでは SQLite が使えないので、production環境だけ PostgreSQL を使用するのはHerokuで最初につまづくポイントだが、これの変更によって使えないメソッドがあるのではと考えた。

が、そんなことはなく、そもそもマイグレーションファイルとはSQLを書かずに、かつ言語の種類(SQLiteかPostgreSQLか等)によらずにDBを操作するためのものである。

今回はControllerの以下のincludeswhereがPostgreSQLでは使えないのでは、といった馬鹿な勘違いをしてしまった‥orz.

categories_controller.rb
def show
  @posts = Post.includes(:categories).where(post_category_relations: { category_id: @category })
end

※Gemのpgloaderを使うなどの記事を見つけたが、それはMySQLのデータをPostgreSQLのデータに移行するものであって、メソッドを変換とかではない。

push後のWarningされてる部分に問題があるのではないか

pushした後に以下のWarningが出るが今回は無関係。またこれらは、どれも特別な使い方をしない限りは、初心者は無視していい警告だ。

remote: ###### WARNING:
remote:        You set your `config.assets.compile = true` in production.
remote:        You set your `config.active_storage.service` to :local in production.
remote:        We detected that some binary dependencies required to
remote:        No Procfile detected, using the default web server.

マイグレーションファイルの理解を深めるのに役立ちそうな記事

そもそもマイグレーションとは何なのか?
https://qiita.com/sobameshi0901/items/f5823fec20e2dd78d9c4

ロールバックという手法もあるらしい?
https://qiita.com/params_bird/items/3d503b5c9f8097df147a

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

Railsチュートリアル(第4版)メモ 第6章

Railsチュートリアル(第4版)の個人メモ
気になった部分、忘れそうな部分を記述。

  • Ruby 2.6.1
  • Rails 5.1.6

前章の最後 (5.4) でUsersコントローラを作成した。そのつづき。
6〜12章にかけて、ユーザ認証の各機能について作成していく。
6章ではこのうち、ユーザのデータモデル、保存について扱われている。

※ おわび
ナレッジになりきれていないメモをQiitaに上げるのが違うような気がしてきたが、
記事として所感を上げれば、それなりに反応があり、勉強にもなったため、お目汚しにはなりますが何卒ご容赦を。
そして最近Rails書いてないのだが下書が埋まってきたので放流。

6章 ユーザーのモデルを作成する

Railsでは認証を実装するための仕組みが既に整っているが、サービスごとに認証には多くのカスタムが必要になる。
このため、車輪の再発明にはなるが、方法を知っていればサードパーティ製の認証も実装しやすくなるので、Railsチュートリアルでは車輪を再発明している。

6.1 Userモデル

Railsは、データモデルとして扱うデフォルトのデータ構造を Model (MVCのM) と呼ぶ。
このModelとのやり取りにはRailsデフォルトでは Active Record というものが使われる。
これはSQLを意識せずにCRUDや構築を行ってくれるもの。

6.1.1 データベースの移行

データベースを永続化するためにUserモデルを作成。
Usersコントローラ作成時と同様、 $ rails g する。

注意として、
コントローラは 複数形 Users
モデルは 単数形 User

とするのが慣習。

$ rails g model User name:string email:string

DBで使う属性(DBでいうカラム名)と、型を : を挟んで渡す。

諸々生成されるが、 db/migrate/ には タイムスタンプ_create_モデル名s.rbというファイルができる。
ここでDB作成のための情報が定義される。

db/migrate/タイムスタンプ_create_users.rb
class CreateUsers < ActiveRecord::Migration[5.0]
  def change
    create_table :users do |t|
      t.string :name
      t.string :email

      t.timestamps
    end
  end
end

idとタイムスタンプについては、特に指定なしでも自動で用意される。
クラス名の部分を見ると、 ActiveRecord::Migration[5.0] を継承しているらしい。
(Railsチュートでは5.0だが、小生の環境は5.1の表記)
timestamps は、タイムスタンプに係る2つのカラム [ created_at, updated_at ] を作成してくれる。

mysqlだとこんなかんじだろうか。

mysql
CREATE DATABASE User;
USE Users;
CREATE TABLE users(
  id INT PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(300),
  email VARCHAR(300),
  created_at TIMESTAMP NOT NULL CURRENT_TIMESTAMP,
  updated_at TIMESTAMP NOT NULL CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP
);

sql書くたびに大文字or小文字 許さないおじさんが発生しそうだな、とビクビクしながら書いている(前職にもいた)。
正直、今の御時世、すべて小文字でも問題ないんだとおもっている。
ちなみに前職では日付はvarchar()で書いてうわなにをするやめろ

マイグレーションを適用。
友人曰く、複数人開発で特に気を遣わんと爆死するコマンドだから、と念を押された。気をつけよう。
DB側はバージョン管理されてるわけではない。

$ rails db:migrate

6.1.2 modelファイル

演習
Railsコンソールで User.new をし、どのような継承関係に有るのか確認した。

Userクラス < ApplicationRecord < ActiveRecord::Base < Object < BaseObject

6.1.3 ユーザーオブジェクトを作成する

railsコンソールのサンドボックスオプション

を使うと、DBへの変更を終了時にすべてロールバックしてくれる。

$ rails console --sandbox

この中での実験。
モデルを生成した際にuserクラスが生成され( app/model/ )、これが ActiveRecord から継承されている。

以下使ったメソッド
valid? : 有効性(Validity)の確認
save : 保存
保存した際、 create_at , update_at にタイムスタンプが押される。
戻り値に、保存ができたかどうかのbool値が帰ってくる。

create : User.new ではメモリ内に生成するだけだったが、生成と同時に保存する。

演習
User.create
user.name
ActiceSupport::timeWithZone

6.2 ユーザーを検証する

6.2.1 有効性を検証する

要はSQLでのカラム型指定みたいな話
:email に対して、 Double とか Boolean は入らんとか。
以下4点

  • 存在性 (presence)
  • 長さ (length)
  • フォーマット (format)
  • 一意性 (uniqueness)

所感

  • usersテーブルに削除フラグって要るような気がする。後で追加するのか?
  • dbのmigrateファイル、いっつも書くidとかをよしなにやってくれるのもだし、varcharとかで文字数指定しなくて良いのだけでも楽。
  • dbのmigrateファイル、変更が時系列で残ってくれるのがとても安心感ある。前職ではDBに変更掛けたときのSQLすら遺してなかった。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Cookieとセッションの違い】Railsチュートリアル 8章と9章では何をしているのか

はじめに

Rails チュートリアル8章、9章では主にログイン機能の実装をしていますが、
sessioncookieなど聞き慣れない用語がいきなり出てきたりして難しいと思います。

私自身、結構混乱してしまう部分もあったので、図を用いて整理してみました。

まずCookieとセッションの違い

8章と9章の違いを理解する上で、まずCookieとセッションの違いを整理します。

Cookieとは

CookieとはWebサーバがブラウザにデータを一時的に保存し、アクセスしてきたクライアントにデータを保持させる仕組みのことです。

以下図のように、クライアントがWebサーバにアクセスすると、WebサーバがブラウザにCookieを保存します。
以降、クライアントがWebサーバにアクセスする際にはこのCookieも一緒に送ります。

cookie_draw.png

Cookieはブラウザを閉じても保持され、有効期限は任意に設定できます。

セッションとは

セッションとはHTTPなどステートレス(状態を保持できない)なプロトコルを使っている場合でも
ステートフル(状態を保持できる)な振る舞いを実現できるようにする方法です。

例えば、本来であればHTTPでは「ユーザのログイン状態」を保持できませんが、
セッションを用いることで「ユーザのログイン状態」を保持して クライアント⇔Webサーバで通信することができます。

セッションの実装には様々なやり方がありますが、Rails(のデフォルト設定)ではCookieによって実装しています。

具体的には以下図のように、セッションを維持するための情報をCookieに保存してクライアント⇔Webサーバで通信を行います。

session_draw.png

セッションはブラウザを閉じると破棄されてしまいます。

8章では何をしているか

8章ではセッションIDを用いたログイン機能を実装しています。

以下コマンドにより、セッション情報としてユーザIDを一時的に保存しています。

session[:user_id] = user.id

これにより、以降は

①クライアントがセッション情報を含んだCookieをサーバに送る

②サーバが保有しているセッション情報と照合

③照合できれば既にログインしているユーザとして認識

というステートフルな通信を実現できます。

ブラウザの開発ツールから、実際にセッション情報を送っているのが確認できます。

session.png

値がユーザIDそのものではなくランダムな文字数列になっているのは、railsが自動でセッション情報を暗号化してくれているからです。
また、このセッション情報は有効期限が「セッション」となっており、ブラウザを閉じると消去されてしまいます。

9章では何をしているか

9章ではセッションを用いず、Cookieのみでログイン機能やその拡張機能を実装しています。
(厳密にはセッションも併用していますが、8章との違いを強調するためにこのような表現をしています。)

8章とは違い、セッション情報ではなく、Cookieに「ユーザID」と「記憶トークン」を格納します。
加えて「記憶トークン」をDBに登録しておき、それを用いて永続的なステートフル通信を実現しています。

「記憶トークン」をDBに登録する際は、ハッシュ関数で暗号化して「記憶トークンダイジェスト」として保存しています。
なので、

ユーザから送られてきた記憶トークンのハッシュ値 ⇔ DBに保存されている記憶トークンダイジェスト

を比較することでユーザ状態を確認しています。
(これはパスワード認証の時と同じです)

これらのフローを図で表すと以下の通りです。

cookie2_draw.png

以下コマンドによってCookieに「ユーザID」と「記憶トークン」を格納しています。

cookies.permanent.signed[:user_id] = user.id
cookies.permanent[:remember_token] = user.remember_token

permanentメソッドを使うとCookieの期限が20年となります。
signedメソッドを使うことで署名付きクッキーを使用でき、ユーザIDを暗号化できます。

ブラウザの開発ツールからCookieの状態を確認することができます。

cookie.png

remember_tokenに「記憶トークン」が格納されています。
user_idに「ユーザID」が暗号化されて格納されています。
(どちらも有効期限が20年)

もしsignedメソッドを使わない場合、クッキー内の情報は以下の通りになります。

cookie2.png

記憶トークンはログインするたびに更新されますが、ユーザIDは頻繁に更新されるものではないので、
そのままCookieに保存しているのは何だか不安です。。。

そのためsignedメソッドによって暗号化しています。

まとめ

8章と9章では同じログイン機能を実装してますが、認証情報をやり取りする方法が違いました。

8章 ⇒ セッションを用いた認証。
    ブラウザを閉じると消えてしまう。

9章 ⇒ Cookieを用いた認証。
    ブラウザを閉じても認証情報を保持できる。
    しかし、記憶トークンをDBに保存したり、署名付きCookieを使うといった対応が必要となる。

以上、何かの参考になれば幸いです。

参考資料

Ruby on Rails チュートリアル

「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典

今さら聞けないセッションとCookie、ログイン・ログアウト(Rails編)

翔泳社 出版「情報処理安全確保支援士 2019年版」 上原孝之 著

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

【Rails】CSVエクスポート機能の実装

目標

ezgif.com-video-to-gif.gif

開発環境

・Ruby: 2.5.7
・Rails: 5.2.4
・Vagrant: 2.2.7
・VirtualBox: 6.1
・OS: macOS Catalina

前提

下記実装済み。

Slim導入
Bootstrap3導入
投稿機能実装

実装

1.application.rbを編集

application.rb
require_relative 'boot'

require 'rails/all'
require 'csv' # 追記

Bundler.require(*Rails.groups)

module Bookers2Debug
  class Application < Rails::Application
    config.load_defaults 5.2
  end
end

2.コントローラーを編集

books_controller.rb
def index
  @book = Book.new
  @books = Book.all
  # 追記
  respond_to do |format|
    format.html
    format.csv do |csv|
      send_users_csv(@books)
    end
  end
end

# 追記
def send_users_csv(books)
  csv_data = CSV.generate do |csv|
    header = %w(ID 登録日 投稿者 タイトル)
    csv << header
    books.each do |book|
      values = [book.id, book.created_at, book.user.name, book.title]
      csv << values
    end
  end
  send_data(csv_data, filename: '本一覧情報')
end

① CSVファイルのヘッダーを設定する。

header = %w(ID 登録日 投稿者 タイトル)
csv << header

② CSVファイルの内容を設定する。

books.each do |book|
  values = [book.id, book.created_at, book.user.name, book.title]
  csv << values
end

③ CSVファイル名を設定する。

filename: '本一覧情報'

3.ビューを編集する。

books/index.html.slim
/ 追記
= link_to 'CSVエクスポート', books_path(format: :csv), class: 'btn btn-success'
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

git pushで毎回ユーザー名とパスワードを入力を回避する方法 - SSH接続

Cloud9からgit pushするのに
毎回ユーザー名とパスワードを要求されるをなんとかしたくて調べてみた
(以下記事作成者に感謝)

git パスワード を毎回聞かれる問題の解決方法 - Qiita

一度ローカル環境のターミナルで設定してみて
Cloud 9からpushしてみるも認証がうまく行かず

鍵の登録はデバイスごとにする必要があります

ローカル環境で設定済みでも、
同じ手続きを再度Cloud9上で行うとSSH接続可能になりました

認証鍵の仕組みは把握していましたが
鍵?という方はこちら

GitHubでssh接続する手順~公開鍵・秘密鍵の生成から~ - Qiita

SSHの仕組みについては

プログラマーがSSH周りで知っておくと良いこと - Qiita

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

【ERROR メッセージ表示】rails 部分テンプレートでいつでも使える 簡易版

【ゴール】

errorメッセージの表示

画面収録 2020-06-23 18.49.15.mov.gif

【メリット】

■ UX向上
■ 部分テンプレートの理解度向上

【開発環境】

■ Mac OS catalina
■ Ruby on Rails (5.2.4.2)
■ Virtual Box:6.1
■ Vagrant: 2.2.7

【実装】

アプリケーション作成

※touch はカレントディレクトリ内でfile作成するコマンド

mac.terminal
$ rails new error_test
$ cd error_test
$ rails g scaffold Item name:string texte:text amount:integer
$ rails db:migrate
$ cd app/views/layouts
$ touch _error_messages.html.erb

モデル追記

※DB保存時の条件
バリデーション = 保存時の制限 を追加

models/item.rb
class Item < ApplicationRecord
  validates :name, presence: true
  validates :text, presence: true
  validates :amount, presence: true
end

ビュー追記

※パーシャル化し、凡庸性UP
「layputs/_error_messages.html.erb」に入れる事で
バリデーションを貼っていれば全てのモデルに使用可能に!!!!

layputs/_error_messages.html.erb
<% if model.errors.any? %>
  <div class="alert alert-warning">
    <ul>
      <% model.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
    </ul>
  </div>
<% end %>

※追加する

Items/_form.html.erb
<%= render 'layouts/error_messages', model: f.object %>

scaffold で作成の場合は上記は不要
各 _form のviewにて下記コード記載の為(scaffold超便利ですね)

/_form.....
<% if item.errors.any? %>
<div id="error_explanation">
  <h2><%= pluralize(item.errors.count, "error") %> prohibited this item from being saved:</h2>

  <ul>
    <% item.errors.full_messages.each do |message| %>
    <li><%= message %></li>
    <% end %>
  </ul>
</div>
<% end %>

※scaffoldの元々のやつ
スクリーンショット 2020-06-23 18.46.33.png

※パーシャルしたやつ
スクリーンショット 2020-06-23 18.47.29.png

以上です。お好みでどうぞ!!!

【合わせて読みたい】

■エラーメッセージに関して
https://qiita.com/ryuuuuuuuuuu/items/1a1e53d062bff774d88a

■hidden_field
https://qiita.com/tanaka-yu3/items/0d454c5ef80f8267f09d

■アプリケーション作成
https://qiita.com/tanaka-yu3/items/3fe1ed2852c6513d3583

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

Rails6の自分流環境構築手順

cloud9で開発している方向けです。

ネットで調べると他にも方法が出てくるので、この方法が合わなかった場合は別の方法を参照してください。

①普遍的なRails5チュートリアルの環境構築方法

$ printf "install: --no-document \nupdate:  --no-document\n" >> ~/.gemrc

$ gem install rails

$ rails new アプリ名

しかし、これでrails sをするとエラーが出てしまいます。

②serverをubuntuサーバに変える

Amazon Linuxサーバーで開発していた人はそのプロジェクトを削除し、新しくubuntuサーバーで作り直してください。

③yarnのインストールとwebpackerのインストール

次のようにコマンドを入力します

$ npm install -g yarn
$ rails webpacker:install

④ちょこっとタイピング

config/environments.development.rb
config.hosts = nil

これでrails sすればうまくいく...はず

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

Railsアプリに独自ドメインを与えてAWSに上げても表示されない問題

「自分のアプリを独自ドメインにしてAWSに上げたろー」

ということで以下の記事を参考に自分のアプリに独自ドメインを付与しました。
https://mel.onl/onamae-domain-aws-route-53/

しかし3日待っても全く表示されない。AWSの紹介ページが表示されるだけ・・・
そこで色々調べた結果、Nginxの設定が必要であるとわかった。

Nginxの設定

EC2で

[USERNAME|~]$ cd /etc/nginx/conf.d/
[USERNAME|conf.d]$ sudo vi 〇〇.conf (#自分のアプリケーション名)

〇〇.confで

server_name  〇〇.com;(#アプリの独自ドメインに変更してください)

保存して終了。再起動する。

[USERNAME|〇〇(アプリ名)]$ sudo nginx -s reload

これで行けるはず!

参考文献
https://qiita.com/naoki_mochizuki/items/5a1757d222806cbe0cd1#nginx%E3%81%AE%E8%B5%B7%E5%8B%95

https://teratail.com/questions/49756

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

【RSpec devise_token_auth 】ユーザー認証トークンを渡す方法

はじめに

devise_token_authを使用してユーザー認証をrequest specに書く際に時間がかかったので、他に同じ様なエラーで詰まっている方のお役に立てれば幸いです。

前提

Ruby:2.6.5
Rails:6.0.3.1

テストはRSpecを使用。
ユーザー認証にdevise_auth_tokenを使用しています。

失敗するspec

shops_request_spec.rb
RSpec.describe "Api::V1::Shops", type: :request do
  describe "GET api/v1/shops" do
    let!(:shops) { create_list(:shop, 10) }
    context "認証済みのユーザーの場合" do
      it "一覧を表示できる" do
        get '/api/v1/shops'
        expect(response.status).to eq(200)
        expect(json.size).to eq(10)
      end
    end
 end

これだとユーザー認証ができずに401のエラーコードが出てテストがパスしません。

ユーザー認証トークンの渡し方

create_new_auth_tokenでトークンを作り、get '/api/v1/shops'にheadersを追加します。
※因みにトークンの認証はuid access-token clientをheadersに返してユーザー認証をしています。

shops_request_spec.rb
RSpec.describe "Api::V1::Shops", type: :request do
  describe "GET api/v1/shops" do
    let!(:shops) { create_list(:shop, 10) }
    context "認証済みのユーザーの場合" do
      let(:auth_headers) { create(:user).create_new_auth_token }
      it "一覧を表示できる" do
        get '/api/v1/shops', headers: auth_headers
        expect(response.status).to eq(200)
        expect(json.size).to eq(10)
      end
    end
 end

この様にかけば、ユーザー認証が成功します!!

参考記事

2番目の記事はやり方は違いますが、同じくdevise_auth_tokenでのユーザー認証のやり方を記載した記事なので、すごく参考になると思います!!

https://tutorialmore.com/questions-2886025.htm

https://qiita.com/mtoyopet/items/ed1bd4b9c1544d401880

おわりに

今年駆け出したばかりのエンジニアなので、何か間違っている点あればコメント等お願いします。

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

Docker+Rails+Vueの環境を迷わず作成するステップ

最近勉強したDockerを使って、railsとVueの環境構築をしてみました。
いろいろ検索してやってみたものの、多くのエラーと向き合う日々を迎えることに...(それでもだいぶ理解は深まった?)

この記事では

  • とにかく開発環境だけ欲しい
  • 自分の忘備録

を主な対象として、最速でDokcer+Rails+Vueの環境を作成するステップをご紹介します?!
(多分エラーは出ないはず。。。)

STEP1. 4つのファイルを作成しよう

まずは作業するフォルダ(ディレクトリ)に

  • Dockerfile
  • docker-compose.yml
  • Gemfile
  • Gemfile.lock

の4つのファイルを作成します。内容はそれぞれ以下のようにします!

Dockerfile
FROM ruby:2.5.3

RUN curl -sL https://deb.nodesource.com/setup_10.x | bash - && apt-get update && \
    apt-get install -y nodejs --no-install-recommends && rm -rf /var/lib/apt/lists/*

RUN apt-get update -qq && apt-get install -y build-essential libpq-dev

RUN apt-get update && apt-get install -y curl apt-transport-https wget && \
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 && apt-get install -y yarn

RUN curl -sL https://deb.nodesource.com/setup_10.x | bash - 
RUN apt-get install -y nodejs npm && npm install n -g && n 10.17.0

RUN yarn add node-sass

RUN mkdir /app
WORKDIR /app
COPY Gemfile /app/Gemfile
COPY Gemfile.lock /app/Gemfile.lock
RUN bundle install
COPY . /app

docker-compose.yml
version: '3'
services:
    web:
        build: .
        command: bundle exec rails s -p 3000 -b '0.0.0.0'
        volumes:
            - .:/app
        ports:
            - 3000:3000
        depends_on:
            - db
        tty: true
        stdin_open: true
    db:
        image: mysql:5.7
        volumes:
            - db-volume:/var/lib/mysql
        environment:
            MYSQL_ROOT_PASSWORD: password
volumes:
    db-volume:

Gemfile
source 'https://rubygems.org'
gem 'rails', '5.2.3'

作業しているディレクトリで
touch Gemfile.lock
を実行すると、からのGemfile.lockが作成されます。

?バージョンやdbのパスワードなどはよしなにご変更ください〜。

STEP2. rails newをする

今回はdockerコンテナ上でrailsアプリを作成するので、コマンドラインにそのまま
rails new
を打つのは正しくありません。
(僕のPCはローカルにrailsを入れていないため、rails newを打っても「そのコマンド知りませんけど?」って怒られます。)

dockerコンテナ上でコマンドを実行したい場合は
docker-compose run
コマンドをつかえばOKです?。

下記コマンドを実行します。
docker-compose run web rails new . --force --database=mysql --webpack=vue --skip-coffee

このコマンドにより、

  • dbはMySQLを明示的に指名
  • Vueを後入れしなくて済む(後入れでエラーが結構出た記憶)
  • coffee使わないので、coffee関連のファイルを作成しない

という付加価値をつけた状態で、rails new しています。

?あと2ステップ!

STEP3. database.ymlを作成する

STEP2の読み込みが完了したら、config/database.ymlが作成されているはず。
このファイル内にある「default」の内容を少し書き換えます。

config/databese.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: password   ←docker-compose.ymlで指定したdbのパスワード
  host: db         ←docker-compose.ymlのservicesで指定したdbの名前

STEP4. docker-compose up --build

ここまでできたら、
docker-compose up --build
を実行します!

少し時間がかかりますが、読み込みが終わったあとにローカルホストにアクセスしてみると、「Yay! You’re on Rails!」の画面が表示されましたか?
もしそうなら成功です!

だがしかしBut。。。?
僕の場合は、「ERROR -- : Unknown database 'app_development' (ActiveRecord::NoDatabaseError)」が表示されました。

僕と同じという方は、
docker-compose exec web rails db:create
をしてあげればOK!

docker-compose down
をした後に、再度
docker-compose up --build
をすれば立ち上がるはずだぞ!お疲れ様でした?

最後に

コロナ禍でWebエンジニア転職を頑張っていますが、railsポートフォリオだけだとお祈りしかされません。
AWSの冗長構成でインフラ構築しててもお祈りです。

そこでRails+VueのRESTfulAPIを使ったアプリ(いわゆるSPA)を追加で作ったところ最終面接までは行けるようになりましたが、それでもやっぱり大変です。

もしWebエンジニア転職が大変だぁという方が読んでくれていたら、これだけは言いたいです。
諦めずに頑張ろうね!!!!

以上、お粗末様でした。

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

Rails フリマアプリ payjpを使った購入機能の実装

なにこれ

某スクールのカリキュラムでフリマアプリを開発しました。
そこで購入機能を実装したので、payjpの導入〜商品購入までの流れを備忘録として書きます。
細かく解説はしないで、ざっと流れを説明する記事です。
コードに縦棒が混じってますが、ご了承下さい。

payjpをインストール

gem 'payjp'をbundle installします

ユーザーのカード情報を保存するためのcardsテーブルを作成

なぜこのテーブルを作るのか

payjpはセキュリティの観点で、payjp側でカード番号などを管理する仕組みになっており、
開発者側の環境では暗号化されてます。
暗号化されたカード情報は保存する必要があるためです。

db/migrate/20200615032616_create_cards.rb
| class CreateCards < ActiveRecord::Migration[5.2] |
|:--|
|   def change |
|     create_table :cards do |t| |
|       t.references :user ,foreign_key: true, null: false |
|       t.string :customer_id, null: false |
|       t.string :card_id, null: false |
|       t.timestamps |
|     end |
|   end |
| end |

次にアソシエーションを組みます。

app/models/card.rb
| class Card < ApplicationRecord |
|:--|
|   belongs_to :user, optional: true |
| end |

ルーティングを設定します。
今回はカード一覧、カード新規登録、カード作成、カード削除をするので、4つ設定します。
商品が購入した時に呼び出されるアクションが欲しいので、posts(商品投稿)にpayアクションを追加しています。
pay/:idで「どの番号の商品か」と言うのを分からせてます。
例)post.id[1]で購入が押されたらパラメーターでpost.id[1]が送られる
それで該当商品を購入済み状態に変更できます!

routes.rb
|   resources :cards, only: [:index, :new, :create, :destroy] |
|   resources :posts do |
|     collection do |
|       post 'pay/:id'=>   'posts#pay' |
|     end |
|   end |

次にcredentials.yml.encにpayjpのシークレットキーの情報を追加します。
credentials.ymlの説明は省略します。

credentialsを編集できるようにするためには、どのエディタで編集するのかをあらかじめ設定する必要があります。

まずは、ターミナルからVSCodeを起動できるよう設定を行います。

VSCodeで、「Command + Shift + P」を同時に押してコマンドパレットを開きます。

続いて、「shell」と入力しましょう。
メニューに、「PATH内に'code'コマンドをインストールします」という項目が表示されるので、それをクリックします。

この操作を行うことで、ターミナルから「code」と打つことでVSCodeを起動できるようになりました。
以下のコマンドでcredentials.ymlを開きます。

EDITOR='code --wait' rails credentials:edit

開いたら以下の内容を記述。
SK_test_XXXXXXの内容は、payjpに会員登録後に「API」という項目から確認できます。

credentials.yml
payjp:
  PAYJP_SECRET_KEY: sk_test_XXXXXXXXXXXXXXXXX

追加したらタブの✗を押して保存します。
control + K だと保存されないです。

cardsコントローラーを作成、編集します。

app/controllers/cards_controller.rb
class CardsController < ApplicationController
  skip_before_action :verify_authenticity_token
  before_action :set_payjp_key, except: :new

  def index
    if current_user.card.present?
      @cards = Card.where(user_id: current_user.id)
    end
  end

  def new
  end

  def create
    if params[:payjp_token]
      customer = Payjp::Customer.create(card: params[:payjp_token])
      @card = Card.new(user_id: current_user.id, customer_id: customer.id, card_id: customer.default_card)
      @card.save
      redirect_to cards_path
    end
  end

  def destroy
    card = Card.find(params[:id])
    customer = Payjp::Customer.retrieve(card.customer_id)
    customer.delete
    card.delete
    redirect_to cards_path
  end

  private

  def set_payjp_key
    Payjp.api_key = Rails.application.credentials.payjp[:PAYJP_SECRET_KEY]
  end

end

createアクションのif params[:payjp_token]は後述しますが、
パラメーターで[:payjp_token]というデータを送っております。
customer = Payjp::Customer.create(card: params[:payjp_token])
でpayjpのサーバーと通信してるみたいです。
通信した結果を変数customerに代入してる。といった流れです。
@card = Card.new(user_id: current_user.id, customer_id: customer.id, card_id: customer.default_card)
これでカードの新規登録を行います。内容は暗号化されたものです

privateの中のset_payjp_keyメソッドとは?
Payjp.api_key = Rails.application.credentials.payjp[:PAYJP_SECRET_KEY]
この記述で、Payjp.api_keyという変数?に、先程追加したcredentials.ymlの中身を呼び出してます。
この記述がないと、createアクションでpayjpのサーバーを呼び出すことができず、エラーが起きます。

beforeアクションでskip_before_action :verify_authenticity_tokenとあります。
これは超重要で、端的に言うと「これがないとpayjpにハッシュ(データ)を送ることができません。」

サーバーサイドの準備は終わったので、次にビューを触っていきます。
application.html.hamlにscriptを追加してpayjpを読み込ませます。

app/views/layouts/application.html.haml
   %body 
     %script{src: "https://js.pay.jp/", type: "text/javascript"} 
     = render 'layouts/notifications'
     = yield

次にカードの新規登録ページを作成します。
クラスは個人で変更して下さい。
%formを使っている理由は、payjpのjsを呼び出すためです。
form_withを使うやり方が分かりませんでした。

app/views/cards/new.html.haml
.show-main__registration-field
  %form.card-form{method: :post, action: "/cards", id: "chargeForm"}
    .show-main__registration-field--text
      クレジットカード情報登録
    .show-main__registration-field__container
      .show-main__registration-field__container__number
        %label.show-main__registration-field__container__number--text
          カード番号
        %span.form-require
          必須
        %input{type: "text", placeholder: "半角数字のみ", class: "show-main__registration-field__container__number--input", id: "card-num-input"}
      .show-main__registration-field__container__expiration
        %label.show-main__registration-field__container__expiration--text
          有効期限
        %span.form-require
          必須
        .show-main__registration-field__container__expiration--input
          %select#month-select
            %option{value: ""} --
            %option{value: "1"}01
            %option{value: "2"}02
            %option{value: "3"}03
            %option{value: "4"}04
            %option{value: "5"}05
            %option{value: "6"}06
            %option{value: "7"}07
            %option{value: "8"}08
            %option{value: "9"}09
            %option{value: "10"}10
            %option{value: "11"}11
            %option{value: "12"}12
          %select#year-select
            %option{value: ""} --
            %option{value: "2021"}21
            %option{value: "2022"}22
            %option{value: "2023"}23
            %option{value: "2024"}24
            %option{value: "2025"}25
            %option{value: "2026"}26
      .show-main__registration-field__container__security
        %label.show-main__registration-field__container__security--text
          セキュリティコード
        %span.form-require
          必須
        %input{class: "show-main__registration-field__container__security--input", id: "security-code-input",  name: "security-code", type: "text", placeholder: "カード背面4桁もしくは3桁の番号"}
        .show-main__registration-field__container__security--information
          %span.show-main__registration-field__container__security--information-link
            =link_to root_path do
              %i.fas.fa-question-circle
              カードの裏面の番号とは?
      %input#add-card-btn{type: 'submit', value: "クレジットカードの登録", class: "show-main__registration-field__container--submit"}

先程formで送信したデータをcontrollerに送れる形式であるpayjp_tokenに変更する処理をjsでします。
このあたりは正直公式のコピペなので、解説できないです。
「こういうもの」としか受け取れないです。
パブリックキーはがっつり本文に書いちゃってokです。
正しいテストカードの情報じゃないとif (status === 200) {によってエラーが出るようになってます。

ちなみに、カードのテスト番号は、以下です
カードナンバー【4242424242424242】
有効期限【12/21】
名前【YUI ARAGAKI】

card-form.js
$(function () {

  // パブリックキーを書いてpayjpと通信できる状態にする
  Payjp.setPublicKey('pk_test_62873b159b61e41f8452494b');
  // 投稿ボタンを定義
  const card_btn = $('#add-card-btn');

  if (card_btn != null) {
    // 投稿ボタンが押されたら発火
    card_btn.click(function (e) {
      e.preventDefault();
      $(function () {
        // カードの情報を定数cardに代入。
        const card = {
          number: $('#card-num-input').val(),
          exp_month: $('#month-select').val(),
          exp_year: $('#year-select').val(),
          cvc: $('#security-code-input').val(),
        }
        form = $("#chargeForm")
        // この記述でtokenを呼び出してます。
        Payjp.createToken(card, function (status, response) {
          if (status === 200) {  //成功した場合。statusが200だと通信成功らしいです。
            // inputをappendしています valueは生成したデータで。
            form.append($('<input name="payjp_token" type="hidden">').val(response.id));
            // これでcreateアクションが呼ばれます。
            form.submit();
            // これが出たらカード情報が登録されます
            alert("カード情報を登録しました");
          } else {
            // カード情報が正しくないor入力漏れがあるとこちらが表示されます
            alert("正しいカード情報を入力してください");
          }
        })
      });
    });
  }

});

次にカード一覧を作成します。
これも公式を移したので解説する部分は少ないです。
payjpは自分でコードを書いたりしないで、公式に頼るのが正解だと思いました。

app/views/cards/index.html.haml
  = render @cards
app/views/cards/_card.html.haml
      = link_to "削除する", card_path(card), method: :delete, class: 'btn', data: { confirm: '削除してよろしいですか?' }

      - customer = Payjp::Customer.retrieve(card.customer_id)
      - @default_card_information = customer.cards.retrieve(card.card_id)
      = "**** **** **** " + @default_card_information.last4
      - exp_month = @default_card_information.exp_month.to_s
      - exp_year = @default_card_information.exp_year.to_s.slice(2,3)
      = exp_month + " / " + exp_year

次は商品詳細ページでpayjpを使った購入リンクを作成します。
postsコントローラーのpayアクションを呼び出す記述をしています。
scriptは公式。

app/views/posts/show.html.haml
   = form_tag(action: :pay, method: :post) do
      %script.payjp-button{:src => "https://checkout.pay.jp", :type => "text/javascript" ,"data-text" => "購入する" ,"data-key" => "pk_test_62873b159b61e41f8452494b"}

コントローラーを記述をします!
cahrgeまで全て公式に書いてあります。
@post.updateでboolean型に指定したpurchasedというカラムをtrueにしてます。
つまり、購入済みの状態にしています。

posts_controller.rb
  def pay
    @post = Post.find(params[:id])
    Payjp.api_key = Rails.application.credentials.payjp[:PAYJP_SECRET_KEY]
    charge = Payjp::Charge.create(
    amount: @post.price,
    card: params['payjp-token'],
    currency: 'jpy'
    )
    @post.update(purchased: true)
    redirect_to root_path, notice: '購入しました!'
  end

以上でpayjpのカード登録〜商品購入までの流れは終了です!

レビュー機能をつけるなら、カラムの設定とかテーブル追加したり色々やると思いますが、
自分たちのチームは必須実装を終わらせると言う目的だったので、そこらへんは触ってないです!
追加実装までやるチームはすごいと思いました。

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

マイグレーション データ型は何が適しての??

マイグレーションで実現できること

テーブル作成
テーブル削除
カラム追加
カラム名変更
カラムのデータ型変更
カラム削除

マイグレーションファイル作成

マイグレーションファイルは モデルを作成した時 に一緒に作成される。
さらに マイグレーションファイル単体 で作成することも可能。

ターミナル
rails g model [モデル名] [属性名:データ型 属性名:データ型・・・] [オプション]

#単体で生成する場合
rails g migration マイグレーション名

上記のコマンドを実行することで、db/migrateフォルダの中にマイグレーションファイルが作成される。

データ型は何が適してるの??

オフィシャル情報 日本語でざっくり概要
primary_key プライマリキー
string 文字列(1〜255文字)
text 長い文字列(1〜4294967296文字)
integer 整数(4バイト)
bigint 整数(8バイト)
float 浮動小数
decimal 精度の高い少数
numeric 数値
datetime 日時
time 時間
date 日付
binary バイナリーデーター
boolean Boolean型

似ているけど違うものはどうするのか

文字を扱う場合、stringとtextどちらが適しているか

stringは、255文字までしか扱うことが出来ないため、状態や時期によっては、256文字以上になる可能性のあるデータを扱う場合はtextを使うことをおすすめします。
名前やメールアドレス、社名などの文字情報は、stringで取り扱い、本文や備考などの文章情報はtextを使うのが一般的です。

enumを扱う場合、stringとintegerどちらが適しているか
hashのintegerをマッピングできるのがenumなので、enumで扱う予定のカラムをstringにしたらそもそもenumを取り入れる意味がないし、機能しないですね。ということを冷静に考えて、enumで扱う予定のカラムのデータ型はintegerが適しています。

idを扱う場合、 integerとbigintどちらが適しているか
idは、将来的にユーザーが増えると膨大な桁数になる可能性があります。Rails5.1からidカラムがデフォルトでbigintになっていることも踏まえて、基本的にはbigintが適していると考えて良いでしょう。

いずれも、現状と一致させるという考え方よりは、将来的に「入らない!」という状況になる可能性が少しでもあれば大きめの箱を用意する、という考え方で選定すると安心です。

補足

Rails modelの命名規約

Railsでは、modelに対応するデータベースのテーブル名はmembersのように複数形になります。

しかし、modelのクラス名は、Memberのように頭が大文字の単数形になる。

また、modelを作成する時は、「rails g model member」のようにmemberを小文字始めても大丈夫です。

また、例えばmember_imageと指定してもMemberImageとしても、MemberImageモデル(テーブル名はmember_images)が作成されます。

ただし、membersのように複数形にすることは厳禁です。Membersモデルが作成されてしまいます。modelは必ず単数形で作成しましょう。

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

[Git] ファイルがどのbranchに含まているか検索する 

謎のmigrationがあるためgit log全体を検索
対象のファイルが含まれるコミットを発見

$ git log --all -- 'db/migrate/2020323*'

commit d178513009038b0d6473de95a685c9402da14123
Author: Cozy <dummy-mail@gmail.com>
Date:   Fri Mar 27 18:20:29 2020 +0900

    〇〇のcolumn名変更

あった。glob対応してるのが嬉しいね

git branchでコミットが含まれるbranchを検索して発見

$ git branch -a --contains d178513009038b0d6473de95a685c9402da14123
  remotes/origin/feature/dummy-feature-branch

これにて一件落着 ?

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

AWS☆☆☆☆ デプロイまでの道のり4-最終章(短いバージョン、全4回)

1)背景

第4回目の最終章です。
自身のポートフォリオをデプロイしました。最後の作業としてドメインの紐つけをします。
AWS関連手順記事はすごく多いので、ここでは備忘録も含めて、非常に端的に手順を記載します。

2)環境

項目 内容
OS.Amazon Linux AMI release 2018.03
Ruby v2.5.1
Ruby On Rails v5.2.4.3
MySQL v5.6
Unicorn v5.4.1

3)内容

以下設定で65分程度かなと思います。(段取りが分かっていれば、30分)
※【ローカルマシン】指定以外は、全てAWSでの作業になります。

(1)お名前ドットコムからドメインを取得(20分)

同サイトからドメインを契約します。ここについては割愛いたします。

(2)Nginxの導入と設定(20分)

  • yumパッケージを活用してNginx(webサーバ)を導入する
  • Nginxのconfigファイルを設定する
  • Nginxのパッケージ権限の付与(/var/lib/nginx)
  • Unicorn設定ファイルの変更(Nginxを経由して処理を行うために設定)

(3)AWS-Route53の設定(10分)

  • ホストゾーンの新規作成
  • 新規レコードセットに同ElaspicIPを登録する

(4)お名前ドットコムの設定(15分)

  • AWSで新規に割り当てられたNSレコードをネームサーバ名として登録する
  • DNS設定(ElaspicIPと、ドメインの紐付けを行う)

(2)Nginx設定2(10分)

  • 登録したドメイン名を同設定ファイルに設定する。

これで完了です。
指定のドメインにアクセスすると、NGINXを介してUnicornが起動しているrailsアプリを参照することが出来ます。
正直簡単です。出来るだけ難しく書かないように端的に記載しました。
以上です。

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

webpacker周りの修正

webpacker3, rails5.2のアプリをクローンしたときにwebpacker周りのエラーに見舞われて直した時の自分用の備忘録です。

これを直した後、webpacker5.1.1、rails6にあげました。

Cannot find module 'babel-plugin-syntax-dynamic-import'

https://github.com/rails/webpacker/issues/1923

pry-doc verisonup

08:35:35 web.1       |  from bin/rails:4:in `<main>'
08:35:35 web.1       | ruby/2.7.1 isn't supported by this pry-doc version
08:35:35 web.1       | exited with code 1
08:35:35 system      | sending SIGTERM to all processes
08:35:40 system      | sending SIGKILL to all processes
nosappunoMacBook-Pro@nosappu ~/desktop/ruby/designcase_hp$ bundle update pry-doc

uninitialized constant Pry::Command::ExitAll (NameError)

 bundle update pry-byebug

https://github.com/pry/pry/issues/2121

undefined method `new_ostruct_member' for #Config::Options (NoMethodError)

https://qiita.com/tttkkkkk/items/f54adc8b7e48dea45e98

Uncaught Error: Module parse failed: Unexpected token (2:0)

File was processed with these loaders:
* ./node_modules/vue-loader/lib/index.js
You may need an additional loader to handle the result of these loaders.

https://github.com/symfony/webpack-encore/issues/321
https://github.com/webpack/webpack/issues/8656
↑より
package.jsonに

"acorn": "^6.0.5"

Module Error (from ./node_modules/vue-loader/lib/index.js):vue-loader was used without the corresponding plugin. Make sure to include VueLoaderPlugin in your webpack config.

未解決
https://qiita.com/kazutosato/items/c0e508f15b9a03f3dd6b
これみてみた

Cannot find module 'postcss-cssnext'

rails webpacker:install 

webpack4以上だと自動的にpostcss.config.jsが作られるらしい
Rails & Webpacker環境でPostCSSを使う
postcss github

gemfileでwebpackerのバージョンをあげていたのでwebpackerのinstallをし直さなければいけなかった

gem 'webpacker', '~> 5.0'
yarn add postcss-cssnext
postcss.config.js
module.exports = {
  plugins: [
    require('postcss-import'),
    require('postcss-flexbugs-fixes'),
    require('postcss-preset-env')({
      autoprefixer: {
        flexbox: 'no-2009'
      },
      stage: 3
    }),
    require('postcss-cssnext') #追加
  ]
}

【保存版】Rails 5 Webpacker公式ドキュメントの歩き方+追加情報

Rails5 / webpacker を heroku で動かす

Rails6でWebpackerの導入(Uikit・foreman)


なんかよくわかんないけど最初webpackerバージョンあげようとしたらこれにつまずいてこれもみてた
UglifyJsPluginは4からは書かなくてもやってくれるらしい
Webpack 4 - How to configure minimize?

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

【CircleCI】GitHubへプッシュ時に自動デプロイする際の手順

今まで自動デプロイは「capistrano」を使用していましたが、毎回コードを修正するたびにローカルでmasterマージして、「bundle exec cap production deploy」を実行していました。

今回はcircleCIを使用し、masterマージされたら自動でサーバーへSSHしてコードをデプロイするように実装してみました。
以下、実装の際の流れや詰まった部分の解説をまとめていきます!

- 開発環境

  • ruby : 2.5.1
  • rails : 2.4.2.3
  • circleCI : 2.1

※ dockerは今回使用していません。

.circleci/config.ymlの設定

①最初にcircleCIで使うconfig.ymlの設定をローカルでしていきます。
circleCIの設定は、該当リポジトリのルート直下に.circleciと言うフォルダを作り、その中のconfig.ymlで行います。

  • config.ymlに以下を追記。
config.yml
version: 2.1
orbs:
  ruby: circleci/ruby@0.1.2 

jobs:
  deploy:
    machine:
      enabled: true
    steps:
      - add_ssh_keys:
          fingerprints:
            - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" #SSHするサーバの秘密鍵を登録後、ハッシュ化されているfingerprintsをコピペする。
      - run: ssh -p $SSH_PORT $SSH_USER@$SSH_HOST "/var/www/リポジトリ名/deploy-me.sh"

workflows:
  version: 2.1
  deploy:
    jobs:
      - deploy:
          filters:
            branches:
              only: master
  • ルート直下に「deploy-me.sh」ファイル作成後、下記を記入。
deploy-me.sh
#!/bin/bash

cd /var/www/リポジトリ名/ && git pull

以下、解説します。
①こちらで自動デプロイの設定をしており、masterマージしたら自動的にデプロイされる仕組みになっている。
②「- add_ssh_keys:」以下には、HOST(IPアドレス)と秘密鍵を登録した際、ハッシュに変換されたfingerprintsをコピペしてくる。これによりSSHするサーバーの秘密鍵を登録できる。
③「- run: ssh -p ~ 」で、設定した鍵 + 設定した環境変数によりsshし、サーバーにログインする。その後、「“/var/www/rails/soup/deploy-me.sh”」によりプルリクしたらgit pullするように設定している。
④workflows以下の設定により、masterブランチ以外ではデプロイを実行しないようにしている。

cirecleCI導入・自動デプロイしたいリポジトリの追加

①まずcircleCIのHP(https://circleci.com) にいき、新しくアカウント登録(sign up)をします。GitHubのアカウントを持っていたらすぐに連携でき、アカウント登録が可能です。

②ログイン後、「Add Projects」を選択し、今回自動デプロイしたいアプリやサイトのリポジトリを追加していきます。
追加するには該当のリポジトリの「Set Up Project」をクリックします。

③上記で設定したconfig.ymlをコピペし、「Add Manually」で登録していく。 この際、秘密鍵の登録はまだできていないです。後に登録していきます。
image.png

④「Start Building」を選択。今回対象となるリポジトリを追加していきます。
追加後、エラーになっていると思いますがそれは秘密鍵や環境変数の設定が済んでいないからです。そちらの情報を追加していきます。

秘密鍵の登録

①ダッシュボード「Pipelines」の右上にある「Project Settings」をクリック。

②「SSH Keys」を選択します。一番下に「Additional SSH Keys」があるため、こちらにローカルの秘密鍵の情報を登録していきます。

③「ADD SSH Key」をクリック。「Hostname」はデプロイ先のIPアドレスを入力します。

④「Private Key*」に秘密鍵を入力するために、ローカルで「.ssh」ディレクトリに入り、lsキーを使って秘密鍵があることを確認します(id_rsa等)。こちらをcatで見ていきます。表示された情報を全てコピペし、「Private Key*」に貼り付けます。この際、「-----BEGIN RSA PRIVATE KEY-----」なども全て含めます。

⑤「Add SSH Key」を押し、無事に通れば設定完了です。エラーが出る場合、pem形式で秘密鍵を登録していないか、秘密鍵の情報が新しい形式のため非対象エラーになっている可能性があります。私の場合は後者のエラーが発生しました。

私は下記のサイトを参考にしてエラーを解消しました。
https://blog.adachin.me/archives/11554
秘密鍵を旧式に更新してから行ったことをまとめました。
https://qiita.com/akk_ayy/items/61215e89cfcf680d1c94

⑥最後に、ハッシュ化されている fingerprints をコピペし、config.ymlの該当部分にペーストします。

環境変数の設定

①「Project Settings」下の「Environment Variables」を選択します。

②「Add Variable」を選択。デプロイ先のポート情報とユーザー名、ホスト名を登録していきます。
- SSH_PORT
- SSH_USER
- SSH_HOST
これで環境変数の設定が完了しました。

③ローカルで設定した内容でSSHログインができるか確かめていきます。

ssh -p ポート ユーザー名@ホスト名 -i ~/.ssh/秘密鍵の名称

これでログインでき、

/var/www/リポジトリ名/deploy-me.sh

これを叩いてgit pullが実行できたら自動デプロイの準備ができています!

自動デプロイを実行

テストデータをmastarマージし、自動デプロイできているか確認。
この際、circleCIがSUCCESSになっていたら成功です!お疲れ様でした!

参考サイト
https://blog.adachin.me/archives/10997
https://qiita.com/tatane616/items/8624e61473a9957d9a81
https://www.tweeeety.blog/entry/2018/02/09/195345

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

【質問】rails db:migrateを実行してDEPRECATION WARNING:エラーの解決方法

初めて質問させていただきます。
プログラミング初心者です。

バージョン:Rails 5.2.4.3

いいね機能を作成のためモデル名Favoritesを作成後
]$ rails db:migrateを実行したところ下記エラーが出ました

エラー文:
DEPRECATION WARNING:Passing the environment's name as a regular argument is deprecated and will be removed in the next Rails version. Please, use the -e option instead. (called from at /home/vagrant/work/Bookers2-favorites/bin/rails:9)
config.eager_load is set to nil. Please update your config/environments/*.rb files accordingly:

  • development - set it to false
  • test - set it to false (unless you use a tool that preloads your test environment)
  • production - set it to true

Traceback (most recent call last):
155: from bin/rails:3:in <main>'
154: from bin/rails:3:in
load'
153: from /home/vagrant/work/Bookers2-favorites/bin/spring:15:in <top (required)>'
152: from /home/vagrant/.rbenv/versions/2.5.7/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in
require'
151: from /home/vagrant/.rbenv/versions/2.5.7/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in require'
150: from /home/vagrant/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/spring-2.1.0/lib/spring/binstub.rb:11:in
'
149: from /home/vagrant/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/spring-2.1.0/lib/spring/binstub.rb:11:in load'
148: from /home/vagrant/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/spring-2.1.0/bin/spring:49:in
'


試したこと:
①$rails c -e test

下記サイトのエラー文と同じようなので試した後再度、rails db:migrateを実行しましたが同じエラーが出て解決できておりません。
https://qiita.com/sukebeeeeei/items/cf0ccb6f7e8b4e8a775b

②$ rails db:migrate:status

database: /home/vagrant/work/Bookers2-favorites/db/development.sqlite3

Status Migration ID Migration Name

up 20200528092619 Devise create users
up 20200528122108 Create books
up 20200530074646 Add user id to books
up 20200601075848 Add profile image id to users
up 20200601090934 Add introduction to users
up 20200601094853 Rename opinion column to books
down 20200622230047 Create favorites

初めて質問させていただいております。何か不足な情報や書き方が至らないところがあるかと思いますが、よろしくお願いします。

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

rails知識メモ[自動で読み込みされるもの]

起動時に自動で読み込まれるもの

  • Rails本体およびその設定(/config/配下)
  • Gemfileによって自動requireされるように指定されているもの

定数を介して自動で読み込み、development環境では自動再読み込みがされるもの

  • /app/配下

https://railsguides.jp/initialization.html
https://railsguides.jp/autoloading_and_reloading_constants.html

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

deviseを利用してRailsアプリケーションに認証機能を作る

はじめに

  • deviseはRailsアプリケーションに簡単に認証機能を追加することができるgemです。deviseはwardenというRackミドルウェアのラッパーで、実際の認証はwardenが行っています(そのため、実装の詳細を知りたい場合はwardenの実装をまず見る必要があるみたいです)。
  • Railsチュートリアルでは認証機能をスクラッチで作成していますが、実際のRailsアプリケーションではこのdeviseを利用して認証機能を作成することがデファクトスタンダードとなっているようです。

  • 今回は自分の勉強のため、deviseを利用してRailsアプリケーションに認証機能を追加する方法を整理したいと思います。なお内容はこちらの記事をほぼ踏襲しています。謝謝

  • なお以下の実装はすべてこちらのリポジトリにあります。

環境

  • Ruby on Rails 5.2.4.3
  • Ruby 2.6.4

deviseのインストール

1.Gemfileを編集

# Devise
gem 'devise'

2.bundle install

$bundle install

deviseの設定

1.以下のコマンドを実行

$ rails g devise:install
      create  config/initializers/devise.rb
      create  config/locales/devise.en.yml
===============================================================================

Depending on your application's configuration some manual setup may be required:

  1. Ensure you have defined default url options in your environments files. Here
     is an example of default_url_options appropriate for a development environment
     in config/environments/development.rb:

       config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

     In production, :host should be set to the actual host of your application.

     * Required for all applications. *

  2. Ensure you have defined root_url to *something* in your config/routes.rb.
     For example:

       root to: "home#index"

     * Not required for API-only Applications *

  3. Ensure you have flash messages in app/views/layouts/application.html.erb.
     For example:

       <p class="notice"><%= notice %></p>
       <p class="alert"><%= alert %></p>

     * Not required for API-only Applications *

  4. You can copy Devise views (for customization) to your app by running:

       rails g devise:views

     * Not required *

===============================================================================

デフォルトURLを設定

config/development.rb
Rails.application.configure do
  ~~中略~~
  config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
end

rootページを作成

ここはスキップして、任意のページをrootページに設定しても大丈夫です。

$rails g controller StaticPages index
route.rb
Rails.application.routes.draw do
  root 'static_pages#index'
  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end

flashメッセージを設定

app/views/layouts/application.html.erbを編集

<!DOCTYPE html>
<html> 
 <head>
  <title>DeviseRails5</title>
  <%= csrf_meta_tags %>

  <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
  <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
 </head>
 <body>
  <p class="notice"><%= notice %></p>
  <p class="alert"><%= alert %></p>

  <%= yield %>

 </body> 
</html>

deviseのviewを作成

$ rails g devise:views
invoke  Devise::Generators::SharedViewsGenerator
create    app/views/devise/shared
create    app/views/devise/shared/_error_messages.html.erb
create    app/views/devise/shared/_links.html.erb
invoke  form_for
create    app/views/devise/confirmations
create    app/views/devise/confirmations/new.html.erb
create    app/views/devise/passwords
create    app/views/devise/passwords/edit.html.erb
create    app/views/devise/passwords/new.html.erb
create    app/views/devise/registrations
create    app/views/devise/registrations/edit.html.erb
create    app/views/devise/registrations/new.html.erb
create    app/views/devise/sessions
create    app/views/devise/sessions/new.html.erb
create    app/views/devise/unlocks
create    app/views/devise/unlocks/new.html.erb
invoke  erb
create    app/views/devise/mailer
create    app/views/devise/mailer/confirmation_instructions.html.erb
create    app/views/devise/mailer/email_changed.html.erb
create    app/views/devise/mailer/password_change.html.erb
create    app/views/devise/mailer/reset_password_instructions.html.erb
create    app/views/devise/mailer/unlock_instructions.html.erb

Userモデルを作成

rails g devise User

上記のコマンドで以下のマイグレーションファイルが生成されます。

db/migrate/20200622180124_devise_create_users.rb
# frozen_string_literal: true

class DeviseCreateUsers < ActiveRecord::Migration[5.2]
  def change
    create_table :users do |t|
      ## Database authenticatable
      t.string :email,              null: false, default: ""
      t.string :encrypted_password, null: false, default: ""

      ## Recoverable
      t.string   :reset_password_token
      t.datetime :reset_password_sent_at

      ## Rememberable
      t.datetime :remember_created_at

      ## Trackable
      # t.integer  :sign_in_count, default: 0, null: false
      # t.datetime :current_sign_in_at
      # t.datetime :last_sign_in_at
      # t.inet     :current_sign_in_ip
      # t.inet     :last_sign_in_ip

      ## Confirmable
      # t.string   :confirmation_token
      # t.datetime :confirmed_at
      # t.datetime :confirmation_sent_at
      # t.string   :unconfirmed_email # Only if using reconfirmable

      ## Lockable
      # t.integer  :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
      # t.string   :unlock_token # Only if unlock strategy is :email or :both
      # t.datetime :locked_at


      t.timestamps null: false
    end

    add_index :users, :email,                unique: true
    add_index :users, :reset_password_token, unique: true
    # add_index :users, :confirmation_token,   unique: true
    # add_index :users, :unlock_token,         unique: true
  end
end

デフォルトではdatabase_authenticatable、registerable、recoverable、rememberable、 validatableがオンになっているようです。

app/models/user.rb
class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable
end

今回はデフォルトのまま作成しますが、オプションで10個のモジュールから好きなものを有効化できます。

モジュール   概要                                                       
Database Authenticatable サインイン中にユーザーの信頼性を検証するために、パスワードをハッシュしてデータベースに保存します。認証は、POST要求またはHTTP基本認証の両方で実行できます。
Omniauthable OmniAuth(https://github.com/omniauth/omniauth)サポートを追加します。
Confirmable 確認手順が記載された電子メールを送信し、サインイン時にアカウントが既に確認されているかどうかを確認します。
Recoverable ユーザーのパスワードをリセットし、リセットの指示を送信します。
Registerable 登録プロセスを通じてユーザーのサインアップを処理し、ユーザーが自分のアカウントを編集および破棄できるようにします.
Rememberable 保存されたCookieからユーザーを記憶するためのトークンの生成とクリアを管理します.
Trackable サインイン数、タイムスタンプ、IPアドレスを追跡します。.
Timeoutable 指定した期間アクティブでなかったセッションを期限切れにします。
Validatable 電子メールとパスワードの検証を提供します。 これはオプションであり、カスタマイズできるため、独自の検証を定義できます。
Lockable 指定された回数のサインイン試行の失敗後にアカウントをロックします。 メールまたは指定した期間の後にロックを解除できます

マイグレーションを実行します

$ rake db:migrate

Viewを編集

ヘッダーを追加します

app/views/layouts/application.html.erb

<!DOCTYPE html>
<html> 
 <head>
  <title>DeviseSampleApp</title>
  <%= csrf_meta_tags %>

  <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
  <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
 </head>
 <body>
 <header>
    <nav>
        <% if user_signed_in? %>
        <%= link_to 'プロフィール変更', edit_user_registration_path %>
        <%= link_to 'ログアウト', destroy_user_session_path, method: :delete %>
    <% else %>
        <%= link_to 'サインアップ', new_user_registration_path %>
        <%= link_to 'ログイン', new_user_session_path %>
        <% end %>
    </nav>
  </header>
  <p class="notice"><%= notice %></p>
  <p class="alert"><%= alert %></p>

  <%= yield %>

 </body> 
</html>
  • トップページにアクセスすると、こんな感じの画面が生成されています。
    スクリーンショット 2020-06-23 3.48.36.png

  • サインアップをクリック
    スクリーンショット 2020-06-23 3.34.51.png

  • サインアップしてメールアドレスとパスワードを入力すると、見事にログインできました!
    スクリーンショット 2020-06-23 3.35.29.png

その他

deviseが提供するヘルパーメソッド

user_signed_in?

ユーザがログインしているかどうかを確認できます。

current_user

ログインしているユーザにアクセスできます。

user_session

セッションにアクセスできます。

サインアップ後のリダイレクト先を変更

app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  def after_sign_up_path_for(resource)
    edit_user_registration_path #ここを編集して任意のページに飛ばせる
  end
end

サインアップ後、以下のページにリダイレクトするようになりました。

スクリーンショット 2020-06-23 3.34.18.png

ログイン後のリダイレクト先を変更

app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  def after_sign_in_path_for(resource)
    edit_user_registration_path #ここを編集して任意のページに飛ばせる
  end
end

コールバック関数

(ここは正確にはよくわかっていませんが)

  • deviseが呼んでくれるコールバックはafter_fetchだけらしいので(要出典)、その他のコールバックを呼びたいときはwardenのインターフェイスを直接呼び出す必要があります。

参考文献

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