- 投稿日:2020-06-23T23:31:50+09:00
【Rails】 本番環境MySQLデータを開発環境に入れた後に消す方法
はじめに
本番環境にMySQLのデータを開発環境に入れる時には特にエラーもなくインプットすることができたのですが、消す時になってエラーが発生してハマってしまいました。
少し珍しいケースかもしれませんが、他の方の参考になればと思いまとめることにしました。関連リンク
そもそも本番環境のMySQLのデータをどうやって開発環境に入れるのかという記事は下記をご参照ください。
- EC2からMySQL(RDS)接続後にローカル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 | +-------------+-------------+---------------------+---------------------+この
production
をdevelopment
へ修正します。$ 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まとめ
つらつらと手順を書いたので、人によっては理解しづらいかもしれませんが、困っている誰かの役に立てばなーと思います。
参考
- 本番環境のデータをローカルのDBに投入したら UnknownMigrationVersionError と ProtectedEnvironmentError (Rails 5)
- 投稿日:2020-06-23T23:09:23+09:00
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.」とは違って内部的なエラーが発生している。
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 RemoveMyTable20200623XXXX_remove_my_table.rbclass RemoveMyTable < ActiveRecord::Migration[6.0] def change drop_table :my_table end endhttps://qiita.com/kanuu/items/a9223712ee0ff8d19d56
その後、テーブルの削除などに使った余分なマイグレーションファイルを削除する。こうして綺麗なマイグレーションファイルだけが残ったので、これをまっさらなHerokuにpushしてから
heroku run rails db:migrate
をしてやると綺麗なデータベースができる。考えたこと
SQLiteとPostgreSQLの互換性の問題ではないか
Herokuでは SQLite が使えないので、production環境だけ PostgreSQL を使用するのはHerokuで最初につまづくポイントだが、これの変更によって使えないメソッドがあるのではと考えた。
が、そんなことはなく、そもそもマイグレーションファイルとはSQLを書かずに、かつ言語の種類(SQLiteかPostgreSQLか等)によらずにDBを操作するためのものである。
今回はControllerの以下の
includes
やwhere
がPostgreSQLでは使えないのでは、といった馬鹿な勘違いをしてしまった‥orz.categories_controller.rbdef 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
- 投稿日:2020-06-23T22:34:18+09:00
正規表現で大文字から始まる文字列を取り出す(Ruby)
今回やる事
タイトル通り、正規表現で大文字から始まる文字列を取り出します。
コード
今回書いたコードは以下の通り
# 配列から大文字から始まる文字列を抜き出すメソッド def upperstr(array) # 配列の添字として使用する変数 count = 0 # 大文字から始まる文字列を格納する配列 upper = [] # eachメソッドで配列に含まれている要素を全て取り出す array.each{|arraystr| # 正規表現で先頭が大文字から始まりる文字列を抽出し、配列(upper)に格納する upper[count] = arraystr.slice(/^[A-Z].*/) # 配列の添字に1を加算する count += 1 } # 文字列の先頭が小文字だった場合は配列にnilが格納されるため、deleteメソッドでnilを削除する。 upper.delete(nil) # メソッドの返り値として、大文字から始まる文字列を格納した配列を変えす。 return upper end # ユーザー用のガイド p "文字列を半角スペースで区切って入力してください" # コンソールから入力した文字列を変数に代入 str = gets # 入力された文字列を半角スペースで区切って配列に代入 ary = str.split(" ") # upperstrメソッドの返り値を変数に代入 # (upperstrメソッドは大文字から始まる文字列を取り出すメソッド) upperary = upperstr(ary) # ユーザー用のガイド p "大文字から始まる文字列を取り出しました" # eachメソッドで配列に含まれている要素を全て取り出す upperary.each{|ustr| # 配列の中身を表示 p ustr }正規表現
※各メソッドや処理についてはコメントに書いたので説明は割愛。
今回はupperstrメソッド内で使用しているsliceメソッドで正規表現を使っております。
噛み砕きまくって説明しますと、以下の通りです。①コード
upper[count] = arraystr.slice(/^[A-Z].*/)②/
/ と / で囲まれた範囲が正規表現パターンの範囲となる③^
^の直後の文字が先頭の文字であることを表しています④[A-Z]
AからZという意味であり、大文字であることを表しています。
^[A-Z] とすることで先頭が大文字である文字列を検索する事ができます。
小文字にしたい場合は[a-z]です。⑤.
. は任意の1文字です。⑥*
は直前の文字列が0回以上繰り返すことを意味します。
. と書くことで、「任意の文字列が0回以上繰り返す」ということになります。
なんかわかりづらいと思いますが、「先頭の文字以外はどうでもいいよ」っていうことです。動作確認
実際にプログラムを動かした結果を書いておきます。
入力値は「aaa AAA B b CC cc DDDDD ddddd」です。
大文字から始まる文字列を取り出すので、想定される結果は「AAA B CC DDDDD」となります。% ruby regex.rb "文字列を半角スペースで区切って入力してください" aaa AAA B b CC cc DDDDD ddddd "大文字から始まる文字列を取り出しました" "AAA" "B" "CC" "DDDDD"想定通りの結果が出ました!今回の記事は以上です!
- 投稿日:2020-06-23T21:53:26+09:00
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:stringDBで使う属性(DBでいうカラム名)と、型を
:
を挟んで渡す。諸々生成されるが、
db/migrate/
にはタイムスタンプ_create_モデル名s.rb
というファイルができる。
ここでDB作成のための情報が定義される。db/migrate/タイムスタンプ_create_users.rbclass CreateUsers < ActiveRecord::Migration[5.0] def change create_table :users do |t| t.string :name t.string :email t.timestamps end end endidとタイムスタンプについては、特に指定なしでも自動で用意される。
クラス名の部分を見ると、ActiveRecord::Migration[5.0]
を継承しているらしい。
(Railsチュートでは5.0だが、小生の環境は5.1の表記)
timestamps
は、タイムスタンプに係る2つのカラム [created_at
,updated_at
] を作成してくれる。mysqlだとこんなかんじだろうか。
mysqlCREATE 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::timeWithZone6.2 ユーザーを検証する
6.2.1 有効性を検証する
要はSQLでのカラム型指定みたいな話
Double
とかBoolean
は入らんとか。
以下4点
- 存在性 (presence)
- 長さ (length)
- フォーマット (format)
- 一意性 (uniqueness)
所感
- usersテーブルに削除フラグって要るような気がする。後で追加するのか?
- dbのmigrateファイル、いっつも書くidとかをよしなにやってくれるのもだし、varcharとかで文字数指定しなくて良いのだけでも楽。
- dbのmigrateファイル、変更が時系列で残ってくれるのがとても安心感ある。前職ではDBに変更掛けたときのSQLすら遺してなかった。
- 投稿日:2020-06-23T20:47:36+09:00
【Rails】CSVエクスポート機能の実装
目標
開発環境
・Ruby: 2.5.7
・Rails: 5.2.4
・Vagrant: 2.2.7
・VirtualBox: 6.1
・OS: macOS Catalina前提
下記実装済み。
実装
1.
application.rb
を編集application.rbrequire_relative 'boot' require 'rails/all' require 'csv' # 追記 Bundler.require(*Rails.groups) module Bookers2Debug class Application < Rails::Application config.load_defaults 5.2 end end2.コントローラーを編集
books_controller.rbdef 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'
- 投稿日:2020-06-23T19:54:37+09:00
Ruby Silverに合格(2020年6月)したので、まとめてみます。
スペック
- 非ITエンジニア
- Rubyはプログラミングスクールで学習
- IT系の資格はITパスポートのみ
ITエンジニアになるためにプログラミングスクールに通い、二ヶ月半程RubyやRailsを学んでいたので、初学者ですが独学ではありません。
受験対策の教材
- [改訂2版]Ruby技術者認定試験合格教本(Silver/Gold対応)
- Rubyがミニツク/ Ruby技術者認定試験(Silver)対策問題集
- Ruby技術者認定試験一問一答
- DIVE INTO EXAM
- 模擬問題集PDF(Silver試験用)
- RubyExamination
- Wandbox(オンラインコンパイラ)
Ruby2.1以下ではエラーになり、2.2以上ではエラーにならないコード出てくるので、手軽にバージョンを切り替えられるWandboxを使うといいかもしれません。
勉強方法
Rubyをスクールで学んでいたので、ある程度の基礎知識はありました。そのため「Rubyがミニツク/入門コース」と「Ruby技術者認定試験合格教本(以下、教本)」を1回読んで基礎知識を広めてから、練習問題に取り掛かりました。
練習問題のレベル感や解説は、以下のように感じました。
- やさしい/丁寧
- 教本の練習問題
- Rubyがミニツク
- Ruby技術者認定試験一問一答
- ふつう
- 模擬問題集PDF(Silver試験用)
- DIVE INTO EXAM
- むずかしい
- RubyExamination
やさしいは、解説が丁寧だったと感じたので、間違えたところの理解がしやすかったです。
ふつうは、やさしいに比べて解説文が短かったので、教本の読み直しやぐぐったりコードを打つ回数が増えました。
むずかしいは、5回やって1〜2回目は不合格、3〜5回目は合格でした。Goldの問題も含まれているらしいので難しく感じましたが、理解を深めるためにやって損はないと思います。
勉強の振り返りと反省
コードの書き方やメソッドの種類等、スクールの学習以外で知識を吸収出来たのがとても良かったので、Ruby初学者の目標としてはSilverを取得するのはアリだと思いました。
しかし、やるからには100点狙おうと思って勉強したのはよくなかったと思います。実務で使わない内容も多いらしいので、アプリを作る時に知っておくと便利だなと思ったのはきちんと理解し、使わなさそうなのは深掘りする必要はなかったかなと思いました。Ruby Silverについて
- 「Ruby Association Certified Ruby Programmer Silver version 2.1」が正式名称らしいです。
- 終了後、即採点されてその場で「合格」の文字が出るので、履歴書にすぐに取得資格として書く事が出来る。
- ここを読むとRuby SilverはITパスポートと同じレベル感なので、資格と考えるなら弱いのかもしれません。
- Rubyの知見は広がり深まりましたが、Rubyエンジニアの方曰く実務で使う内容は少ないとのことです。
- 投稿日:2020-06-23T19:06:05+09:00
git pushで毎回ユーザー名とパスワードを入力を回避する方法 - SSH接続
Cloud9から
git push
するのに
毎回ユーザー名とパスワードを要求されるをなんとかしたくて調べてみた
(以下記事作成者に感謝)git パスワード を毎回聞かれる問題の解決方法 - Qiita
一度ローカル環境のターミナルで設定してみて
Cloud 9からpush
してみるも認証がうまく行かず鍵の登録はデバイスごとにする必要があります
ローカル環境で設定済みでも、
同じ手続きを再度Cloud9上で行うとSSH接続可能になりました認証鍵の仕組みは把握していましたが
鍵?という方はこちらGitHubでssh接続する手順~公開鍵・秘密鍵の生成から~ - Qiita
SSHの仕組みについては
- 投稿日:2020-06-23T18:51:41+09:00
【ERROR メッセージ表示】rails 部分テンプレートでいつでも使える 簡易版
【ゴール】
errorメッセージの表示
【メリット】
■ 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.rbclass 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 %>以上です。お好みでどうぞ!!!
【合わせて読みたい】
■エラーメッセージに関して
https://qiita.com/ryuuuuuuuuuu/items/1a1e53d062bff774d88a■hidden_field
https://qiita.com/tanaka-yu3/items/0d454c5ef80f8267f09d■アプリケーション作成
https://qiita.com/tanaka-yu3/items/3fe1ed2852c6513d3583
- 投稿日:2020-06-23T14:18:00+09:00
いろんなフィボナッチ数列の関数作ってみた(Ruby)
単純な再帰で書く
絶対おそい(nが0or1の深さになるまで再帰するため)。
def fib(n) return n if n == 0 || n == 1 return fib(n - 1) + fib(n - 2) endちょっと工夫した再帰
再帰だが、やってることはfor文と大して変わらない。
ただ再帰関数なので、超でかいnが渡されたらスタックオーバーフローするかも?def fib(n, a, b) return a if n == 0 return fib(n - 1, b, a + b) endforで書く
再帰じゃないのでスタックオーバーフローが発生しない…はず。
分割代入使うとキレイに書ける。
分割代入をすこれ。def fib(n) a, b = 0, 1 n.times.each { a, b = b, a + b } a end動的計画法(メモ化)で書く
TODO 誰か書いてください。
- 投稿日:2020-06-23T13:53:23+09:00
Chefのチュートリアル
このチュートリアルでは、Chefについて学び、Chefを使ってAlibaba Cloud上でシンプルなReact.jsサイトを設定、構築、デプロイする方法を学びます。
本ブログは英語版からの翻訳です。オリジナルはこちらからご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。
前提条件
このチュートリアルに従うには、以下のものが必要です。
- 2つのAlibaba Cloud Elastic Compute Service (ECS)インスタンスがUbuntu 16.04でインストールされており、少なくとも2GBのRAMを持っています。これらのインスタンスのうち1つはChefノードに、もう1つはChefサーバに使用されます。また、これらのインスタンスでは、ポート22、80、443が開いていることを確認してください。
- Chefノードとサーバの両方に使用する完全修飾登録ドメイン(またはFDQN)。Alibaba Cloudドメインを購入するか、Freenomで無料で取得することができます。
Chefを知る
Chefはいくつかの異なるコンポーネントで構成されています。これらのコンポーネントを理解することが重要なので、ここではChefの3つの主要なコンポーネントを簡単に見ていきましょう。
- Chefサーバー:このコンポーネントは設定データのハブとして機能し、設定レシピ、cookbooks、ノードに適用されるポリシー、Chefによって管理されている各登録ノードを記述するメタデータがすべて保存される中心的な場所として機能します。また、このコンポーネントは、組織内の他のすべてのマシン(またはノード)がデプロイメント設定の目的で使用する中央マシンでもあります。
- Nodes:ノードの重要なコンポーネントは、物理的または仮想的なもので、Chefを使用して管理できるマシンと理解することができます。Chef-clientは各ノードにインストールされ、各ノードを希望の状態に設定するために使用されます。ノードはchef-clientを使用してchefサーバーと対話し、レシピ、テンプレート、ファイル配布などの設定情報を取得します。
- Workstation: Chef ワークステーションは、Chef の設定情報を作成または編集する場所です。設定ファイルはChefサーバーにプッシュされ、任意のノードにデプロイできるようになります。ワークステーションからChefサーバーとのやりとりは、knifeとchefコマンドラインツールを使用して行われます。
環境の設定
いよいよ実用的なことをする時が来ました。このチュートリアルでは、環境を設定し、chef を使って React.js アプリケーションを構築するために必要なツールをインストールします。
ワークステーションの設定
ワークステーションは基本的にはChefの設定の詳細をオーサリングする場所です。ワークステーションはあなたが選択したOSであれば何でも構いません。つまり、Linux、MacOS、Windowsの全てがここで動作することになります。
1.ChefDKパッケージをインストールします。Chef DK (開発キット)には、インフラストラクチャの開発とテストに必要なすべてのツールが含まれています。このチュートリアルを書いている時点では、現在の安定版(4.0.60)を使用しています。このリンクをクリックして、お使いのOSに基づいたChef DKをダウンロードしてください。
2.Chef DKをインストールしたことを確認し、コマンドラインからChef DKにアクセスできることを確認します。これを行うには、
chef —version
を実行してインストールを確認することができます。chef@workstation:~$ chef --version Chef Development Kit Version: 4.0.60 chef-client version: 15.0.300 delivery version: master berks version: 7.0.8 kitchen version: 2.2.5 inspec version: 4.3.2
- MacおよびLinuxユーザーの場合は、Chef開発キットに含まれているRubyのバージョンがデフォルトのRubyのバージョンとして設定されていることを確認する必要があります。これを行うには、以下の手順に従ってください。
- ターミナルを開き、
which ruby
を実行します。以下のような結果が得られるはずです。chef@workstation:~$ which ruby /usr/bin/ruby
chef shell-init
サブコマンドを使用して、ChefDKに含まれるRubyをシステムRubyとして設定する必要があります。ChefDKによって使用されるアプリケーションは、ワークステーション上にも存在する可能性のある他のRuby開発ツールから分離することができます。chef@workstation:~$ echo 'eval "$(chef shell-init bash)"' >> ~/.bash_profile && source ~/.bash_profile
zsh
、fish
、Windows PowerShell (posh) など、bash とは異なるシェルを使用している場合は、SHELL_NAME
をシェルに、SHELL_PROFILE
をシェルプロファイルに置き換えて、以下のコマンドを実行してください。chef@workstation:~$ echo 'eval "$(chef shell-init SHELL_NAME)"' >> ~/.SHELL_PROFILE && source ~/.SHELL_PROFILE
- もう一度
which ruby
コマンドを実行して、Chef開発キット版のrubyを使用していることを確認すると、以下のような出力が得られるはずです。chef@workstation:~$ which ruby /opt/chefdk/embedded/bin/ruby4.次に、ワークステーション用の
react-app-repo
という作業ディレクトリを作成する必要があります。このためにchef generate repo repo_name
コマンドを使用することになります。これにより、Chefが必要とするファイルやフォルダ構造が作成されます。chef@workstation:~$ chef generate repo react-app-repo && cd react-app-repo5.ワークステーションの設定が完了したので、Chefサーバーの設定と設定を行います。
Chefサーバーの設定
Chefサーバーを設定するには、以下の手順に従います。
1.ChefサーバーとしてUbuntu 16.04でインストールされたAlibaba Cloud ECSインスタンスをスピンアップし、ポート80、22、443が開いていることを確認します。クラウドでChefサーバを実行している場合は、セキュリティグループを通じてこれらのポートが開いていることを確認します。
2.Chefサーバーには、解決可能なドメインとホスト名が必要です。サーバーのホスト名がパブリックホスト名と一致していることを確認する必要があります。これは、以下のコマンドを実行することで可能です。
chef@chef_server:~$ echo YOUR_DOMAIN_NAME | xargs sudo hostname3.学習のために、このチュートリアルのために以下のbashスクリプトを作成しました。これはChef-serverパッケージをダウンロードしてインストールする際に役立つはずです。
- 以下のスクリプトをサーバ上のパス
/tmp/installChefServer.sh
にコピーしてください。chef@chef_server:~$ sudo vi /tmp/installChefServer.sh bash #!/usr/bin/env bash BOLD='\e[1m' GREEN='\e[92m' NC='\e[0m' updateLinuxPackages() { printf "${BOLD}${GREEN}=================================== Updating all packages ============================================ ${NC}\n" apt-get update } createDirectories() { if [ ! -d /creds ]; then mkdir /creds fi if [ ! -d /downloads ]; then mkdir /downloads fi } downloadAndInstallChefServer() { if [ ! -f /downloads/chef-server-core_12.19.26-1_amd64.deb ]; then printf "${BOLD}${GREEN}=================================== Downloading the Chef server package... ================== ${NC}\n" wget -nv -P /downloads https://packages.chef.io/files/stable/chef-server/12.19.26/ubuntu/16.04/chef-server-core_12.19.26-1_amd64.deb fi if [ ! $(which chef-server-ctl) ]; then printf "${BOLD}${GREEN}=================================== Installing Chef server =================================== ${NC}\n" dpkg -i /downloads/chef-server-core_12.19.26-1_amd64.deb chef-server-ctl reconfigure printf "${BOLD}${GREEN}=================================== Waiting for services ====================================== ${NC}\n" until (curl -D - http://localhost:8000/_status) | grep "200 OK"; do sleep 15s; done while (curl http://localhost:8000/_status) | grep "fail"; do sleep 15s; done printf "${BOLD}${GREEN}============================= Creating user ========================== ${NC}\n" # creating user format: chef-server-ctl user-create USER_NAME FIRST_NAME LAST_NAME EMAIL 'PASSWORD' --filename FILE_NAME chef-server-ctl user-create admin admin admin admin@example.com 'notsecure' --filename /creds/chefadmin.pem printf "${BOLD}${GREEN}============================= Creating oganization with user ========================== ${NC}\n" # creating org format: chef-server-ctl org-create SHORT_ORG_NAME 'FULL_ORG_NAME' --association_user USER_NAME --filename FILE_NAME chef-server-ctl org-create chef "Chef-learn, Inc." --association_user admin --filename organization-validator.pem printf "${BOLD}${GREEN}============================= Adding Web UI for chef ========================== ${NC}\n" chef-server-ctl install chef-manage chef-server-ctl reconfigure chef-manage-ctl reconfigure --accept-license fi printf "${BOLD}${GREEN}==================================== Your Chef server is ready! ================================== ${NC}\n" } main() { updateLinuxPackages createDirectories downloadAndInstallChefServer } main
このスクリプトでは、以下の情報を持つユーザーも作成します。
- ユーザー名: admin
- Firstname:admin
- Lastname: admin
- 電子メール: admin@example.com
- パスワード: notsecure
以下のコマンドを実行してスクリプトを実行可能な状態にします。
chef@chef_server:~$ sudo chmod u+x /tmp/installChefServer.sh
- 最後にスクリプトを実行します。少し時間がかかるかもしれません。
chef@chef_server:~$ sudo /tmp/installChefServer.sh4.ブラウザ上のChefのWebインターフェースにホスト名でアクセスできます。
ワークステーションがChef Serverと通信するように設定する
ワークステーションとChefサーバー間の通信を確立するために、すでにChefDKに含まれている
Knife
ユーティリティツールを利用します。基本的に、Knifeは、Chefサーバーを認証するために2つのファイルを必要とします。
knifeの設定ファイル
knife.rb
には、Chef サーバーの URL、RSA 秘密鍵(SSH 鍵)の場所、cookbookのデフォルトの場所などの情報が含まれています。RSA秘密鍵は、Chefサーバに送信されるすべてのリクエストを認証するために使用されます。公開鍵はChefサーバーが保持し、プライベート鍵はワークステーションが保持します。
ワークステーションとChefサーバー間の通信を確立するには、以下の手順に従ってください。
1.
knife configure
コマンドを実行して、knifeの設定を作成します。
YOUR-HOST-NAME
をchef-serverドメイン名に、SHORT-ORG-NAME
をchef
に置き換えます。また、クライアントキーを配置するための出力で指定されたパスをメモしておきます。chef@workstation:~$ knife configure WARNING: No knife configuration file found. See https://docs.chef.io/config_rb_knife.html for details. Please enter the chef server URL: [https://devops1c.mylabserver.com/organizations/chef]: https://YOUR-HOST-NAME/organizations/SHORT-ORG-NAME Please enter an existing username or clientname for the API: [user] admin ***** You must place your client key in: /home/user/.chef/chefadmin.pem Before running commands with Knife ***** Configuration file written to /home/user/.chef/credentials2.あなたの
react-app-repo
ディレクトリにknife.rb
ファイルを作成して、knife がcookbooks
の場所を知っていることを確認する必要があります。chef@workstation:~$ mkdir .chef && echo 'cookbook_path ["#{File.dirname(__FILE__)}/../cookbooks"]' >> .chef/knife.rbまた、
installChefServer.sh
スクリプトでユーザーを作成した時に作成したSSH鍵ファイルを、scp
コマンドを使ってchef-serverからワークステーションにコピーする必要があります。Note
~/.chef/admin.pem
はクライアントキーを置くために指定されたパスですが、knife configure
コマンドの出力で指定されたパスと異なる場合は変更してください。そして、以下の項目に置き換えてください。
IP-ADDRESS-OR-HOSTNAME
は、chef-serverのパブリックIPアドレス/ホスト名に置き換えます。
USER
はChefサーバーのユーザー名に置き換えてください。
PATH_TO_YOUR_SSH_KEY
は、Chefサーバの ssh-key へのパスに置き換えてください。chef@workstation:~$ scp -i PATH_TO_YOUR_SSH_KEY USER@YOUR-IP-ADDRESS-OR-HOSTNAME:/creds/chefadmin.pem ~/.chef/admin.pemあるいは、サーバへのアクセスを得るための認証手段としてパスワードを使用している場合は、以下のコマンドを実行することもできます。
chef@workstation:~$ scp USER@YOUR-IP-ADDRESS-OR-HOSTNAME:/creds/chefadmin.pem ~/.chef/admin.pem3.次に、以下のコマンドを使用してChefサーバーからSSL証明書を取得し、検証する必要があります。
chef@workstation:~$ knife ssl fetch WARNING: Certificates from www.mydomainname.com will be fetched and placed in your trusted_cert directory (/home/user/.chef/trusted_certs). Knife has no means to verify these are the correct certificates. You should verify the authenticity of these certificates after downloading. Adding certificate for www_mydomainname_com in /home/user/.chef/trusted_certs/www_mydomainname_com.crt
knife ssl check
コマンドを実行して、SSL構成を確認します。chef@workstation:~$ knife ssl check Connecting to host ec2-34-207-124-26.compute-1.amazonaws.com:443 Successfully verified certificates from ec2-34-207-124-26.compute-1.amazonaws.comこれでワークステーションの設定が完了し、knifeを使ってChefサーバーに接続できるようになりました。次のパートでは、ノードの設定を行います。
ノードの設定とブートストラップ
Chefで設定を管理する作業を開始する前に、作業するノードが必要になります。これを行うには、Ubuntu 16.04をインストールした別のECSインスタンスを作成し、ワークステーションから
Knife
とbootstrap
サブコマンドを利用します。ノードサーバを作成するだけで、ほとんどの作業はworkstation
から行われます。1.Ubuntu 16.04をインストールした別のAlibaba Cloudインスタンスを作成し、ポート80、22、443、3000が開いていることを確認します。react.jsアプリケーションはポート3000で実行されます。
2.以下のコマンドを実行して、ノードサーバのホスト名がパブリックホスト名と一致していることを確認する必要があります。
では、次のように置き換えます。
IP-ADDRESS-OR-HOSTNAME
をノードサーバのパブリック IP アドレス/ホスト名に置き換えます。ノードサーバ上のユーザの名前を持つ
USER
PATH_TO_YOUR_SSH_KEY
にノードサーバの ssh-key へのパスを指定します。chef@workstation:~$ ssh -i PATH_TO_YOUR_SSH_KEY USER@YOUR-IP-ADDRESS-OR-HOSTNAME 'echo YOUR_DOMAIN_NAME | xargs sudo hostname'3.ワークステーションから、新しいクラウドサーバーをChefサーバーが管理するノードにブートストラップするには、以下のコマンドを実行します。
以下では、
IP-ADDRESS-OR-HOSTNAME
をノードサーバのパブリックIPアドレス/ホスト名に置き換えます。ノードサーバ上のユーザの名前を持つ
USER
PATH_TO_YOUR_SSH_KEY
にノードサーバの ssh-key へのパスを指定します。
reactJS-node
でnode_name
を指定します。node_name
はノードに与えたい名前であることを理解してください。chef@workstation:~$ knife bootstrap IP-ADDRESS-OR-HOSTNAME --connection-user USER --sudo -i PATH_TO_YOUR_SSH_KEY --node-name NODE-NAME Bootstrapping 34.76.3.167 [34.76.3.167] -----> Installing Chef Omnibus (stable/15) [34.76.3.167] [34.76.3.167] downloading https://omnitruck.chef.io/chef/install.sh ...... [34.76.3.167] Getting information for chef stable 15 for ubuntu... [34.76.3.167] Installing chef 15 [34.76.3.167] [34.76.3.167] [34.76.3.167] Thank you for installing Chef Infra Client! For help getting started visit https://learn.chef.io [34.76.3.167] [34.76.3.167] Starting the first Chef Infra Client Client run... [34.76.3.167] [34.76.3.167] +---------------------------------------------+ [34.76.3.167] [34.76.3.167] 2 product licenses accepted. [34.76.3.167] [34.76.3.167] +---------------------------------------------+ [34.76.3.167] [34.76.3.167] Starting Chef Infra Client, version 15.0.300 [34.76.3.167] [34.76.3.167] resolving cookbooks for run list: [] [34.76.3.167] Synchronizing Cookbooks: [34.76.3.167] Installing Cookbook Gems: [34.76.3.167] Compiling Cookbooks... [34.76.3.167] [2019-07-01T06:52:36+00:00] WARN: Node reactJS-node has an empty run list. [34.76.3.167] Converging 0 resources ........ [34.76.3.167] Running handlers: [34.76.3.167] [34.76.3.167] Running handlers complete [34.76.3.167] Chef Infra Client finished, 0/0 resources updated in 02 secondsあるいは、サーバへのアクセスを得るための認証手段としてパスワードを使用している場合は、以下のコマンドを実行してください。
chef@workstation:~$ knife bootstrap IP-ADDRESS-OR-HOSTNAME -N NODE_NAME -x USER -P 'PASSWORD' --sudo4.自分のノードがChefサーバーに関連付けられていることを確認するには、
knife node list
コマンドを実行します。chef@workstation:~$ knife node list reactJS-node
knife node show
コマンドを実行することで、ノードのデータを見ることができます。knife node show NODE-NAMEchef@workstation:~$ knife node show reactJS-node Node Name: reactJS-node Environment: _default FQDN: ip-172-31-56-238.home.internal IP: 41.215.245.118 Run List: Roles: Recipes: Platform: ubuntu 16.04 Tags:React.jsアプリケーションの構築
chefサーバー、ワークステーション、ノードのセットアップが完了したので、 react.jsアプリケーションを構築する準備が整いました。以下のようなcookbookを書くことになります。
- node.jsのセットアップとインストール
- pm2をインストールします。
pm2
はプロセスマネージャーであり、react.js
アプリの動作を維持するのに役立ちます。
react.js
アプリケーションをインストールします。
react.js
アプリケーションを起動します。そのためにchef executeとbashリソースを使うことになります。これらのリソースはどちらもコマンドやスクリプトを実行するために使用します。
execute
リソースは単一のコマンドを実行するために、bash
リソースは複数行のコマンドを実行するために使用します。構文やプロパティの詳細については、execute リソースと bash リソースのドキュメントを参照してください。ワークステーションの
cookbooks/example/attributes/recipes
ディレクトリにあるdefault.rb
ファイルを開き、以下のように置き換えてください。bash 'Install Node.js' do cwd "/home/ubuntu" code <<-EOH curl -sL https://deb.nodesource.com/setup_8.x -o nodesource_setup.sh bash nodesource_setup.sh apt-get install nodejs -y EOH end execute 'Install pm2' do cwd "/home/ubuntu" command 'npm install pm2 -g' end execute 'Setup react app' do cwd "/home/ubuntu" command 'npx create-react-app my-app' only_if do ! File.exist?('/home/ubuntu/my-app') end end bash 'Start application' do cwd "/home/ubuntu" code <<-EOH cd my-app pm2 start npm -- start EOH endcookbookを実行するためには、Chefサーバーにアップロードする必要があります。このファイルに変更を加えるたびに、再アップロードする必要があることに注意してください。
react-app-repo
ディレクトリにあることを確認して、このコマンドを実行してください。chef@workstation:~$ knife upload cookbooks/example以下のコマンドを使用して、ノードの
run_list
にCookbookのrecipe
を追加する必要があります。chef@workstation:~$ knife node run_list add reactJS-node 'recipe[example]' reactJS-node: run_list: recipe[example]
run_list
の詳細はドキュメントで確認できます。さて、
knife ssh
コマンドを使ってreactJS-node
にcookbookをデプロイします。そして、以下のように置き換えてください。
USER
をノードサーバ上のユーザ名に置き換えてください。
PATH_TO_YOUR_SSH_KEY
にノードサーバの ssh-key へのパスを指定します。chef@workstation:~$ knife ssh 'name:reactJS-node' 'sudo chef-client' --ssh-user USER --ssh-identity-file PATH_TO_YOUR_SSH_KEYこれで、ブラウザのウィンドウに
http://NODE_SERVER_IP_ADDRESS:3000
を貼り付けて react.js アプリケーションにアクセスできるようになりました。このようなページが表示されるはずです。結論
このガイドでは、Chefを始める上での柔軟な基礎を解説しています。Chefの詳細については、Chefの公式ドキュメントを参照して、chef rallyを学ぶことからご覧ください。
アリババクラウドは日本に2つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
アリババクラウドジャパン公式ページ
- 投稿日:2020-06-23T12:53:01+09:00
マイグレーション データ型は何が適しての??
マイグレーションで実現できること
テーブル作成
テーブル削除
カラム追加
カラム名変更
カラムのデータ型変更
カラム削除マイグレーションファイル作成
マイグレーションファイルは モデルを作成した時 に一緒に作成される。
さらに マイグレーションファイル単体 で作成することも可能。ターミナル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は必ず単数形で作成しましょう。
- 投稿日:2020-06-23T11:56:01+09:00
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アプリを参照することが出来ます。
正直簡単です。出来るだけ難しく書かないように端的に記載しました。
以上です。
- 投稿日:2020-06-23T11:23:56+09:00
【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.ymlversion: 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」で登録していく。 この際、秘密鍵の登録はまだできていないです。後に登録していきます。
④「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
- 投稿日:2020-06-23T04:00:02+09:00
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 installdeviseの設定
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.rbRails.application.configure do ~~中略~~ config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } endrootページを作成
ここはスキップして、任意のページをrootページに設定しても大丈夫です。
$rails g controller StaticPages index
route.rbRails.application.routes.draw do root 'static_pages#index' # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html endflashメッセージを設定
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.rbclass 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>その他
deviseが提供するヘルパーメソッド
user_signed_in?ユーザがログインしているかどうかを確認できます。
current_userログインしているユーザにアクセスできます。
user_session
セッションにアクセスできます。
サインアップ後のリダイレクト先を変更
app/controllers/application_controller.rbclass ApplicationController < ActionController::Base def after_sign_up_path_for(resource) edit_user_registration_path #ここを編集して任意のページに飛ばせる end endサインアップ後、以下のページにリダイレクトするようになりました。
ログイン後のリダイレクト先を変更
app/controllers/application_controller.rbclass ApplicationController < ActionController::Base def after_sign_in_path_for(resource) edit_user_registration_path #ここを編集して任意のページに飛ばせる end endコールバック関数
(ここは正確にはよくわかっていませんが)
- deviseが呼んでくれるコールバックはafter_fetchだけらしいので(要出典)、その他のコールバックを呼びたいときはwardenのインターフェイスを直接呼び出す必要があります。
参考文献