- 投稿日:2020-01-21T22:44:27+09:00
【Rails】devise実装後のユーザー新規登録時のエラー[ArgumentError in Users::RegistrationsController#create]
概要
Railsアプリにて、ログイン機能を実装するために
gem 'devise'
を利用。
users/sign_upからユーザーの新規登録を行ったところエラーが発生した。エラー文
ArgumentError in Users::RegistrationsController#create wrong number of arguments (given 0, expected 1) app/controllers/users/registrations_controller.rb:13:in `create' def create @user = User.new(user_params) if @user.save redirect_to @user, notice: 'User was successfully created.' else render :new end
wrong number of arguments (given 0, expected 1)
は
引数が1つ渡されるはずなのに0になってますよ。ということでコントローラーでcreateアクションがうまくできていない。結論
has_secure_password
password_digest
を使っていたから。
devise
導入時はhas_secure_password
password_digest
を使ったセキュアパスワード設定は行わない。
代わりにencrypt_password
をテーブルカラムに追加することでセキュアパスワード設定ができる。今回の解決までの流れ
参考:http://ja.voidcc.com/question/p-zenkcgoo-cv.html
調べると
has_secure_password
がいらないという情報があったので、userモデルから消しました。すると、同じようにユーザーの新規登録をすると異なるエラーメッセージが出ました。
password_digest
についてエラーが出ている模様。ActiveRecord::NotNullViolation in Users::RegistrationsController#create PG::NotNullViolation: ERROR: null value in column "password_digest" violates not-null constraint DETAIL: Failing row contains (5, test, test@a.com, test@a.com, null, null, 2020-01-21 01:37:23.23543, 2020-01-21 01:37:23.23543, $2a$11$mFFmw7JD8nrrm3hbz/LUQeFwRPYjjBNKIRAjVuRBNXUM57v2JeeI6, null, null, null). : INSERT INTO "users" ("name", "email", "profile", "created_at", "updated_at", "encrypted_password") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id"
password_digest
はdevise
導入前にセキュアパスワード設定のために用意していたカラムです。
調べてみるとdevise
を使用するときはdevise
がpassword_digest
の代わりにencrypt_password
を作ってくれるので、password_digest`はいらないことがわかりました。確かに
devise
の導入を行っている際にコマンド$ rails generate devise userを実行し、作られるマイグレーションファイルに
encrypt_password
が入っていました。schema.rbclass AddDeviseToUsers < ActiveRecord::Migration[5.2] def self.up change_table :users do |t| ## Database authenticatable t.string :encrypted_password, null: false, default: "" (省略) end今回はこのままマイグレーション実行していたのですが、既にusersテーブルに
password_digest
カラムがあったため上書きされず、encrypted_password
は反映されてませんでした。
encrypted_password
について調べずにマイグレーション実行していたことを反省・・・ということで、
password_digest
カラムを削除してから、マイグレーションをやり直してエラーは解決しました。もう一度結論ですが、
devise
を利用してパスワードをハッシュ化し、セキュアパスワード設定をするにはカラムにpassword_digest
ではなくencrypt_password
を使うことになります。他にもusers/newでcreateされるユーザーは
devise
管理化の
controllers/users/registrations_controller.rbのnewやcreateメソッドに従って挙動するので、
controllers/users/users_controller.rbのnewやcreateメソッドは不要になるなど
devise
を実装することで不要になるものはいくつかあります。
- 投稿日:2020-01-21T22:38:40+09:00
[Welcome to nginx on the Amazon Linux AMI!]nginxサーバにアプリケーションをアップロードした時に起こるルーティングエラーの解決例
1.エラーの様子
まずエラーまでの流れですが、ローカル環境でエラーもなく、GitHubへのcommit,pushをし、EC2サーバー(nginx)上に自動デプロイが終わった後にElastic id(個人のipアドレスに紐付け済みの公開用ipアドレス)に接続したところ下記のような画面が表示されました。
2.どんなエラー?
自分が設定したアプリケーションのアドレスではなく、nginxのホームに接続してしまうというエラーになっています。
3.エラーの原因
ネットサーバーまでのルーティングの設定エラーです
見つけ方としては、エラーまでの流れで説明した通り、ローカル環境でエラーを出していないため、ルーティングの設定ミスだとわかります。
4.解決方法
ルーティングに関する箇所を調べて打ち忘れ打ち間違いを修正します。
具体的には下記の原因が考えられます①開発したファイルの中のconfig/locals/unicorn.rbの記載ミス
②config/deploy/production.rbの記載ミス
③config/deploy/deploy.rbの記載ミス
④nginxの設定の記載ミス(EC2サーバにログインして[ec2-user@ip-172-xx-xx-xxx ~]$ sudo vim /etc/nginx/conf.d/rails.conf
とコマンドを打つことで確認できます)そして今回筆者は④で下記のように設定していました。
<間違った設定>
よくよく見るとこの中の'sever_name'に余計な文字が入っており間違っています。
設定にはElastic idだけで良いので正しくは下記の通りとなるべきでした。
<正しい設定>
こちらを修正したところ、検索の箇所にElastic id(13.112.68.204)を打つことで正しいアプリケーションのサイトに飛ぶよう設定することができました。
※ここまでのルーティングのチェックでローカルのファイルに変更などが生じている可能性があるため、GitHubのcommit忘れの確認と、自動deploy(またはpull origine masterコマンド)を行っておきましょう。更新忘れてるかもと思ったら、この更新作業は何度コマンドしても大丈夫なのでとりあえず行ってみましょう。
何かの参考にしてください。
- 投稿日:2020-01-21T22:28:38+09:00
MVCとはなんなのか
Ruby on Rails初心者として、自分自身の理解を整理したいのでまとめたいと思います。
何か認識違いがあれば、ご指摘いただければ幸いです。MVCとは
UI(ユーザインタフェース)を持つソフトウエアのアーキテクチャの一種。
画面に表示する部分(UI)は、アプリケーション固有のデータや処理の扱いの性質が異なるため、画面の表示とアプリケーションのデータに関する部分を混ぜて記述してしまうと、コードが複雑化してしまい、保守性が悪くなってしまいます。そこで、アプリケーション固有のデータの部分、画面を表示させるUIの部分、この2つをつなぎ合わせる制御の部分の3つに分けて管理をしやすくしようというものです。
M(model)
アプリケーション固有のデータや処理の扱いの部分
・データベースへの保存、読み込み、永続化を担当する。V(View)
UIに関わる部分
・HTTPレスポンスの中身を実際に組み立てて、画面を表示する。C(Controller)
ModelとViewを統合的に制御する部分
・ブラウザからのリクエストを受けて適切なレスポンスを作成するための制御を行う。MVCのメリット
・それぞれが専門的な分野になるため、一つ一つの仕様変更がしやすくなる。
・分野ごとに得意な人が開発を進められる。まとめ
MVCアーキテクチャを使うことによって複雑化するコードをそれぞれの3つの分野に分けることで単純化し、管理しやすくすることで、それぞれが得意な分野に分かれて開発できるようになり、作業しやすい環境が生まれるということ(と感じました)。
- 投稿日:2020-01-21T22:01:08+09:00
docker環境で db:migrate:resetしたいとき( seed_fuも)
dbをリセットしたいとき
dockerを触り始めたばかりのときは停止させたdockerを再起動するのにも手こずりますので初歩的な手順。
大体rails のコマンド前にdocker-composeをつけるだけですが。docker-compose exec コンテナ名 bin/rails db:migrate:resetコンテナは停止させなくて良いです
なぜならそのコンテナに対してmigrateリセットするからですdocker-compose exec コンテナ名 bin/rails db:migratedocker-compose exec コンテナ名 bin/rails db:seed_fudocker-composeのときはymlファイルを参照するのでコンテナIDではなくコンテナ名を記述してください。
- 投稿日:2020-01-21T20:19:27+09:00
CodeCommit + CodeDeploy + CodePipelineでEC2にデプロイ~CodeDeployの設定~
目次 1. CodeCommitの設定 2. CodeDeployの設定(この記事) 3. CodePipelineの設定・デプロイ実行 AWSのCodeCommit、CodeDeploy、CodePipelineを組み合わせてEC2にデプロイするまでをまとめました。
この記事ではCodeDeployでデプロイアプリケーションを作成する手順を説明します。前提
- デプロイ先のEC2インスタンスは作成済みとします。
- ELB(ロードバランサー)はApplication Load Balancerを使用する想定とします。
- Ruby on Railsアプリケーションをデプロイする想定とします。
- EC2 : Amazon Linux2
CodeDeploy
EC2インスタンスやオンプレミスインスタンス、AWS Lambda、Amazon ECSに対するアプリケーションのデプロイを自動化するデプロイメントサービスです。
EC2に対するデプロイは無課金で実行できます。用語
- AppSpec file : デプロイの内容を定義したファイル。YAMLもしくはJSONで記述する。
- リビジョン : S3もしくはGithubにアップロードした、アプリケーションコードとAppSpec fileをバンドルしたアーカイブファイル。
デプロイ要件
CodeDeployのデプロイタイプは「インプレースデプロイ」と「Blue/Greenデプロイ」が選択でき、今回は「インプレースデプロイ」を選択します(デプロイタイプについては後ほど説明します)。
デプロイ作業中にロードバランサーのトラフィック制御は行いません。EC2へのインプレースデプロイは以下のフローで行われます。
- アプリケーションにAppSpec fileを含めたアーカイブファイルをAmazon S3、もしくはGithubにアップロード。
- アップロードしたリビジョンの情報を次のデプロイ対象としてCodeDeployに提供。
- デプロイ先EC2に常駐しているCodeDeployAgentプロセスがCodeDeployをポーリングして、デプロイ対象リビジョンの置き場所・デプロイ実施時期などの情報を取得する。
- 3で取得した情報に基づいて、EC2のCodeDoployAgentがS3やGithubからデプロイ対象リビジョンをpullして、AppSpec fileの手順に従ってデプロイを実行する。
準備
S3にリビジョンを置くバケットを作成
- Amazon S3コンソール(https://console.aws.amazon.com/s3/)を開きます。
- [バケットを作成する]を選択します。
- [バケット名]を入力して[バケットの作成]を選択します。
CodeDeployからEC2にアクセスためのサービスロールを作成
- IAMコンソール(https://console.aws.amazon.com/iam/)を開きます。
- ナビゲーションペインの[ロール]を選択し、[作成]を選択します。
- [ロールの作成]ページで[AWSサービス]を選択し、[このロールを使用するサービスを選択]リストからCodeDeployを選択します。
- [ユースケースの選択]でCodeDeployを選択し、[次へ]を選択します。
- アクセス権限ポリシーのを確認して[次へ]を選択します。
- [ロールの名前]にサービスロール名(例:AWSCodeDeployRole)を入力し、[作成]を選択します。
EC2からS3にアクセスするためのインスタンスプロファイルを作成
- IAMコンソール(https://console.aws.amazon.com/iam/)を開きます。
- ナビゲーションペインの[ポリシー]を選択し、[作成]を選択します。
- [JSON]タブに以下を貼り付けて[確認]を選択します。
{ "Version": "2012-10-17", "Statement": [ { "Action": [ "s3:Get*", "s3:List*" ], "Effect": "Allow", "Resource": "*" } ] }- [ポリシー名]に適当な名前を入力して[作成]を選択します。
- ナビゲーションペインで[ロール]を選択し、[作成]を選択します。
- [AWSサービス]を選択し、[このロールを使用するサービスを選択]リストからEC2を選択します。
- [ユースケースを選択]でEC2を選択し[次へ]を選択します。
- 先ほど作成したポリシーを選択し、[次へ]を選択します。
- [タグの追加]は何もせずに[次へ]を選択します。
- [ロールの名前]に適当なロール名を入力して[作成]を選択します。
EC2にCodeDeployAgentをインストール・起動
EC2にSSH接続して、下記コマンドを実行します。
$ sudo yum update # CodeDeployAgentはRubyで動作するので、Rubyをインストール $ sudo yum install ruby $ sudo yum install wget $ cd /home/ec2-user # このURLは東京リージョンのCodeDeployリソースキットファイルが置いてある場所です $ wget https://aws-codedeploy-ap-northeast-1.s3.ap-northeast-1.amazonaws.com/latest/install $ chmod +x ./install $ sudo ./install auto下のコマンドを叩いてCodeDeployAgentが起動していればOKです。
$ sudo systemctl status codedeploy-agentCodeDeployのデプロイアプリケーション作成・設定
デプロイアプリケーション作成
- CodeDeploy コンソール (https://console.aws.amazon.com/codedeploy) を開きます。
- ナビゲーションペインから[アプリケーション]を選択し、[アプリケーションの作成]を選択します。
- [アプリケーション名]を入力し、[コンピューティングプラットフォーム]で[EC2/オンプレミス]を選択します。
- [アプリケーションの作成]を選択します。
デプロイグループの作成
- 作成したデプロイアプリケーションのページの[デプロイグループ]タブを選択し、[デプロイグループの作成]を選択します。
- 必要項目を入力します。
- デプロイグループ名 : 任意の名前(例:SampleAppDeploymentGroup)
- サービスロール : 先に作成したAWSCodeDeployRole
- デプロイタイプ : インプレース
- 環境設定 : Amazon EC2 インスタンス(タググループでEC2インスタンスに使用したタグのキーと値を指定)
- デプロイ設定 : CodeDeployDefault.OneAtATime
- ロードバランサー : [ロードバランシングを有効にする]チェックボックスを外す
- 詳細-オプション : 任意で自動ロールバックの設定、アラームの設定が可能
- [デプロイグループの作成]を選択します。
デプロイタイプとデプロイ設定の選択肢と内容は下の通りです。
デプロイタイプ
インプレース Blue/Green 既存EC2インスタンスのアプリケーションを上書きする。 新規のEC2インスタンスを作成し、そちらにアプリケーションをデプロイする。アプリケーションが稼働したらロードバランサーのルーティングを新環境向けに切り替える。 デプロイ設定
OneAtATime HalfAtATime AllAtOnce 1度に可能な限り多くのインスタンスに対してデプロイを実施します。 1度に全体の半数のインスタンスに対してデプロイを実施します。 1度に1つのインスタンスに対してデプロイを実施します。 AppSpec file作成
AppSpec fileはデプロイの内容を定義するファイルです。
アプリケーションの配置先、パーミッション、デプロイのライフサイクルイベントで実行する処理を定義できます。
EC2へのインプレースデプロイで使用可能なライフサイクルイベントは5つあります。
- ApplicationStop
- アプリケーションの停止などで使用する。
- BeforeInstall
- ファイルの暗号化、現在のバージョンのバックアップ作成などで使用する。
- AfterInstall
- アプリケーションの設定、ファイルの許可の変更などに使用する。
- ApplicationStart
- アプリケーションの起動などで使用する。
- ValidateService
- デプロイが正常に完了したことの検証に使用する。
ApplicationStopイベントは注意が必要で、新しくデプロイするアプリケーションのAppSpec fileではなく、最後に正常にデプロイされたアプリケーションのAppSpec fileの内容で実施されます。従って初回デプロイ時には何も実行されません。
appspec.ymlを作成
appspec.ymlをアプリケーションソースコードのルートに作成し、デプロイの定義を書いてきます。
Railsアプリケーションのappspec.ymlの内容はこちらの記事が参考になります。appcpec.ymlversion: 0.0 # 0.0固定 os: linux # デプロイ先サーバーのOS files: # アプリケーションの配置場所 - source: / destination: /var/www/sample_app/current permissions: # 配置ディレクトリのパーミッション - object: /var/www/sample_app/current owner: {ユーザー名} group: {ユーザーグループ名} pattern: "**" mode: 775 type: - file - directory hooks: # デプロイのライフサイクルイベント ApplicationStop: - location: deployment_scripts/stop_application.sh runas: {シェルスクリプトの実行ユーザー名} AfterInstall: - location: deployment_scripts/install_gems.sh runas: {シェルスクリプトの実行ユーザー名} - location: deployment_scripts/compile_assets.sh runas: {シェルスクリプトの実行ユーザー名} - location: deployment_scripts/run_db_migrations.sh runas: {シェルスクリプトの実行ユーザー名} ApplicationStart: - location: deployment_scripts/start_application.sh runas: {シェルスクリプトの実行ユーザー名}デプロイタスクを作成
アプリケーションルートにdeployment_scriptsディレクトリを作成し、デプロイタスクのスクリプトを配置します。
デプロイタスクは任意のスクリプト言語で記述可能です。deployment_scripts/stop_application.sh#!/bin/bash source /home/{ユーザー名}/.bash_profile cd /var/www/sample_app/current # Pumaを停止 RAILS_ENV=production bundle exec pumactl -F config/puma.rb stopまとめ
これでCodeDeployを使用したデプロイの準備ができました。
今のままでもAWS CLIを使ってリビジョンをS3にアップロード → デプロイ実行を行うことはできますが、
デプロイの度に毎回手動でコマンドを叩くのは面倒です。次回で、CodePipelineを使用してCodeCommitのリポジトリが変更されたタイミングでデプロイを自動実行する仕組みを作っていきます。
参考記事
- 投稿日:2020-01-21T19:00:25+09:00
`create_or_find_by` はユニーク制約が定義されたテーブルで効いてくる
以下の記事で
find_or_create_by
とcreate_or_find_by
の違いについてコメントしたのですが、投稿元の方から反応が無かったので別記事として投稿することにしました「find_or_create_by」と「create_or_find_by」 の違い #Railsのコードを読んでみた - Qiita
find_or_create_by でできないカラムもcreate_or_find_byではできてしまう可能性があります。
例えば、Userモデルがあったとします。create_or_find_by ではcreateが先に実行されるため2つ同じようなデータが作られます。
find_or_create_byでは、findが先に実行されるため、検索結果が返され、同じデータは2つ作られることはありません。意識して使用しないとそのような動作になってしまうのですが、恐らく
create_or_find_by
のユースケースは DB で unique 制約が定義されたカラムに対しての実行だと思います。See also: 新メソッド: #create_or_find_by
find_or_create_by
の場合正常系
find_by
を実行し、レコードが取得できなかったcreate
を実行し、レコードが作成される異常系
処理 A と B が同時に実行されている場合
- A:
find_by
を実行し、レコードが取得できなかった- B: A と同じ条件で
find_or_create_by
を実行。find_by
でレコードが取得できなかった- A:
create
を実行し、レコードが作成される- B:
create
を実行し、レコードが作成される (実際には unique 制約でエラーになるはず)同じレコードが 2 つ出来てしまった! (実際には unique 制約でエラーになるはず)
▶
find_or_create_by
のfind
とcreate
の間に別のプロセスのcreate
が割り込む可能性があります。
create_or_find_by
の場合処理 A と B が同時に実行されている場合
- A:
create
を実行し、レコードが作成される- B: A と同じ条件で
create_or_find_by
を実行。create
で DB の unique によりレコードの作成に失敗- B:
find_by
を実行し、レコードが取得される▶ 別のプロセスが同時に
create_or_find_by
を実行しても安全に処理される
- 投稿日:2020-01-21T17:36:43+09:00
[rails] 投稿一覧にユーザー情報を表示
始めに
今回、プロゲートと違う方法で投稿一覧でユーザー情報を表示します。
プロゲートでrailsを終えてからよく、ツイッター風アプリを作成すると思います。
そこで、プロゲートのコードをコピペすることは誰でも出来ますが、
重要なのは理解して自分でコードを書くことだと思います。他のやり方で表示することが出来たので、参考やヒントになれば嬉しいです。
完成イメージ
※注:デザインは今回しません。また、分かりやすく理解してもらうためにユーザー情報は名前だけにします。前提
・usersテーブルと投稿用のテーブル(今回はcommentsテーブル)があること。
MVC(model/controller/view)の設定
controller設定
app/controllers/comments_controller.rbclass CommentsController < ApplicationController def index @comment = Comment.all.order(created_at: :desc) endこれはプロゲートでもでてきた投稿された順に上から表示しています。
modelの設定(※ここからプロゲートと違う!)
app/models/comment.rbclass Comment < ApplicationRecord belongs_to :user#追記 endbelongs_toとはなんぞや?って思った方いるかも知れません。
簡単に説明すると、userテーブルと投稿用のテーブル(今回はcommentsテーブル)の2つを紐付けてくれる仕組みのものです。
詳細はこちら!view設定
app/views/comments/index.html.erb<% @comment.each do |comment|%> <%= comment.user.name%> <%= link_to(comment.content,"/comments/#{comment.id}")%> <% end %>上記のコードの2行目の <%= comment.user.name%>は
先程belongs_to :userと紐付けているためこのように書くことが出来ます。
もし、紐付けが出来ていなかったらエラーが出ると思います。最後に
今回、belongs_to を使ってuserテーブルとcommentテーブルをアソシエーションしました。
もし、何か修正点とかございましたらコメント等
恐縮ですが、宜しくおねがいします
- 投稿日:2020-01-21T17:11:34+09:00
【Rails】enumを使用したセレクトボックスの実装とDBへの保存
はじめに
都道府県などのプルダウンメニューを作成する際、enumを使いました
これを使うことで都道府県などのデータをわざわざテーブルとして用意する必要がなくなります
便利だったのですが、DBへの保存の際に型が合わないなどの問題も発生したのでまとめておきます環境
Ruby: 2.5.1
Rails: 5.2.4実際の操作
実際の操作は以下のようになります
- 該当カラムをinteger型で作成
- モデルにプルダウンメニューで表示させるもの一覧を記載
- ビューで表示させるプルダウンの記述
- 入力したフォームの受け取り型を編集
1. 該当カラムをinteger型で作成
下記の場合は都道府県です
schema.rbt.integer :prefecture, null: false
2. モデルにプルダウンメニューで表示させるもの一覧を記載
models/address.rbenum prefecture: { 北海道:1,青森県:2,岩手県:3,宮城県:4,秋田県:5,山形県:6,福島県:7, 茨城県:8,栃木県:9,群馬県:10,埼玉県:11,千葉県:12,東京都:13,神奈川県:14, 新潟県:15,富山県:16,石川県:17,福井県:18,山梨県:19,長野県:20, 岐阜県:21,静岡県:22,愛知県:23,三重県:24, 滋賀県:25,京都府:26,大阪府:27,兵庫県:28,奈良県:29,和歌山県:30, 鳥取県:31,島根県:32,岡山県:33,広島県:34,山口県:35, 徳島県:36,香川県:37,愛媛県:38,高知県:39, 福岡県:40,佐賀県:41,長崎県:42,熊本県:43,大分県:44,宮崎県:45,鹿児島県:46,沖縄県:47 }
これで表示させる準備完了3. ビューで表示させるプルダウンの記述
address.html.haml= form.select :prefecture, Address.prefectures.keys, {prompt: "選択してください"}, class: "prefecture-select"
これでプルダウンメニューとして表示することはできるようになったんですが、binding.pryでparamsの中を見てみると"北海道"として値を取得してきてしまいました。
prefectureカラムはinteger型なのでこのままだとDBに登録できなくて困ります。
4. 入力したフォームの受け取り型を編集
色々調べた結果、以下のようにすると対応するvalueの値を取得できることがわかりました。
address.html.haml= form.select :prefecture, options_for_select(Address.prefectures), {prompt: "選択してください"}, class: "prefecture-select"しかし、これだと"1"という文字列なのでまだカラムに登録できません。
form.selectにおける入力値を数値として送れないかと思いましたが、やり方がわからなかったので、受け取る側で無理矢理数値型に変換することにしました。少々かっこ悪いですが、ストロングパラメータで数値型にした後にmergeしてます。
registrations_controller.rbdef address_params params.required(:address).permit(:postal_code, :city, :street, :building).merge(prefecture: params[:address][:prefecture].to_i) end
これで晴れてDBへ保存できるようになりましたただもっとスマートな方法がありそうな気がしてます
何か知ってる方いらっしゃいましたら教えていただけると嬉しいです
似たようなものにactive_hashというものがあります
gemをインストールする必要がありますが、こちらは数値型としてデータを取得できますし、ActiveRecordのメソッドも使えるみたいなので便利そうです参考記事
- 投稿日:2020-01-21T16:50:13+09:00
Rails 6+Grapeで作るAPIサーバーにDeviseトークン認証を付ける
はじめに
iOS・AndroidアプリやWebアプリをクライアントとしたAPIサーバーをRuby on Railsで実装するケースがあります。この記事では、Grape(REST APIフレームワーク)を利用して作るAPIサーバーにDevise(認証機能を提供するgem)を組み合わせ、アクセストークンを介した認証方式を実装する手順を紹介します。
同様の紹介事例について
Devise + Grape で認証付きAPIの実装 - Qiita
上記の記事では本記事と同様に、GrapeとDeviseに加えてトークン認証機能を付加するgemであるdevise_token_authを用いて実装する手法が紹介されています。ただし、
Token の更新に関してですが、今回の例では一度発行した Token は再度ログインするまで更新されません。
とあるようにdevise_token_authの本来の機能であるリクエストごとにアクセストークンを更新する仕様は有効になっていません。ここでは、上記記事のコードをベースに、Grapeとdevise_token_authの仲立ちをするgrape_devise_token_authを加えることでその点をクリアし、現行のRails 6で動作するサンプルを作ります。
前提条件
以降の手順解説では、Ruby 2.6.5とRails 6.0.2.1を使用することを想定しています。
Railsアプリを作成する
# rails new token-auth-sampleRailsアプリを新規作成して、以下のGemを追加します。
Gemfile.rbgem 'devise' gem 'devise_token_auth' gem 'grape' gem 'grape_devise_token_auth'$ bundle installDevise関連の環境設定を行う
# rails g devise:install # rails g devise_token_auth:install User auth新たに作成されたUserモデルのマイグレーションを行います。
# rails db:migrate基本部分のコード修正
app/controllers/application_controller.rbclass ApplicationController < ActionController::Base include DeviseTokenAuth::Concerns::SetUserByToken protect_from_forgery with: :null_session endprotect_from_forgeryは一般的なRailsアプリにおけるCSRF対策の仕組みに関する設定で、指定しない場合はPOSTリクエストを受け付けた際にActionController::InvalidAuthenticityTokenエラーとなります。これを無効化するには
protect_from_forgery with: :null_session
とします。app/models/user.rbclass User < ActiveRecord::Base # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable include DeviseTokenAuth::Concerns::User endUserモデルでは、
devise
メソッドで有効化する機能が列挙されていますが、:trackable
が含まれていたら外しておきましょう。前述のrails g devise_token_auth:install User auth
コマンドで作成されたマイグレーションでtrackable用のカラムが作成されておらず、サインインリクエストの際にNoMethodError (undefined method `current_sign_in_at' 〜
が発生するためです。(末尾の参考情報を参照)config/routes.rbRails.application.routes.draw do devise_for :users namespace :api do mount_devise_token_auth_for 'User', at: '/v1/auth' mount Api::Root => '/' end endAPIエンドポイント部分のコード追加
app/api/api.rbmodule Api class Root < Grape::API GrapeDeviseTokenAuth.setup! do |config| config.authenticate_all = true end mount V1::Root end endapi/v1/root.rbmodule V1 class Root < Grape::API version 'v1', using: :path format :json auth :grape_devise_token_auth, resource_class: :user helpers GrapeDeviseTokenAuth::AuthHelpers desc 'GET /api/v1/test' get 'test' do authenticate_user! { message: 'test', current_user_uid: current_user.uid, authenticated?: authenticated?, } end end endここまでで、以下のエンドポイントが利用可能になっています。
- ユーザーアカウント作成
POST http://localhost:3000/api/v1/auth
- サインイン
POST http://localhost:3000/api/v1/auth/sign_in
- サンプルGETリクエスト
GET http://localhost:3000/api/v1/test
動作確認
ローカルサーバーを起動しておきます。
# rails s => Booting Puma => Rails 6.0.2.1 application starting in development => Run `rails server --help` for more startup options Puma starting in single mode... * Version 4.3.1 (ruby 2.6.5-p114), codename: Mysterious Traveller * Min threads: 5, max threads: 5 * Environment: development * Listening on tcp://127.0.0.1:3000 * Listening on tcp://[::1]:3000 Use Ctrl-C to stopサインアップ(ユーザーアカウント作成)
まず、新しいユーザーを作成します。
cURLでのリクエスト例# curl --request POST \ --url http://localhost:3000/api/v1/auth \ --header 'content-type: application/x-www-form-urlencoded' \ --data email=user01@example.com \ --data password=user01 \ --data password_confirmation=user01サインアップリクエストのレスポンスヘッダーには、このユーザーの認証情報が含まれています。次のリクエストの際には認証情報として
access-token, client, uid
の値を指定します。GETリクエスト
次に、作成されたユーザーでGETリクエストを行います。認証情報を収めた3つのリクエストヘッダーを付加します。
cURLでのリクエスト例# curl --request GET \ --url http://localhost:3000/api/v1/test \ --header 'access-token: b638qOBLJ_sIEEJEiMC1ug' \ --header 'client: 1XcTtaq2uA3DK0qvY6qM9Q' \ --header 'uid: user01@example.com'レスポンスヘッダーには
access-token, client, uid
が含まれており、access-token
の値が更新されています。access-token
はリクエストを行うたびに新しい値と置き換わることから、毎回異なるアクセストークンを用いてアクセスする仕様で動作していることが分かります。おわりに
RailsとGrapeを使ったAPIプロジェクトで、Deviseの認証機能を用いてトークン認証を行う手順を紹介しました。devise_token_authのトークン更新機能が有効になっており、トークンの有効期間を絞れるという点で安全上望ましい仕様になっています。一方APIクライアントの方では、トークンの値が変更されるのに応じて書き換わったトークンを適切に更新管理することが大切になります。
参考情報
Devise + Grape で認証付きAPIの実装 - Qiita
https://qiita.com/travelist/items/ec0b08a9a19cbe9ec78bGrapeとdevise_token_authを併用する方法について
- Usage with Grape · Issue #73 · lynndylanhurley/devise_token_auth https://github.com/lynndylanhurley/devise_token_auth/issues/73
- How can I use this gem with Grape?・FAQ - devise-token-auth https://devise-token-auth.gitbook.io/devise-token-auth/faq#how-can-i-use-this-gem-with-grape
モデルでのTrackableオプションについて
- Remove Trackable option from generator by SugiKent · Pull Request #1362 · lynndylanhurley/devise_token_auth
https://github.com/lynndylanhurley/devise_token_auth/pull/1362- Why is Trackable option still active? · Issue #1356 · lynndylanhurley/devise_token_auth
https://github.com/lynndylanhurley/devise_token_auth/issues/1356
- 投稿日:2020-01-21T16:14:56+09:00
HerokuでRailsタスクを定期実行する方法(Google Apps Scriptのトリガーを使う方法)
HerokuにデプロイしたRailsアプリでタスクを定期実行する方法を紹介します。
ここで示す方法は、Google Apps Script (GAS)を使う方法です。結論を先に述べると以下のようにします:
1. Railsタスクを作成しておく
2. GASでHerokuのAPI経由でコマンドをpostする関数を書く
3. GASでスケジューラーを作成する(トリガーを作る)例として、Railsの場合を示していますが、GAS経由で「herokuのコマンドを定期実行する」という点がポイントなので、他の用途にも使えます。言語がRubyである必要性もありません。
この記事では、Railsの画像投稿アプリを例にとります。
スケジューラーを使って、24時間ごとにデータベースのテーブルのレコードを全て削除し、初期データの画像を投稿する方法を示します。対象読者:プログラミング初心者向け
- 私自身は転職活動中の未経験エンジニアです。内容には正確性を期しますが、間違いがあればご指摘くださると幸いです。
- 初学者がHerokuを使っていて、「Herkouでデータベースを定期的にリセットしたいが調べても方法が分からない」と疑問を持った際に、当記事の内容を少しでも活用してもらえればと思って書きました。
経緯 (経緯に興味のない人は飛ばしてください)
HerokuにRailsアプリをデプロイしていて、一定時間ごとにデータベースを初期化するために今回の方法に行き着きました。
前提として、
- Heroku上にアップローダーしたファイルは再起動の際に削除されます:Why are my file uploads missing/deleted? - Heroku Help
- また、HerokuのDynoは24時間ごとに再起動がかかるので、ファイルをアップロードして長時間保存することはできません(gitリポジトリに含まれるものは除きます): Dynos and the Dyno Manager | Heroku Dev Center
このような理由で、画像投稿機能のあるwebアプリをHerokuにデプロイした場合、画像の保存場所をAWS S3などに指定することはよくあると思います。
しかし、私のようにポートフォリオとしてアプリを公開したいだけなら、24時間ごとに投稿画像が削除されても問題ないと考える人もいるでしょう。
一方、アプリの体裁を整えるために、幾つかの画像だけはアプリの再起動の度に投稿された状態にしたいこともあるでしょう。今回の私がこのような状況でした。
これを解決するために以下のようにしました。
- Railsのタスクを作成する。このタスクの実行でテーブルを空にしてから適当な画像を投稿する(このための数枚の画像は、git管理する)
- Heroku APIを使い、httpリクエストでRailsタスクを実行する
- GASでhttpリクエストを定期実行する
これで何とか解決したので、そのぞれの方法を説明します。
前提となるサンプリアプリの作成
画像投稿機能
例として、carrierwaveで画像を投稿するサンプルアプリを以下のように作ります。
rails new sample-app rails db:create rails generate scaffold picture image:string rails db:migrate画像投稿用のgemとしてcarrierwaveをインストールします。
gemfileに追記してgem 'carrierwave'としてから
bundle install
とします。
carrierwaveの設定のインストールのため、rails g uploader image
とし、carrierwaveのuploaderをモデルにマウントします。app/models/picture.rbclass Picture < ApplicationRecord mount_uploader :image, ImageUploader endファイルをアップロードできるようにerbファイルに以下を追記します。
app/views/pictures/_form.html.erb<%= form.text_field :image %>続いて、投稿した画像を表示できるように以下を追記します。
app/views/pictures/index.html.erb<td><%= image_tag picture.image.to_s %></td>最低限の内容ですが、これで画像投稿アプリができました。
画像投稿するためのRailsタスクを作成
rails g task initialize_db
として、タスクのファイルを以下のように編集します。lib/tasks/initialize_db.rakenamespace :initialize_db do desc "初期データとしてpicturesテーブルにデータを入れる" task add_initial_blog: :environment do Picture.destroy_all Picture.create!([ {image: File.open("#{Rails.root}/public/samples/0apple.jpeg")}, {image: File.open("#{Rails.root}/public/samples/0cake.jpeg")} ]) end end初期データとして投稿するための画像データは、0apple.jpegと0cake.jpegです。
これを/public/samples/
フォルダに配置します。
これらをgit管理することで、herokuの再起動時に削除されずに済みます。これで、ターミナルで
rails initialize_db:add_initial_blog
とすれば、picturesテーブルのレコードを全て削除して、新規に2つの画像を投稿することができます。ひとまず、ここまでの内容をHerokuにデプロイ済みだとします。
このタスクをスケジューラーで定期的に実行するのが今回の目的となります。HerokuのコマンドをAPI経由で実行する
Herokuにアプリをデプロイする際や、ログを確認する際にはHeroku CLIを使って、コマンドを実行するのが一般的です。
しかし、コマンドの実行を自動化するにはAPIを使う方が(おそらく)便利です。
Heroku APIについては公式のリファレンスにまとまっています。APIでone-off Dynoを作り、コマンドを実行
今回は、API経由でコマンドを実行する方法に着目します。
公式によれば以下のようにします: Platform API Reference | Heroku Dev CenterPOST /apps/{app_id_or_name}/dynos今回はherokuのCLIで
heroku run rails initialize_db:add_initial_blog
と打つのをAPIで代替したいので、curlで以下のようにします。$ curl -n -X POST https://api.heroku.com/apps/$APP_ID_OR_NAME/dynos \ -d '{ "command": "heroku run rails initialize_db:add_initial_blog", }' \ -H "Content-Type: application/json" \ -H "Accept: application/vnd.heroku+json; version=3" -H "Authorization: Bearer $HEROKU_API_KEY"
$APP_ID_OR_NAME
と$HEROKU_API_KEY
については個々のアプリに応じて読み替えてください。Herokuの
$APP_ID_OR_NAME
と$HEROKU_API_KEY
の確認方法
$APP_ID_OR_NAME
を確認するにはCLIでheroku apps
と打ちます。
もしくは、アプリの公開URLがhttps://<$APP_ID_OR_NAME>.herokuapp.com/
のような形式になっているので、そこから読み取ることもできます。
$HEROKU_API_KEY
を確認するには、heroku auth:token
とCLIで打ちます。このトークンは1年しか有効ではないので、半永久的に使いたい場合には、heroku authorizations:create
としてトークンを生成してください:Getting Started with the Platform API | Heroku Dev CenterGASでスケジューラーを作成
他のスケジューラーではダメなのか
herokuで特定の処理を一定時間ごとに実行する代表的な方法はHeroku Schedulerというアドオンを使うものです。
しかし、Heroku Schedulerの使用にはクレジットカードの登録が必要であり、無料Dynoの枠を超えると課金される可能性もあるので、完全に無料の方法として、GASを使うことにしました。
他の方法としてClock ProcessesというHerokuの機能を活用する手もあります: Scheduled Jobs and Custom Clock Processes | Heroku Dev Center。Clock Processesはクレジットカード登録なしで使用できますが、追加のdynoを使うため、今回は見送りました。
GASなら無料でスクリプトの定期実行ができる
Googleドライブで使用できるGoogle Apps Scriptは、無料でスクリプトを定期実行できます。
実際には実行回数に制限がありますが、無料プランでも十分な回数です:Quotas for Google Services | Apps Script | Google Developers。
例えば、今回利用するURL Fetch callsでは一日あたり20000回使用できます。GASの環境設定
GASの実行環境を整えます。googleのアカウントを持っていれば、1分で完了します。
googleドライブで「Google Apps Script」というアプリを選択するだけです。初回はメニューに登録されていないので、「アプリを追加」からGoogle Apps Scriptを検索して、アプリを追加してください。
GASで定期実行するスクリプト
GASは、一部独自機能があるものの、文法はJavaScriptに準拠しています。
heroku APIをcurlで使用するためのコマンドをGASのコードに読み替えます。
結果だけ示すと、以下のようにrunHerokuTask関数を定義し、この関数を定期実行すればうまくいきます。function runHerokuTask() { runHerokuCommand("heroku run rails initialize_db:add_initial_blog"); } function runHerokuCommand(command) { var urlTemplate = "https://api.heroku.com/apps/%s/dynos"; var herokuToken = PropertiesService.getScriptProperties().getProperty("heroku_token"); var herokuAppName = PropertiesService.getScriptProperties().getProperty("heroku_app_name"); var herokuAuth = Utilities.formatString("Bearer %s", herokuToken); var url = Utilities.formatString(urlTemplate, herokuAppName); var headers = { "Content-type": "application/json", "Accept": "application/vnd.heroku+json; version=3", "Authorization": herokuAuth } var data = { "command": command } var options = { "method": "post", "payload": JSON.stringify(data), "headers": headers }; var response = UrlFetchApp.fetch(url, options); var text = response.getContentText(); Logger.log(text); }このコードでのポイントを幾つか説明します。
- トークンやアプリ名などは、プロパティから取り出す
UrlFetchApp.fetch
でhttpリクエストをするGASのコードをgithubで公開する場合、パスワードや環境依存の定数はコードに含めたくはありません。
そのため、GASの機能のプロパティサービスを活用します。プロジェクトのプロパティというところからスクリプトのプロパティで「キーと値のペア」を登録します。
PropertiesService.getScriptProperties().getProperty("キーの名前")
として、キーに紐付いた値を取り出します。またhttpリクエストには、UrlFetchAppを使います。
今回は、POSTメソッドなので、オプションが必要ですが、getメソッドであれば、UrlFetchApp.fetch("http://www.google.com/")
とするだけでwebサイトにアクセスできます。GASのスクリプトの定期実行
GASのスクリプトの定期実行には、トリガーを登録します。
これで、毎日、0~1時ごろに登録した関数が自動実行されます。
- 投稿日:2020-01-21T15:12:56+09:00
【Rails】ActiveRecordで関連テーブルのカラムでwhereまたは、orderする【ActiveRecord】
はじめに
表題の通り、ActiveRecordで関連テーブルのカラムでwhereまたは、orderする方法について書いていきます。
前提
UserモデルとPostモデルが1:Nで関連づけられており、さらにPostモデルとCommentモデルが1:Nで関連づけられている場合を前提とします。
基本的な書き方は変わらないので、適宜ご自身の状況に置き換えて使用してください。コード
# eager_loadでPostsにCommentsをjoinする posts = User.posts.eager_load(:comments) # whereで絞り込み posts.where('comments.body = ?', 'テスト') # orderで並び替え posts.order('comments.created_at desc')説明
まずはwhereやorderで使用したい関連テーブルをjoinします。
その後、
where('関連テーブル名.カラム名' 条件)
order('関連テーブル名.カラム名' desc or asc)
で絞り込み、または並び替えを行います。おわりに
今回はActiveRecordの書き方のみを書きましたが、実際にどんなクエリが発行されているのかも意識しておくといいかもしれません。
- 投稿日:2020-01-21T13:19:56+09:00
RailsのDB操作を行うコマンドまとめ
はじめに
DB操作を行うコマンドというのは
rails db:migrate
などのことです。
コマンドは数が多く、名前から想像しにくい(自分だけ?)ものもあったりするため、備忘録としてまとめておこうかと思います。最初はスカスカですが、少しずつ充実させていく予定です。
※見栄えも少しずつ整えていきます。。。■参考サイト(公式GitHub)
https://github.com/rails/rails/blob/v5.2.0/activerecord/lib/active_record/railties/databases.rake環境
- Rails 5.2.0
コマンド
コマンド 説明 備考 rails db:create データベースを作成 rails db:drop データベースを削除 rails db:migrate マイグレートを実行 rails db:migrate:reset データベースを作成し直した後にマイグレートを実行 rails db:reset DB再作成後、マイグレートを実行し、seedファイルからデータ作成 db:drop後にdb:setupを行っている。 rails db:setup DB作成後、マイグレートを実行し、seedファイルからデータ作成 マイグレーションファイルは使用せず、schema.rbからマイグレートを行う
- 投稿日:2020-01-21T13:12:30+09:00
既存のRailsアプリにVue.jsを導入する
環境
ruby 2.6.0
Rails 5.2.4.
Vue 2.6.11gem 'webpacker' のインストール
Gemfilegem 'webpacker', github: 'rails/webpacker'bundleyarn のインストール
$ brew install yarn $ yarn -vwebpacker のインストール
$ bin/rails webpacker:install $ bin/webpackの順に入力。
webpack 関連のファイルが作成・更新される。Vue.js のインストール
$ rails webpacker:install:vueこのコマンドを実行することで、
app/javascript/packs
配下にファイルが作成される。これでvueの導入は完了。
動作確認
viewの操作をしてみる
app/javascript/packs/hello_vue.jsimport Vue from 'vue/dist/vue.esm' #htmlを操作する場合は、 vue/dist/vue.esm をimport const app = new Vue({ el: '#hello', data: { message: "Test text" } })任意のview<div id="hello"> {{ message }} </div> <%= javascript_pack_tag 'hello_vue' %>Test textと表示されればOK。
<%= javascript_pack_tag 'hello_vue' %>でjsファイルの読み込みを行う。
- 投稿日:2020-01-21T11:33:43+09:00
Cloud9でRails 6.0のSeleniumとGoogle Chromeを使える設定しましょう!
みなさん、お疲れ様です!
Cloud9で元気いっぱいで新しいRails6アプリを作ろうと思っている方、
必ずテストも作りたいよね!もうグーグルクロームをインストールしていますよね? このバッシュスクリプトはめっちゃ便利です。
$ curl https://intoli.com/install-google-chrome.sh | bash
そしてSeleniumのシステムテストを稼働すると、このエラーはありますでしょうか?
$ rails test:system Run options: --seed 47710 # Running: E Error: WelcomeTest#test_visiting_the_index: Selenium::WebDriver::Error::UnknownError: unknown error: Chrome failed to start: exited abnormally (unknown error: DevToolsActivePort file doesn't exist) (The process started from chrome location /opt/google/chrome/google-chrome is no longer running, so ChromeDriver is assuming that Chrome has crashed.) test/system/welcomes_test.rb:5:in `block in <class:WelcomeTest>'気を落ち込まないように!
- グーグルのバージョンを確認してください
$ google-chrome-stable -version Google Chrome 79.0.3945.130
- 正しいchrome-webdriverをダウンロードして、インストールします。
https://chromedriver.chromium.org/downloads
で自分のバージョンをダウンロードしてください。例えば今の場合、79が必要ね$ wget -N https://chromedriver.storage.googleapis.com/79.0.3945.36/chromedriver_linux64.zip $ unzip chromedriver_linux64.zip $ sudo mv -f chromedriver /usr/local/bin/chromedriver $ sudo chown root:root /usr/local/bin/chromedriver $ sudo chmod 0755 /usr/local/bin/chromedriver $ chromedriver --version ChromeDriver 79.0.3945.36 (3582db32b33893869b8c1339e8f4d9ed1816f143-refs/branch-heads/3945@{#614}) // OK!!!!!!
- Railsのシステムテスト用のオプションを設定します
/test/application_system_test_case.rbrequire "test_helper" class ApplicationSystemTestCase < ActionDispatch::SystemTestCase driven_by :selenium, using: :chrome, screen_size: [1400, 1400], options: { args: %w[headless disable-gpu] } end
- 確認!
$ rails test:system Run options: --seed 49276 # Running: 2020-01-21 01:54:40 WARN Selenium [DEPRECATION] :args or :switches is deprecated. Use Selenium::WebDriver::Chrome::Options#add_argument instead. Capybara starting Puma... * Version 4.3.1 , codename: Mysterious Traveller * Min threads: 0, max threads: 4 * Listening on tcp://127.0.0.1:41043 . Finished in 1.324751s, 0.7549 runs/s, 0.7549 assertions/s. 1 runs, 1 assertions, 0 failures, 0 errors, 0 skipsまあ後でdeprecationsの問題に考えましょうね、
とりあえず稼働かどうか確認してください!いかがでしたか?問題なかった?コメント、煽りはコメントに書いてください!
- 投稿日:2020-01-21T10:38:10+09:00
WebMockを使って外部API接続をスタブ化する
概要
APIはJavaで実装して、Javaから返ってきたjsonをRailsで受け取ってRails側でそのjsonデータを表示するという流れにしたく、Railsの実装をしている時のテストや、いちいちJavaを起動させなくていいようにスタブ化したのが目的です。
Rails開発でWebMockを使ってAPIアクセスをスタブ化するからのコードを引っ張ってきただけなので、リンク先の解説みた方が断然わかりやすいです。
実際のコード
api_stub.rbmodule ApiStub require 'webmock' WebMock.enable! # アプリケーションコードに`call_get_api`という名称の外部API呼び出し実装を含むメソッドがあることして、ここで同名のメソッドを作成してstub登録します。 def call_get_api WebMock.stub_request(:any, "http://www.example.com/").to_return( body: File.read("#{Rails.root}/test/fixtures/stub_api_response.json"), status: 200, headers: { 'Content-Type' => 'application/json' }) super # アプリケーションコードの実装を呼び出す end endapi_module.rbmodule ApiModule require_relative 'api_stub' prepend ApiStub if ENV["APIMODE"] == "mock" && Rails.env.development? def call_get_api # ここに本来の外部API呼び出しの実装が入る end endapi_client.rbclass ApiClient require_relative 'api_module' include ApiModule endweb_controller.rbclass WebController < ApplicationController require './lib/externals/api_client' require 'net/http' def fetch client = ApiClient.new client.call_get_api res = Net::HTTP.get("www.example.com", "/") @result = JSON.parse(res) end end脱線 スタブとモックの違い
スタブは受信メッセージのテストのために使うためのもの。
モックは送信メッセージのテストのために使うもの。参照
Rails開発でWebMockを使ってAPIアクセスをスタブ化する
Ruby on RailsでWebMockを利用する
- 投稿日:2020-01-21T08:32:56+09:00
Rails 6ではsend_data/send_fileメソッド呼び出し時にERB::Util.url_encodeは不要です
Rails 6にアップグレードすると発生する問題
Railsでファイルダウンロード機能を実装するときは
send_data
メソッドやsend_file
メソッドがよく使われます。
このとき、ファイル名に日本語(正確には非ascii文字)が含まれていると、IEやEdgeで文字化けします。
そのため、Rails 5.2以前では以下のようにERB::Util.url_encode
メソッドを使って文字化けを防いでいました。class FooController < ApplicationController # ... def download # ... # Rails 5.2以前ではurl_encodeをかけないと、IEやEdgeでダウンロードしたときに # `縺ォ縺サ繧薙#.txt`のようなファイル名になってしまっていた send_data(your_data, filename: ERB::Util.url_encode('にほんご.txt'), disposition: 'attachment') end endしかし、RailsアプリケーションをこのままRails 6にアップグレードすると、再びファイル名が文字化けします。
(IEやEdgeのみならず、Chrome等でも文字化けします)# Rails 5.2でダウンロードしたときのファイル名 にほんご.txt # Rails 6.0でダウンロードしたときのファイル名 %E3%81%AB%E3%81%BB%E3%82%93%E3%81%94.txt原因
これはRails 6でファイル名がデフォルトでエンコードされるようになったのが原因です。
解決策
Rails 6ではデフォルトでエンコードされるので、
ERB::Util.url_encode
を挟まずにsend_data
メソッドやsend_file
メソッドを呼び出してください。-send_data(your_data, filename: ERB::Util.url_encode('にほんご.txt'), disposition: 'attachment') +send_data(your_data, filename: 'にほんご.txt', disposition: 'attachment')こうすれば、どのブラウザでも文字化けせずに日本語のファイル名でダウンロードすることができます。
- 投稿日:2020-01-21T08:19:38+09:00
カラムを追加してpgからschemaにdumpさせてみました
記録用
railsでgenerate migrationコマンドを使って、自動的に作成していましたが、その方法で作成しない方針だったため、migrationファイルからDBにカラムを追加したり、コメントを入れたり、schemaディレクトリにバックアップファイルを作成してその中にdumpさせました。
完全に理解していないですが、記録用と手順ややったことを忘れないためにも残しておきます。
migretionファイルでカラムの追加
カラムの追加
ALTER TABLE テーブル名 ADD COLUMN カラム名 データ型 型名 ; COMMENT ON TABLE テーブル名 IS 'コメント';SQLで確認
\d (テーブル名) \d+ でコメントも確認することができる列 | 型 | 修飾語
↑のような形式で追加したカラムを確認することができる
schemaファイルにdumpするとき
データベースを指定してダンプする場合は、pg_dumpを使用する
pg_dump DB名 --schema-only -U username -h host -p port -t 'table' > file(バックアップファイル).sqldumpのオプション内容
-- schema-only
データ定義(スキーマ)のみをダンプし、データはダンプしません。-U username
指定したユーザとして接続します。-h
000.000.000.000-p
ポート番号-t table
tableに一致するテーブル(またはビューやシーケンス)のみをダンプします。table > file.sql
dump先を指定このようにオプションで絞っていきました。
schemaファイルにdumpできていることを確認することができました。
次回からこの手順で作成していきます。参考文献
https://www.postgresql.jp/document/9.4/html/ddl-alter.html
- 投稿日:2020-01-21T07:20:46+09:00
【Rails】 DataTables 動的にカラムを変更する方法
はじめに
Railsアプリケーションで DataTables を使う方法を以前にまとめさせていただきました。
DataTables を使ったテーブルのカラムを動的に変更したい需要があると思いますが、まとめられている記事を見かけませんでしたので、こちらにてまとめさせていただきます。
この方法を理解していれば、開発時間を極端に減らして高機能なテーブルを提供することができます。なお、今回の方法は少し強引にカラムを動的に変更しています。
もし、もっといい方法があるということをご存知の方はコメントをいただければ嬉しいです。動的にカラムを変更する方法
前提条件
下記リンクにてDataTablesを実装していること。
このリンク先のコードを元にして、動的にカラムを変更する方法をこちらの記事にて特記したいと思います。
- 【Rails】DataTables 実装方法
値を変更する方法
動的にカラムを変更するには、
users.coffee
のコードを変更することによって可能です。ここでは一例として、id が 3 のときに"あほ"を表示するコードを書いています。
app/assets/javascripts/users.coffee$ -> # *** 省略 *** # user_table へカラムを追加する user_table.setColumns([ # 以下に注目 { data: 'id', title: 'ユーザID', width: '5%' # 以下を追記 render: (data, type, row) -> # data / type / row にどんなデータが入っているか確認。 console.log data console.log type console.log row if data == "3" "あほ" }, { data: 'username', title: 'ユーザ名', width: '25%' }, { data: 'name', title: '名前', width: '30%' }, { data: 'created_at', title: '登録日時', width: '20%' }, { data: 'updated_at', title: '更新日時', width: '20%' }, ]) # *** 省略 ***フォントを変更する方法
つづいて、フォントを変更する方法を紹介します。
一例として、id が 3 のときに赤色の文字で"あほ"と表示するコードを書いています。
htmlタグを使ってそこにcssを埋め込んでいるだけとなります。(少し強引かもしれません。。)app/assets/javascripts/users.coffee$ -> # *** 省略 *** # 以下に注目 { data: 'id', title: 'ユーザID', width: '5%' # 以下を追記 render: (data, type, row) -> if data == "3" "<span style='color: red;'>あほ</span>" }, # *** 省略 ***Bootstrap のレイアウトを導入する
最後に応用技として、 Bootstrap のレイアウトを導入する方法を紹介します。
一例として、id が 3 のときに赤色の文字で"あほ"と表示するコードを書いています。
応用と書きましたが、htmlタグを使ってbootstrapで使用できるclassを付与しているだけとなります。app/assets/javascripts/users.coffee$ -> # *** 省略 *** # 以下に注目 { data: 'id', title: 'ユーザID', width: '5%' # 以下を追記 render: (data, type, row) -> if data == "3" "<div><center><span class='label label-default'>あほ</span></center></div>" }, # *** 省略 ***まとめ
いかがでしょうか。Railsなので動的に値を変更したい需要はかなりあるかと思いますが、DataTables だとドキュメントが英語で読みづらいし、あまり柔軟性がないと考える方もいると思います。
少し強引ではありますが、このような感じで色々な応用をすることも可能ですので、ご自身で色々と試してみるのもいいかもしれません。
- 投稿日:2020-01-21T07:17:25+09:00
[bundler: command not found: unicorn_rails Install missing gem executables with `bundle install]AWSのEC2サーバ上でRailsに追加したgemfileが反映されない時の解決例
このエラーの原因で考えられること
local環境でしかgemfileが反映されていないことが考えられます。
具体的には下記のことにより起こっていると考えられます。1.rbenvのrehashし忘れ
2.bundlerの入れ忘れ
3.githubへの反映し忘れ(commitとpushのし忘れ)解決方法
1.rbenvのrehashし忘れ
rbenv(rubyの環境構築)について更新をすれば解決します
EC2サーバー上で下記のコマンドを入力してください[ec2-user@ip-xxx-xx-xx-xxx chat-space$ gem install bundler -v 2.0.2]$rbenv rehash2.bundlerの入れ忘れ
EC2サーバー上にbundlerをインストールし、再度bundle installすることで解決します
バンドラーのバージョンはご自分のプロジェクトファイルのものと合わせるためローカルサーバー上でバージョンを調べたのち、EC2サーバー上で下記のコマンドを入力してくださいNeverland:chat-space kontatomoya$ bundler -v #プロジェクトのローカルディレクトリで bundler -v でbundleのバージョンを調べられます(筆者の場合は"Bundler version 2.0.2"が帰ってきたのでver2.0.2で以下を進めています) [ec2-user@ip-xxx-xx-xx-xxx chat-space]$ gem install bundler -v 2.0.2 [ec2-user@ip-xxx-xx-xx-xxx chat-space$ gem install bundler -v 2.0.2]$ bundle install #bundlerをインストールし、bundle installしてます3.GitHubへの反映し忘れ(commitとpushのし忘れ)
EC2サーバーにプロジェクトを保存するには、GitHub上のデータを受け取りコピーという流れとなるため、GitHub上のデータに反映した後のデータをgit cloneしないとEC2サーバー上でも反映されません。そのため下記の手順に従って最新ファイルを反映させましょう。
①GitHub Desktopでcommitとpushし、GitHub上のデータに反映させましょう。
やり方はここでは説明しませんが簡単です。わからない人は下記などでやり方を確認してみましょう。(公式の使用方法解説ページにリンクしてます。)
②EC2サーバーのファイルに反映させましょう
今はEC2のプロジェクトが更新されていない状態なので、pullコマンドで更新を行いましょう[ec2-user@ip-xxx-xx-xx-xxx chat-space$ gem install bundler -v 2.0.2]$ git pull origin master #EC2は表示だけが必要となるため反映させるのはmasterとしましょう③bundle installを行う
このプロジェクトのダウンロードができただけで、インストールはできていないので最後に忘れずbundle installしましょう[ec2-user@ip-xxx-xx-xx-xxx chat-space$ gem install bundler -v 2.0.2]$ bundle installこれでこのエラーは解消されます。
- 投稿日:2020-01-21T06:26:52+09:00
[Ruby on Rails] resourcesの使い方について
resourcesに慣れないので理解することを目的に個人のメモとして残します
環境
OS:Windows10
Rubyバージョン:ruby 2.5.3p105 (2018-10-18 revision 65156) [x64-mingw32]
Railsバージョン:Rails 5.2.4.1resourcesの使い方
routes.rbRails.application.routes.draw do resources :tests end上記のようにroutes.rbでモデルを選んで宣言
resourcesの機能
- 複数のCRUD処理に関わるルーティングを設定する(下記の表参照)
- いくつかのURLと同値である簡潔な文字列が使用できる
URLと同値な文字列 httpメソッド URL コントローラー アクション tests GET /tests tests index tests POST /tests tests create new_test GET /tests/new tests new edit_test GET /tests/:id/edit tests edit test GET /tests/:id tests show test PATCH /tests/:id tests update test PUT /tests/:id tests update test DELETE /tests/:id tests destroy 同じ文字列でもメソッドが異なるため判別されると考えられる
RESTfulについて
勉強中。随時加筆
- 投稿日:2020-01-21T02:14:41+09:00
rails+froalaエディタ使用の注意
表示させる部分にはクラスに'fr-view fr-element'を付ける
froalaエディタは、とても高機能のエディタである。
ブログアプリで使用するとき、form画面ではとくに問題ないが、その内容を表示させるときに思うように表示されないときがある。
それは、form画面ではデフォルトで<div class="fr-view fr-element">で囲まれているが、表示させるときはない。
画像の左寄せ、中央寄せ、右寄せの機能がうまく表示されないのはこのせいである。
なので表示させたいページで同じようにdivで囲めばよい。
- 投稿日:2020-01-21T01:53:53+09:00
Rails6 アプリからメールを送信する デプロイ環境編
目的
- Rails6で作成したアプリをデプロイした時に当該アプリからメールを送信する方法をまとめる。
前提条件
- 下記の方法、またはそれに準ずる方法でローカル環境にてテストメールが送信できる状態のRailsアプリが存在すること。
- メール送信を行いたいアプリがすでにherokuでデプロイされていること
作業期待値
- herokuでデプロイしているアプリからメールが送信されるようにする。
- メール送信内容はRails6 アプリからGmailのメールサーバからメールを送信する ローカル環境編と変わらずにクラウドサーバであるheroku側の設定を主に行う。
- herokuでのデプロイ方法の基本は下記の本を参考に構築を行なった。個人開発の公開時のノウハウが詰まった本なのでこれから勉強する人はバイブル的に持っておくことをおすすめする。本件のクリティカルな解決法は記載されていないが非常に素晴らしい本である。(アフィリエイトリンクでは無いので安心してください)
作業前にちょっと聞いてほしいこと
- 前回のRails6 アプリからGmailのメールサーバからメールを送信する ローカル環境編を実施された方なら簡単である。
- あまり難しいことを考えずに実施していただきたい。
- ローカル開発環境だとGmailのサーバを使用してメールを送信したが、heroku上のアプリだとSendGridというものからメールを送信する。(他にも方法があるが比較的簡単なので今回はこの方法を採用した。)
考え方
- ローカル開発環境のメールサーバ設定はheroku環境だとそのまま流用できないので専用のメールサーバ設定が必要となる。
- heroku上のアプリからメールを送るには専用の設定ファイルが必要と覚えておいてほしい。
- デプロイ中は前述した専用の設定ファイルから自動で設定が読まれる。
- 下記に前述の内容の簡易図を記載する。
作業概要
- SendGridの有効化とAPI鍵作成
- デプロイアプリとAPI鍵の紐付け
- メール確認
作業詳細
SendGridの有効化とAPI鍵作成
下記コマンドを実行してSendGridを有効化する。
$ heroku addons:create sendgrid:starterherokuにログインする。
デプロイしているアプリ名をクリックする。
下記画面になったら確認用のメールアドレスを記入しメールを送るボタンをクリックする。(本メールアドレスはアプリからの送受信には全く関係ない。あくまでSendGridの確認用のアドレスである。)
受信ボックスに下記のようなメールが届いていることを確認して、「Confirm Email Address」をクリックする。
「API Key Name」に認識しやすい任意のAPI鍵の名前を入力、(自分がわかるならなんでもOK)「API Key Permissions」は「Full Accesss」を選択し内容を確認後「Create & View」をクリックする。
デプロイアプリとAPI鍵の紐付け
下記コマンドを実行してAPI鍵をherokuの変数に格納する。(本作業で自動的にメールサーバ用のパスワードとユーザ名が自動生成される)
$ heroku config:set SENDGRID_API_KEY=XXXXXXXXXXXXXXXXXXXX6NDlg.J1bMNO_jbeepuH8LOYFwkMKFcOKoQ5vZ8z9axkzMyWUメールサーバの設定
- 下記に存在する送信先を指定するファイル
product.rb
をエディタで開く
- アプリ名フォルダ/config/environments
- product.rb
ファイル
product.rb
を下記のように修正してSentGridからメールを送信できるようにする。(下記のように設定すると、先の作業で登録したAPI鍵からuser_nameとpasswordが自動生成されそれぞれ環境変数SENDGRID_USERNAMEとSENDGRID_PASSWORDに格納され、それを読んでメールを送るようになる。)Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. # Code is not reloaded between requests. config.cache_classes = true # Eager load code on boot. This eager loads most of Rails and # your application in memory, allowing both threaded web servers # and those relying on copy on write to perform better. # Rake tasks automatically ignore this option for performance. config.eager_load = true # Full error reports are disabled and caching is turned on. config.consider_all_requests_local = false config.action_controller.perform_caching = true # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). # config.require_master_key = true # Disable serving static files from the `/public` folder by default since # Apache or NGINX already handles this. config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? # Compress CSS using a preprocessor. # config.assets.css_compressor = :sass # Do not fallback to assets pipeline if a precompiled asset is missed. config.assets.compile = false # Enable serving of images, stylesheets, and JavaScripts from an asset server. # config.action_controller.asset_host = 'http://assets.example.com' # Specifies the header that your server uses for sending files. # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX # Store uploaded files on the local file system (see config/storage.yml for options). config.active_storage.service = :local # Mount Action Cable outside main process or domain. # config.action_cable.mount_path = nil # config.action_cable.url = 'wss://example.com/cable' # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ] # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. # config.force_ssl = true # Use the lowest log level to ensure availability of diagnostic information # when problems arise. config.log_level = :debug # Prepend all log lines with the following tags. config.log_tags = [ :request_id ] # Use a different cache store in production. # config.cache_store = :mem_cache_store # Use a real queuing backend for Active Job (and separate queues per environment). # config.active_job.queue_adapter = :resque # config.active_job.queue_name_prefix = "eveyDayStudy_production" config.action_mailer.perform_caching = false # Ignore bad email addresses and do not raise email delivery errors. # Set this to true and configure the email server for immediate delivery to raise delivery errors. # config.action_mailer.raise_delivery_errors = false # Enable locale fallbacks for I18n (makes lookups for any locale fall back to # the I18n.default_locale when a translation cannot be found). config.i18n.fallbacks = true # Send deprecation notices to registered listeners. config.active_support.deprecation = :notify # Use default logging formatter so that PID and timestamp are not suppressed. config.log_formatter = ::Logger::Formatter.new # Use a different logger for distributed setups. # require 'syslog/logger' # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name') if ENV["RAILS_LOG_TO_STDOUT"].present? logger = ActiveSupport::Logger.new(STDOUT) logger.formatter = config.log_formatter config.logger = ActiveSupport::TaggedLogging.new(logger) end # Do not dump schema after migrations. config.active_record.dump_schema_after_migration = false # Inserts middleware to perform automatic connection switching. # The `database_selector` hash is used to pass options to the DatabaseSelector # middleware. The `delay` is used to determine how long to wait after a write # to send a subsequent read to the primary. # # The `database_resolver` class is used by the middleware to determine which # database is appropriate to use based on the time delay. # # The `database_resolver_context` class is used by the middleware to set # timestamps for the last write to the primary. The resolver uses the context # class timestamps to determine how long to wait before reading from the # replica. # # By default Rails will store a last write timestamp in the session. The # DatabaseSelector middleware is designed as such you can define your own # strategy for connection switching and pass that into the middleware through # these configuration options. # config.active_record.database_selector = { delay: 2.seconds } # config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver # config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session end↓修正
Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. # Code is not reloaded between requests. config.cache_classes = true # Eager load code on boot. This eager loads most of Rails and # your application in memory, allowing both threaded web servers # and those relying on copy on write to perform better. # Rake tasks automatically ignore this option for performance. config.eager_load = true # Full error reports are disabled and caching is turned on. config.consider_all_requests_local = false config.action_controller.perform_caching = true # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). # config.require_master_key = true # Disable serving static files from the `/public` folder by default since # Apache or NGINX already handles this. config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? # Compress CSS using a preprocessor. # config.assets.css_compressor = :sass # Do not fallback to assets pipeline if a precompiled asset is missed. config.assets.compile = false # Enable serving of images, stylesheets, and JavaScripts from an asset server. # config.action_controller.asset_host = 'http://assets.example.com' # Specifies the header that your server uses for sending files. # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX # Store uploaded files on the local file system (see config/storage.yml for options). config.active_storage.service = :local # Mount Action Cable outside main process or domain. # config.action_cable.mount_path = nil # config.action_cable.url = 'wss://example.com/cable' # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ] # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. # config.force_ssl = true # Use the lowest log level to ensure availability of diagnostic information # when problems arise. config.log_level = :debug # Prepend all log lines with the following tags. config.log_tags = [ :request_id ] # Use a different cache store in production. # config.cache_store = :mem_cache_store # Use a real queuing backend for Active Job (and separate queues per environment). # config.active_job.queue_adapter = :resque # config.active_job.queue_name_prefix = "eveyDayStudy_production" config.action_mailer.perform_caching = false config.action_mailer.delivery_method = :smtp config.action_mailer.perform_deliveries = true config.action_mailer.smtp_settings = { :enable_starttls_auto => true :address => 'smtp.sendgrid.net', :port => 587, :domain => 'herokuapp.com', :authentication => :plain, :user_name => ENV['SENDGRID_USERNAME'], :password => ENV['SENDGRID_PASSWORD'], } # Ignore bad email addresses and do not raise email delivery errors. # Set this to true and configure the email server for immediate delivery to raise delivery errors. # config.action_mailer.raise_delivery_errors = false # Enable locale fallbacks for I18n (makes lookups for any locale fall back to # the I18n.default_locale when a translation cannot be found). config.i18n.fallbacks = true # Send deprecation notices to registered listeners. config.active_support.deprecation = :notify # Use default logging formatter so that PID and timestamp are not suppressed. config.log_formatter = ::Logger::Formatter.new # Use a different logger for distributed setups. # require 'syslog/logger' # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name') if ENV["RAILS_LOG_TO_STDOUT"].present? logger = ActiveSupport::Logger.new(STDOUT) logger.formatter = config.log_formatter config.logger = ActiveSupport::TaggedLogging.new(logger) end # Do not dump schema after migrations. config.active_record.dump_schema_after_migration = false # Inserts middleware to perform automatic connection switching. # The `database_selector` hash is used to pass options to the DatabaseSelector # middleware. The `delay` is used to determine how long to wait after a write # to send a subsequent read to the primary. # # The `database_resolver` class is used by the middleware to determine which # database is appropriate to use based on the time delay. # # The `database_resolver_context` class is used by the middleware to set # timestamps for the last write to the primary. The resolver uses the context # class timestamps to determine how long to wait before reading from the # replica. # # By default Rails will store a last write timestamp in the session. The # DatabaseSelector middleware is designed as such you can define your own # strategy for connection switching and pass that into the middleware through # these configuration options. # config.active_record.database_selector = { delay: 2.seconds } # config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver # config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session endメール確認
- 下記のメール送信トリガーコードが記載されているコントローラが実行されるような操作を行う
NoticeMailer.greeting.deliver_now
- Rails6 アプリからGmailのメールサーバからメールを送信する ローカル環境編の対応で筆者の環境では
http://localhost:3000/posts/index/:id
にアクセスした時にメールが送信されるようにトリガーコードを設置している。- 筆者の場合herokuのパスに置き換え
https://study-record.herokuapp.com/posts/index/:id
にアクセスしエラーが出ないことを確認する。- テストメール送信先アドレスを確認し下記のようなメールを受信していることを確認する。
![]()
- 投稿日:2020-01-21T01:31:39+09:00
Rails SQliteからmysqlへ変更(途中から)
アプリ作成後にmysqlに変更する方法
MySQLを起動して接続の確認
$ mysql.server start起動後、接続できるか確認
mysql -u root -pRailsで利用するユーザーを作成します。
create user ユーザー名@'localhost' identified by 'パスワード'; 例 (create user railsuser@'localhost' identified by 'railspass';)ユーザーが作成されたことが確認
select User,Host from mysql.user;権限の付与を行います
grant all on *.* to ユーザー名@'localhost';設定ファイルの変更
config/database.ymldefault: &default adapter: mysql2 encoding: utf8 pool: 5 username: ユーザー名 password: パスワード host: localhost development: <<: *default database: sample_ec #データベース名Gemfileに記述
gem 'mysql2'$ bundlemysqlにDBの追加とテーブル作成
$ bundle exec rake db:create $ bundle exec rake db:migrateこれで完了
mysqlユーザーの削除方法
mysql> drop user ユーザー名@'localhost';最初からmysqlを使用する場合
rails new アプリケーション名 -d mysql
- 投稿日:2020-01-21T01:15:37+09:00
Webサービスをインターネットに公開する(cloud9からHerokuにデプロイ)
Herokuについて
- https://jp.heroku.com
- Paas(Platform as s Service)と呼ばれるクラウドサービス
- 元々、Rubyのアプリケーションをホスティングするサービス
- PHP等、他の言語にも対応
デプロイの準備
設定箇所
1. Gemfile
2. config/database.yml
3. config/environments/production.rb
4. config/routes.rb1.Gemfile
Gemfileにあるgem'sqlite3'を切り取って group :development, :test doに貼り付ける
gem 'pg', '~> 0.18.4'を追加するGemfilegroup :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] gem 'sqlite3' endGemfilegroup :production do gem 'pg', '~> 0.18.4' endbundle install --without productionを実行する(production以外のgemをインストールする)
bundle install --without production2.config/database.yml
sqliteはproduction環境では使わないので、database: db/production.sqlite3を削除し、下記のように記述する
config/database.ymlproduction: <<: *default adapter: postgresql encoding: unicode3.config/environments/production.rb
config.assets.compile = falseをtrueに書き換える
config/environments/production.rb# Do not fallback to assets pipeline if a precompiled asset is missed. config.assets.compile = true4.config/routes.rb
rootページ(例:root 'questions#index')が設定されているか確認する(設定されていないとエラーになってしまう)global configの設定
個人の識別情報を登録する
$ git config --global user.name "名前" $ git config --global user.email メールアドレスgitの設定
ソースコードのバージョンを管理するツール
gitリポジトリの新規作成
$ git init管理するファイルを選択する
※git ignoreファイルで書かれたものは登録しない
cloud9の設定アイコンからShow Hidden Filesにチェックが入っているか確認する$ git add -Acommitという登録処理をする
$ git commit -m "Initial commit"Heroku Cliのインストール
Heroku Cli:cloud9などからHerokuを操作するためのツール
cli(Command Line Interface)ファイルをダウンロードする
https://devcenter.heroku.com/articles/heroku-cliのOther installation methodsを使う
(TarballsのLinux(x64)のリンクをコピー)$ curl -OL https://cli-assets.heroku.com/heroku-linux-x64.tar.gz圧縮ファイルなので、解凍する。
tar zxf heroku-linux-x64.tar.gzherokuフォルダを/user/localフォルダに移動する
/usr/local:一般的にシステム管理者が自分でコンパイルしたアプリケーションをインストールする場所sudo mv heroku /usr/local/パスの設定を行う
echo 'PATH=/usr/local/heroku/bin:$PATH' >> $HOME/.bash_profilePATH=/usr/local/heroku/bin:$PATHという文字列をユーザーのホームディレクトリにある、.bach_profileというファイルの内容に追記、という意味。
.bach_profile:シェルの設定ファイルのこと。
シェルというのは、人間からコンピュータに命令を伝えるための仕組み。設定したパスを反映する
source $HOME/.bash_profileインストール出来たか確認するために、herokuのバージョンを確認する
heroku -vインストール用にダウンロードしたheroku-linux-x64.tar.gzを削除する
rm -f heroku-linux-x64.tar.gzRailsアプリとHerokuの関連付け
アプリのフォルダまで移動し、heroku cliを使ってherokuにログインする
EmailとPasswordを入力したらログイン完了!$ heroku loginもしheroku: Press any key to open up the browser to login or q to exit:と表示されてログインできない場合は、
$ heroku login --interactiveを実行する
Railsアプリとherokuの関連付けを行う
アプリを表示するためのURLは https://アプリ名.herokuapp.com/$ heroku create アプリ名デプロイ
ソースコードをサーバーにデプロイする
$ git push heroku master実行した時に、"You must use bundle 2 or greater with this lockfile."
とエラーが表示されたら、https://programmingnavi.com/1685/サポートサイトの記事を参照するデータベースのマイグレーションを実行する
$ heroku run rails db:migrateインターネットに公開されたwebサイトの情報を確認する
$ heroku apps:info※アプリを削除する場合
heroku apps:destroy --app アプリ名本当に削除して良いか確認を求められるので、再度アプリ名を入力する
→削除されるこちらの内容はhttps://www.udemy.com/course/the-ultimate-ruby-on-rails-bootcamp/
を元に作成しました。
- 投稿日:2020-01-21T00:10:25+09:00
【Rails】セキュアパスワード(has_secure_passwordメソッド)について
概要
個人的にアプリ作成時にテーブル設計で
password_digest
をカラムとして、セキュアパスワードを利用する前提でテーブル作成していましたが、改めてセキュアパスワードについて理解しておくためまとめていきます。セキュアパスワードとは
パスワードの値をDB上にそのまま保存することはセキュリティ上問題があります。
そのためセキュアパスワードというパスワードとパスワード確認をユーザーに入力させて、
その2つの値をハッシュ化したものをデータベースに保存するという方法で脆弱性を回避します。このハッシュ化というのは{key => value}のハッシュではなくて、ハッシュ関数というものを利用して入力されたパスワードを異なる値に変更する処理のことを指します。
パスワードをランダムな文字列に変換して、DBに保存するということ。セキュアパスワードの実装方法
has_secure_passwordメソッドをモデルに記述
has_secure_password
メソッドを利用して、password_digest
カラムにハッシュ化した値を保存するという方法を行います。ユーザーモデルに
has_secure_password
を記述します。
ついでに一般的なパスワードのバリデーションも追記しておきましょう。models/user.rbclass User < ApplicationRecord has_secure_password validates :password, presence: true, length: { minimum: 6 } endこの記述によって、Userモデルは
password
とpassword_confirmation
の2つの属性が使えるようになります。
さらに、ハッシュ化したパスワードをDB内のpassword_digest
に保存するようになります。bcryptをinstall
次に
gem'bcrypt'
(ビークリプト)をインストールします。
has_secure_passwordメソッドを使用するためにbcryptが必要になります。
bcryptによってパスワードをハッシュ化するための関数が提供されます。gem 'bcrypt', '3.1.13'Gemfileに追記して、
$ bundle install確認
セキュアパスワードの設定をしてから、登録したユーザーのpasswordは以下のようにハッシュ化されて
password_digest
に保存されるようになります。irb(main):001:0> User.last User Load (0.4ms) SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT $1 [["LIMIT", 1]] => #<User id: 18, name: "testttt", email: "testtt@a.com", password_digest: "$2a$10$C/nH7reWZY/8QwbN8YFcaOjQSPtqW3aEDGrNuG.8ePP...", created_at: "2020-01-20 15:05:43", updated_at: "2020-01-20 15:05:43", password: nil, password_confirmation: nil, admin: false>