- 投稿日:2019-11-01T23:29:03+09:00
Rails6のActionDispatch::HostAuthorizationとELBのヘルスチェックの共存
Rails6のActionDispatch::HostAuthorization設定とokcomputerを利用した
Nginx - Rails - RDSという経路のヘルスチェックの共存に少しコツが必要だったので記事にしました。ActionDispatch::HostAuthorization
https://github.com/rails/rails/pull/33145
Rails6から追加された、DNSリバインディング攻撃から保護する新機能です。下記のように設定することで、指定したホスト以外からのアクセスはエラーとなります。
Rails.application.config.hosts << "product.com"okcomputer
https://github.com/sportngin/okcomputer
HealthCheck系のgemです。
2019/10/26(執筆時点の一週間前)にRails6対応がリリースされました。
Rails - DBという経路のヘルスチェックを簡単に追加することができます。
例えば、下記のような設定で、/custom_pathというパスにDBまでのヘルスチェック機能を追加することができます。# config/initializers/okcomputer.rb OkComputer.mount_at = false # config/routes.rb, at any priority that suits you mount OkComputer::Engine, at: "/custom_path"発生した問題
Rails6 + AWSで下記の構成のようなアプリを開発していました。
ECS +----------------+ ALB---|--Nginx--Rails--|---RDS +----------------+Rails6の
HostAuthorizationとokcomputergemを利用し、/healthcheckというパスでALBからのヘルスチェックをDBまで通して行おうとしました。
しかし、Railsが403エラーを返し、ヘルスチェックが失敗してしまいました。問題の原因
Nginx、Railsの設定はそれぞれ下記のようになっていました。
Nginxの設定
# healthcheck部分のみ抜粋 server { location /healthcheck { access_log off; proxy_pass http://rails:3000; } }Railsの設定
Rails.application.config.hosts << "product.com"原因はシンプルで、「ヘルスチェック時のホスト名が
product.comでないからエラーになっていた」というものです。対策
いくつか対策方法が考えられますが、今回はシンプルにNginxでHostヘッダを設定する対策を採用しました。
Nginxの設定
server { location /healthcheck { access_log off; # 以下を追加 proxy_set_header Host healthcheck.localhost; proxy_pass http://rails:3000; } }Railsの設定
Rails.application.config.hosts << "product.com" Rails.application.config.hosts << "healthcheck.localhost"この設定で無事、ALBからのhealthcheckでhealthyとなりました!
もう少しスマートな対応方法ありましたら、教えていただけると嬉しいです
- 投稿日:2019-11-01T21:09:35+09:00
[メモ]Railsで特定のページで条件分岐する方法
例えば、page1というページの場合に特定の処理を行いたい場合
<% if request.path.include?('page1') %> [処理を書く] <% end %>
- 投稿日:2019-11-01T20:16:24+09:00
video_tagで横幅いっぱいに動画を挿入する方法
はじめに
video_tagで横幅いっぱいに自動再生で動画を流す。
備忘録として残します。つまずいたところ
- 動画のファイルの置所
- 自動再生
- 横幅を画面いっぱい、縦幅は指定
実装手順
app/assetsの直下にvideosフォルダを作成。
videosフォルダ内に背面で流したい動画を入れる。
(ここでは、test_video.mp4という動画ファイルを入れました。)次にvideo_tagを使って動画を表示
index.html.haml.video-content = video_tag "test_video.mp4", loop: true, autoplay: true, muted: trueobject-fit: cover;をつけることで、動画の横と縦の比率を変更できた。
動画も崩れないで再生されている。index.scss.image-content{ height: 80vh; z-index: 1; video{ width: 100%; height: 100%; object-fit: cover; }背面に動画を入れたい時は、position: absolute;などで調整してください。
videoタグの属性説明
属性 説明 poster 動画が再生されていない時に表示させる画像をパスで指定 autoplay ページのロードが完了したら自動的に動画を再生する loop 動画を繰り返すループ再生を許可する controls 再生ボタンやタイムラインなどのインターフェースパーツを表示させる muted 音声付き動画データの場合は消音にする preload 事前に動画データを読み込むか制御する、属性の値で指定する
【auto】初期値でページロードと合わせて読み込みされる
【none】動画データの読み込みがされない状態
【metadata】動画データのメタデータのみ読み込みされる
- 投稿日:2019-11-01T14:43:26+09:00
MySQL かんたんにテーブルのid番号を1からリセットする方法
MySQLのid番号 リセット方法
MySQLには初期設定でauto-increment機能が設定されています。
簡単にいうと「自動連番機能」です。ただ番号間にあるレコードを消すとそのid番号のみが欠番となったまま、無視され、最後の番号から連番されてしまうため、テーブル管理において不都合なことが生じる場合があります。
そこで本記事では
「id番号を1から振りなおす方法」をご紹介いたします。
方法のみ知りたい方は以下のリンクをクリック
方法へジャンプ
状況:
たとえばこんな感じのテーブルがあり、id番号が順番に振られています。
id name 1 ANA 2 DELTA 3 JAL 4 UNITED 5 VANILA 6 PEACH しかし、いくつかレコード削除などによって欠番が生じると下のような順番になります。
id name 1 ANA 3 JAL 4 UNITED 6 PEACH 上の状態でさらにレコードが追加となると下のような連番となります
7 Sky Mark 8 Jet star 歯抜になってしまったid:2と5は欠番となったまま。
静的なテーブルでこのid番号を1から振り直す方法がないものか探した結果、なんとかできる方法に行き着いたのでご紹介します。
方法
ターミナル上で
1.mysqlに入る
mysql -u root -p
パスワードは基本的には空のままEnterでOK
2.データベースを選択
mysql> use データベース名
3.テーブルのidを定義し直す
mysql> set @n:=0;
mysql> update`テーブル名` set id=@n:=@n+1;
4.確認
mysql> select*from テーブル名;以上の操作でidの番号を振り直すことができたはずです。
基本的にはレコードが入っているテーブルにて以上の方法を試してみてください。
静的なテーブルでは基本的に以上の方法でOKです。がしかし、
レコードが追加されるようなテーブルでは、上記リセットをかけても次のid番号は、もともと最後に入っていたレコードの次の番号からになってしまうため、mysqlのauto_increment自体をリセットする必要があります。
方法2
そんな時は以下の2つの方法を状況に応じて試してみてください。
1.レコードがすべて空の状態からリセットしたい
レコードが空であれば、
ALTER TABLE `テーブル名` auto_increment = 1;でOK
2.レコードが複数存在する状態で最後のidの次から連番にしたい
本記事上部の連番リセット方法でレコード番号を振り直しをしたあとで。。。。
mysql> select*from テーブル名;
でid番号を振り直したテーブルを確認し、例えば下のテーブルなら
id name 1 ANA 2 JAL 3 UNITED 4 PEACH 次は5番から連番になるようにしたい!
ALTER TABLE `テーブル名` auto_increment = 開始したいid番号;
つまり
ALTER TABLE `テーブル名` auto_increment = 5;でOK。次に入るレコードは5からの連番になります。
****************************************
プログラミング初級者が自身の備忘録も兼ねて書いた記事ですのでご指摘等ありましたら気軽にコメントください。なにか同様の問題でお困りの方にお役に立てたら嬉しいです。テーブルのリレーションによっては本記事の番号振り直し自体がエラーになる場合がありますので、テーブル同士のリレーションおよび関係性を確認して記述の修正、一時コメントアウト等適宜行い、実行してください。
- 投稿日:2019-11-01T14:43:26+09:00
テーブルのid番号を1から連番にリセットする方法
MySQLのid番号 リセット方法
MySQLには初期設定でauto-increment機能が設定されています。
簡単にいうと連番機能です。
レコードを消したりして欠番となったまま、id番号の欠番状態を直す方法をご紹介いたします。方法のみ知りたい方は以下のリンクをクリック
こんなとき(id変更したい時の例)
たとえばこんな感じのテーブルがあり、id番号が順番に振られています。
id name 1 ANA 2 DELTA 3 JAL 4 UNITED 5 VANILA 6 PEACH しかし、いくつかレコード削除などによって欠番が生じると下のような順番になります。
id name 1 ANA 3 JAL 4 UNITED 6 PEACH 7 Sky Mark 8 Jet star 歯抜になってしまったidはあらたにレコードを足しても最後のレコードのidから連番となるため、欠番となったままになってしまいます。このid番号を1から振り直す方法がないものか探した結果、なんとかできる方法に行き着いたのでご紹介します。
方法
ターミナル上で
1.mysqlに入る
mysql -u root -p
2.データベースを選択
mysql> use データベース名
3.テーブルのidを定義し直す
mysql> set @n:=0;
mysql> update`テーブル名` set id=@n:=@n+1;
4.確認
mysql> select*from テーブル名;以上の操作でidの番号を振り直すことができたはずです。
基本的にはレコードが入っているテーブルにて以上方法で連番しなおしてみてください。次に入る、レコードは最後に入っていたレコードの次の番号からになってしまうため、auto_increment自体をリセットする場合は以下になります。
レコードをすべて空にした状態からauto_incrementをリセットする場合
ALTER TABLE `テーブル名` auto_increment = 1;でOK。施行後入るレコードは1からの連番になります。
- 投稿日:2019-11-01T14:43:26+09:00
MySQL テーブルのid番号を1から連番にリセットする方法
MySQLのid番号 リセット方法
MySQLには初期設定でauto-increment機能が設定されています。
簡単にいうと連番機能です。
レコードを消しすとそのid番号が欠番となったまま、連番されてしまうため、id番号を1から振りなおす方法をご紹介いたします。方法のみ知りたい方は以下のリンクをクリック
状況:
たとえばこんな感じのテーブルがあり、id番号が順番に振られています。
id name 1 ANA 2 DELTA 3 JAL 4 UNITED 5 VANILA 6 PEACH しかし、いくつかレコード削除などによって欠番が生じると下のような順番になります。
id name 1 ANA 3 JAL 4 UNITED 6 PEACH 上の状態でさらにレコードが追加となると下のような連番となります
7 Sky Mark 8 Jet star 歯抜になってしまったid:2と5は新たにレコードを足しても最後のレコードのidから連番となるため、欠番となったままになってしまいます。
静的なテーブルでidが正しい連番でなければいけなかったため、このid番号を1から振り直す方法がないものか探した結果、なんとかできる方法に行き着いたのでご紹介します。
方法
ターミナル上で
1.mysqlに入る
mysql -u root -p
パスワードは基本的には空のままEnterでOK
2.データベースを選択
mysql> use データベース名
3.テーブルのidを定義し直す
mysql> set @n:=0;
mysql> update`テーブル名` set id=@n:=@n+1;
4.確認
mysql> select*from テーブル名;以上の操作でidの番号を振り直すことができたはずです。
基本的にはレコードが入っているテーブルにて以上方法で連番しなおしてみてください。静的なテーブルでは以上の方法でOKです。
がしかし、
レコードが追加されるようなテーブルでは、次のid番号は最後に入っていたレコードの次の番号からになってしまうため、auto_increment自体をリセットする必要があります。
でも大丈夫
そんな時は以下の状況に応じた2つの方法をいずれか試してみてください。
1.レコードがすべて空の状態から
レコードが空であれば、
ALTER TABLE `テーブル名` auto_increment = 1;でOK
2.レコードの途中から
本記事上部の連番リセット方法でレコード番号を振り直しをしたあとで。。。。
mysql> select*from テーブル名;
でid番号を振り直したテーブルを確認し、例えば下のテーブルなら
id name 1 ANA 2 JAL 3 UNITED 4 PEACH 次は5番から連番になるようにしたい!
ALTER TABLE `テーブル名` auto_increment = 開始したいid番号;
つまり
ALTER TABLE `テーブル名` auto_increment = 5;でOK。次に入るレコードは5からの連番になります。
****************************************
プログラミング初級者が自身の備忘録も兼ねた記事ですのでなにか同様の問題でお困りの方にお役に立てたら嬉しいです。テーブルのリレーションによっては本記事の番号振り直し自体がエラーになる場合がありますので、テーブル同士のリレーションおよび関係性を確認して記述の修正等適宜行い、実行してください。
- 投稿日:2019-11-01T14:41:42+09:00
【i18n-js】Railsアプリのi18n(tメソッド)をVue.jsでも使用する
Railsアプリ開発の際、フロントをVue.jsで書いているのですが、
「i18nをフル活用し、ソースコードに日本語のベタ書きは限りなくゼロにしていこう!」
とした場合、
「Vue.jsではどうすればいいの?」
となったので実装の記録を書き残します。前提
- macOS Mojave 10.14.6
- Ruby 2.5.5
- Rails 5.2.3
- Vue 2.6.10
gem「i18n-js」を導入
Gemfilegem 'i18n-js'terminal$ bundle installJavaScriptでI18nを利用する場合、
config/ja.ymlを直接使える訳ではなく、.jsに変換してそれを読み込んで利用します。
i18n-jsはその変換出力のためのgemです。i18n-js.ymlを作成
どのように変換出力するかのルールを設定するファイルです。
公式などを見ると一般的に使われる設定ではtranslation.jsという1つのファイルに全ての言語の設定を詰め込むため、読み込みが重くなってしまいます。
なので言語別に出力されるよう設定します。config/i18n-js.ymltranslations: - file: "app/assets/javascripts/i18n/%{locale}.js"許可するlocaleを限定
後述する
rake i18n:js:exportをこのまま実行してしまうと、許可されている全ての言語のjsファイルが生成されてしまいます。(私の場合90個ぐらいでした)
日本で開発されている方であれば、日本語と英語だけで十分かと思いますので今回はその2言語のみ生成されるようにします。config/application.rb# デフォルトのlocaleを日本語(:ja)にする config.i18n.default_locale = :ja # 許可するlocaleを日本語(:ja)と英語(:en)に限定する config.i18n.available_locales = %i[ja en]これで
ja.ymlはja.jsに、en.ymlはen.jsに変換出力されるようになります。rake i18n:js:exportで出力
js用のlocaleファイルを変換するコマンドを実行します。
terminal$ rake i18n:js:export
en.jsとja.jsは確認できましたか?
中を見てみるとyamlファイルで定義しているものを数行に凝縮していますね。
最終的にtメソッドはこれらのファイルからマッチするものを探してきます。i18n.jsを編集
同時に
public/javascript/にi18n.jsも出来ました。
機能の根幹となるメソッドがたくさん書いてあるファイルです。この中から
defaultLocaleとlocaleを必要に応じて変更します。
railsのgemi18nとは別物なので、別途定義が必要です。
日本語であれば"ja"ですね。また、以下については通常行わないのかもしれませんが、
public/javascript/i18n.jsをapp/assets/javascript/i18n.jsに移動してください。私はしばらくconsoleで確認しても
- i18nが認識されない
- default_localeが"en"から変わらなかった
ので、
i18n/ja.jsと同じapp/assets/javascript/に置くことで解決しました。もしより良い解決策をご存知の方いらっしゃいましたらコメントお願いいたします。
head内でlocaleファイルの読み込み設定
railsのアセットパイプラインを使う方法と使わない方法があるのですが、
今回は使わない方法でheadタグ内でjavascript_include_tagを用いて読み込みを行います。
(i18n-js公式ドキュメントではどちらの方法も書いてあります。)application.html.erb<head> <!-- 〜中略〜 --> <%= javascript_include_tag "i18n" %> <%= javascript_include_tag "i18n/#{I18n.locale}" %> </head>
I18n.localeの部分でユーザーそれぞれのlocaleが適用されます。consoleでI18nコマンドが使えるか確認
現時点でI18nが使えるかどうか、
rails serverを立ち上げてローカルでRailsアプリにアクセスします。
chromeのデベロッパーツールで画像のように打ち込んで確認してみましょう。
2つ目はご自身のアプリで定義してあるものを適当に呼び出してみてくださいね。vueファイルでI18nコマンドを省略するためのmixinを作成
i18n-jsによりjsファイルでは使えるようになりましたが、
vueファイルではまだ使えません。
そこでmixinを作成し、そのjsファイルを読み込むことでvueファイルでも使えるようにします。
どうせなら省略形でもメソッドが動いてくれるように工夫してみましょう。mixins/i18n.jsexport const i18n = { methods: { t: (...args) => I18n.t(...args), currentLocale: () => I18n.currentLocale() } };いちいち
I18n.t('hoge')と打たなくてもt('hoge')だけでメソッドが機能します。コンポーネントでmixinをimport
sample.vue<template> </template> <script> import { i18n } from "../mixins/i18n"; export default { mixins: [i18n] } </script>vueファイルでtメソッドが使えるか確認
sample.vue<template> <h2>{{ t('create') }}</h2> </template> <script> import { i18n } from "../mixins/i18n"; export default { mixins: [i18n] } </script>上記vueファイルが使われているページにアクセスし、
i18nで定義された日本語(今回の場合は「登録」)が表示されます。以上です。お疲れ様でした!
おまけ1:本番環境へデプロイするにはrake assets:precompile
今回
app/assets/に新たに作成されたファイルがあるので
本番環境へデプロイするにあたりprecompileが必要ですが、
対象から外れてしまっている場合は以下の設定で対象に含める必要があります。production.rbconfig.assets.precompile += %w( application.js application.css ) files = Dir[Rails.root.join('app', 'assets', 'javascripts', 'i18n', '*.js')] files.map! {|file| file.sub(%r(#{Rails.root}/app/assets/javascripts/), '') } config.assets.precompile += filesおまけ2:i18nのyamlファイルを修正した場合は?
terminal$ rake i18n:js:export修正を加える都度変換してください。
参考記事
・i18n-js 公式ドキュメント
https://github.com/fnando/i18n-js
・[stackoverflow]単一のリポジトリでロケールを共有するRails + Vue.jsインスタンスにI18nがありますか?
https://stackoverflow.com/questions/48950685/is-there-a-i18n-on-a-railsvue-js-instance-which-share-locales-in-a-single-repos
・[Qiita]i18n-jsで必要な言語のみロードしてパフォーマンスUP
https://qiita.com/konifar/items/9886c7da97f20d3206cc
・[Qiita]react_railsとi18n-jsをwebpackerで動かす
https://qiita.com/Atsuyoshi-N/items/48f8b5d5802b9ac47732#i18n%E3%81%AE%E8%A8%AD%E5%AE%9Arails%E5%81%B4
- 投稿日:2019-11-01T13:33:30+09:00
rails generateでのpolymorphic associationの生成
- 投稿日:2019-11-01T12:38:22+09:00
Rails6 のちょい足しな新機能を試す103(ActionDispatch::Response#content_type編)
はじめに
Rails 6 に追加された新機能を試す第103段。 今回は、
ActionDispatch::Response#content_type編です。
Rails 6 では、content_typeは、 Content-Type Header の情報をそのまま返すようになります。Ruby 2.6.5, Rails 6.0.0, Rails 5.2.3 で確認しました。
また、RSpec のバージョンは、 3.9.0 です。$ rails --version Rails 6.0.0今回は、User CRUD を作り、request spec を変更することにより確認します。
RSpec の導入などについては、 Rails6 のちょい足しな新機能を試す24(unfreeze_time 編) などを参考にしてください。
Rails プロジェクトを作る
$ rails new rails_sandbox cd rails_sandboxUser の CRUD を作成する
$ bin/rails g scaffold User namerequest spec を編集する
spec/requests/users_spec.rbを編集します。ここで
response.content_typeとresponse.media_typeのテストを追加していることに注意してください。spec/requests/users_spec.rbrequire 'rails_helper' RSpec.describe "Users", type: :request do describe "GET /users" do it "works! (now write some real specs)" do get users_path expect(response.content_type).to eq('text/html; charset=utf-8') expect(response.media_type).to eq('text/html') expect(response).to have_http_status(200) end end end実際にテストする
実際にテストすると spec が通ることが確認できます。
$ rspec spec/requests/users_spec.rbRails 5 では
Rails 5.2.3 では、
content_typeはtext/htmlを返すため spec が失敗します。
つまり、以下のように書くと、 spec が通ります。spec/requests/users_spec.rbexpect(response.content_type).to eq('text/html')ちなみに
今回、 request spec に登場した
responseのクラスは、ActionDispatch::Responseの 派生クラスのActionDispatch::TestResponseです。
ですが、content_typeメソッドは、ActionDispatch::Responseクラスで実装されています。試したソース
試したソースは以下にあります。
https://github.com/suketa/rails_sandbox/tree/try103_response_content_type参考情報
- 投稿日:2019-11-01T12:10:25+09:00
RailsでCSSやJavaScriptが読み込まれる仕組みをアセットパイプライン、Sprockets、マニフェストファイルで理解する
本来、HTML,CSSでサイトを作成する際は、HTMLファイルからlinkタグを使ってCSSファイルを読み込む設定が必要です。
しかし、Railsの場合、それらを記述する必要はありません。
じゃぁどうやって必要なCSSやJavaScriptが読み込まれるのか??
アセットパイプライン
Sprockets
マニフェストファイル
のこれらの単語を使ってざっくり理解する。アセットパイプライン
要は、まとめてくれる(統合してくれる)って仕組み。
詳しく働きをみると以下のようになる。
1.コンパイル
2.統合
3.圧縮
4.ダイジェスト付与
5.完成したファイルがpublic/assets/に保存されるSprockets
アセットパイプラインの動作を担っているのがSprockets。
gemとしてデフォルトで入っている。
アセットパイプラインはデフォルトで有効なので、無効にしたい場合は--skip-sprocketsをつけて以下のコマンドを実行。$ rails new appname --skip-sprocketsマニフェストファイル
app/assets/javascripts/application.js
app/assets/stylesheets/application.css
がそれぞれcssとJavaScriptのマニフェストファイル。
ここに記述されてあるrequire_tree.によって指定されるディレクトリのファイルが全て読み込まれるオススメ記事
Ruby on Rails のアセットパイプラインの挙動を環境ごとに学ぶ
Railsガイド アセットパイプライン
railsのアセットパイプラインについて解説する
- 投稿日:2019-11-01T09:03:52+09:00
Ruby初心者がいきなりRailsするときのMemo
初めに
これまではPHPかPythonでの開発がほとんどだったのですが、様々な事情により、Ruby on Railsの案件に取り組むことになりました。これまでよくやっていたPython + Flask構成と比較しながらRuby on Railsを勉強しているのですが、その試行錯誤を残しておきたいと思います。内容は随時更新します。
目次
- Rubyの環境構築
- Railsの導入
Rubyの環境
Pythonでは、以下の環境を使っていました。
* pyenv(Pythonのバージョン管理) * pipenv(仮想環境構築+Packageの管理)Rubyでそれぞれに対応するのは、(というかPythonのそこら辺のツールはRubyのツール群に触発されて開発されたものが多いので、こちらのほうが大元というべきなのですが、)
* rbenv(Rubyのバージョン管理) * bundler(gemの管理)です。一般的なRubyプロジェクトは、bundlerを用いて
mkdir PROJECT_DIR cd PROJECT_DIR bundler init #これによってGemfile, Gemfile.lockが作られる vi Gemfile #Gemfileに必要なライブラリ群を記載 bundler install --path vendor/bundler #Gemfileに記載したライブラリ群をvendor/bundler以下にインストール bundler exec COMMAND #pipenv run COMMANDに対応するコマンドとして環境を作るようです。
Rails環境の構築
Railsは
- 投稿日:2019-11-01T09:03:52+09:00
PythonistがRuby on Railsに異世界転生したときの記録
初めに
これまではPHPかPythonでの開発がほとんどだったのですが、様々な事情により、Ruby on Railsの案件に取り組むことになりました。これまでよくやっていたPython + Flask構成と比較しながらRuby on Railsを勉強しているのですが、そのmemoを残しておきたいと思います。内容は随時更新します。
環境
- ubuntu 19.04 eoan ermine
- rbenv version 1.1.1
- ruby verison 2.6.5
目次
- Rubyの環境構築
- Railsの導入
Rubyの環境
Pythonでは、以下の環境を使っていました。
* pyenv(Pythonのバージョン管理) * pip(デフォルトのPackage管理) * pipenv(仮想環境構築+Packageの管理)Rubyでそれぞれに対応するのは、(というかPythonのそこら辺のツールはRubyのツール群に触発されて開発されたものが多いので、こちらのほうが大元というべきなのですが、)
* rbenv(Rubyのバージョン管理) * gem(デフォルトのPackage管理:ただしRubyではPackageのことをGemとよんでいる) * bundler(仮想環境構築+Gemの管理)です。Gemというのは、PythonでいうPackageみたいなもののようです。一般的なRubyプロジェクトは、bundlerを用いて
mkdir PROJECT_DIR cd PROJECT_DIR rbenv local 2.6.5 #pipenv install 3.8.0と同じノリです gem install bundler bundler init #これによってGemfile, Gemfile.lockが作られる。pipenv initと同じ vi Gemfile #Gemfileに必要なライブラリ群を記載 bundler install --path vendor/bundler #Gemfileに記載したライブラリ群をvendor/bundler以下にインストール bundler exec COMMAND #pipenv run COMMANDに対応するコマンドとして環境を作るようです。
PipenvとBundlerは大体同じですが、以下のような細かい違いがあります。
bundler execはpipenv runと対応していますが、pipenv shellに対応するコマンドはなさそうです- pipenvでは、Packageのインストール先は、デフォルトで
~/.local以下に作られ、PIPENV_VENV_IN_PROJECTでプロジェクトディレクトリ以下に作成されます。一方、bundlerでは--pathオプションにより都度指定する仕組みのようです。Rails環境
RailsはRuby用のWeb開発フレームワークです。その意味ではFlaskと似ていますが、Flaskよりもデフォルトのツールが揃っている気がします。(例えばORMなどです。)その点では、FlaskよりもDjangoのCounterpartと考えるべきなのかもしれません。
Rails環境の構築ですが、上に書いたように、GemfileにRailsを追加してやっていくスタイルかと思いきや、そうではありませんでした。
Railsは統合的なWeb開発環境であり、bundlerを内包しているとのことです。Rails comes with baked in support with bundler.
Bundler公式ドキュメントここでは、公式ドキュメント通りに
gem install rails rails new APP_DIR cd APP_DIR bundler installで良いようです。
- 投稿日:2019-11-01T08:03:20+09:00
Railsの便利機能「Application Template」で rails newと初期設定を自動化できた!
Railsアプリの新規作成から初期設定までを
rails newとrails db:createだけで完了させます。
rails newのあとにひたすらつづくgemのインストールや初期設定、めんどくさくないですか?
ちょっとしたtypoでRailsAbort! こういった人的ミスによるグツグツから開放されたくないですか?
テンプレートファイルは1つにまとめておけるので、Railsアプリ新規作成時の手順書としてもメンテできて一石二鳥ですよ!環境
- MacOS 10.14.6
- Ruby 2.6.3
- Rails 5.2.3
- MySQL 8.0.16
- Docker 19.03.4
- docker-compose 1.24.1
※Dockerじゃなくてもイケます。
方法
RailsのApplication Templateという機能を使用します。
やること
- ApplicationTemplateファイルをつくります。
rails new -m app_template.rbコマンドをうちます。rails db:createコマンドをうちます。- 以上(*´∀`)
手順
①ApplicationTemplateファイルをつくる
プロジェクトフォルダのルートに
app_template.rbを新規作成します。むずかしく考えなくていいです。
いつもやってる作業を上から順にかいていくだけです。ちなみに、わたしの
app_template.rbはこんなかんじ。docker-rails-mysql-template/app_template.rb at master · yukawahara0416/docker-rails-mysql-template
やってることは以下のとおり。
- gemの指定
- gem_groupの指定
- コマンドの実行(
bundle install,rspec:intallなど)- 不要なディレクトリの削除
- 設定ファイルの取得
- 設定ファイルの書き換え(日本語化、
database.ymlなど)もっと複雑なこともできるみたいですが、これだけでもかなり手間が省けます。
②rails new -mコマンドをうつ
いつもの
rails newに-m app_template.rbをつけるだけです。ルートフォルダに配置して使用する場合
$ rails new . -m app_template.rbGitHubなど外部からテンプレファイルを取得する場合
$ rails new . -m https://raw.githubusercontent.com/yukawahara0416/docker-rails-mysql-template/master/app_template.rbほかのオプションと組み合わせて
$ rails new . -B -T -d mysql -m https://raw.githubusercontent.com/yukawahara0416/docker-rails-mysql-template/master/app_template.rb
-Bはbundle installのスキップ、-TはMinitest用のtestディレクトリの生成スキップ、-d mysqlはDBをMySQLに指定しています。ちなみに、Dockerならこんなかんじです。
$ docker-compose run web rails new . -B -T -d mysql -m https://raw.githubusercontent.com/yukawahara0416/docker-rails-mysql-template/master/app_template.rbターミナルはこんなかんじ。順番に実行してくれてますね。
apply https://raw.githubusercontent.com/yukawahara0416/docker-rails-mysql-template/master/app_template.rb gemfile mysql2 gemfile rails-i18n gemfile group :development, :test append Gemfile gemfile factory_bot_rails gemfile guard-rspec gemfile rspec-rails gemfile rubocop gemfile spring gemfile spring-commands-rspec append Gemfile gemfile group :development append Gemfile gemfile better_errors gemfile binding_of_caller append Gemfile gemfile group :test append Gemfile gemfile capybara gemfile webdrivers (~> 3.0) append Gemfile run bundle install from "." ...中略... remove test insert app/views/layouts/application.html.erb remove .gitignore create .gitignore create config/locales/ja.yml insert config/application.rb insert config/application.rb insert config/environments/development.rb generate rspec:install create .rspec create spec create spec/spec_helper.rb create spec/rails_helper.rb insert .rspec run guard init rspec from "."③rails db:createコマンドをうつ
たった1コマンドでRailsアプリの初期設定までできてしまいました。
最後にDBを生成してYay!を確認してみましょう。$ rails db:createずっとRailsの初期設定の自動化を夢見てきたので感激です(´;ω;`)
以上です。
参照
- 投稿日:2019-11-01T02:46:34+09:00
rescueでエラーを拾ってくれない問題
BackGround
Postmanを使ってRailsのアクションを設計どうりに処理してくれるかテストしていました。
問題になったのはこのuser_controllerのshowアクションuser_controller.rbclass UsersController < ApplicationController def show @user = User.find(params[:id]) render json: { status: 'success', data: @user } rescue ActiveRecord::RecordNotFound render json: { status: 'error!', data: @user.errors } end private def user_params params.require(:user).permit(:user_name,:email,:password,:password_confirmation) end end存在したら、ユーザ情報を返し、「存在しなければそんなのいねえよ!」ってことでエラーを吐くはず。
Let's Do It!!
ってことでPostman上で存在しないユーザ(ID:20)に対し、アクションを要求する。
error!って返って来るはず♪
ん?404???error!じゃなくて??
404までは期待どうり。だけどそのあとの処理が拾われていない??
rescueとは・・・Research Solution
大人しく、チャレキャラのメンターさんに質問しました。
その中でも、日頃お世話になっているアルバイト先のBig Bossに助けてもらいました?Solution
user_controller.rbclass UsersController < ApplicationController def show @user = User.find(params[:id]) render json: { status: 'success', data: @user } rescue ActiveRecord::RecordNotFound render json: { status: 'error!', data: '' }, status: :not_found end private def user_params params.require(:user).permit(:user_name,:email,:password,:password_confirmation) end end
render json: { status: 'error!', data: @user.errors }の部分を
render json: { status: 'error!', data: '' }, status: :not_foundに変更Why??
理由としては、userがnillなのに、errorメソッドを呼んで、errorを返してしまうってこと*らしい
確かにnillってオブジェクトでもないわけだからそれにメソッド呼んでも処理ができるはずはない。
だもんで、戻り値にエラーを吐かないようにしてかつ、statusを返すようにしたわけですね!+ α
そもそも、
rescueは多用しないほうがいいという知見をいただきました。
自分も使い慣れてないし、当分はif-else分岐で行こうかと思い、書き直してみよう!user_controller.rbclass UsersController < ApplicationController def show @user = User.find_by(id:"") render json: { status: 'success', data: @user } if ActiveRecord::RecordNotFound render json: { status: 'error!', data: 'user_params' }, status: :not_found end private def user_params params.require(:user).permit(:user_name,:email,:password,:password_confirmation) end endこんな感じ?
コメントで教えてもらうと助かりますSummary
チャレキャラのメンターさん達みたいになりたい
- 投稿日:2019-11-01T01:12:18+09:00
【Ruby on Rails】gem「devise」のREADMEを読んでみた
はじめに
オープンソースのソフトウェアやプログミング言語、ライブラリには、間違いなく公式のドキュメントが存在します。
学習のために無料のラーニングシステムを使うこと、書籍を購入することもいいですが、個人的には、公式ドキュメントには必ず一度は目を通すべきものだと思ってます。
なぜなら出版されてしまった本とは異なり、常に最新の状態にアップグレードされ、多くの人が目にするので間違いが日々修正されているからです。
英語が読めない? 長くて読む気がでない? ならばググりましょう!
例えば英語がわからないなら、この世の中便利な時代なので、英語のドキュメントについてすでに読んだ人の記事などが検索してヒットするはずです)やったこと
Ruby on Railsの開発環境下で、認証機能を実装したい際に利用することが多いgem「devise」のREADMEを読んでみました。
※2019年10月時点の情報です。https://github.com/plataformatec/devise
deviseが持っているモジュール(簡単に言えば機能)
- Database Authenticable: サインインに必要なパスワードを暗号化し、DBに保存してくれる機能
- Omniauthable: OmniAuthをサポートしてくれる機能(今回の記事ではあまり触れません)
- Confirmable: サインインの際,そのアカウントが確認済みか否かチェックし,メールを送信する機能
- Recoverable: ユーザーのパスワードをリセットに関する機能
- Registerable: 登録プロセスを通りユーザーがサインアップした後、ユーザー情報の編集や削除ができる機能
- Rememberable:ユーザー情報をcookieに保存できるよう、トークンを生成・削除してくれる機能
- Trackable: サインイン回数、サインイン時間、IPアドレスを保存する機能
- Timeoutable:セッションの有効期限を一定時間で切る機能
- Validatable: email: emailとパスワードのバリデーションのための機能
- Lockable: サインインに何度も失敗した際、アカウントをロックする機能
いくつも機能があるので、もはや全ての機能を使いこなせる気がしない・・・
ただ、railsを触りたての初心者やフレームワーク(つまりはRailsアプリケーションの構築)について理解が浅い人にはdeviseの利用はオススメしないとのこと。 理由: まずはRailsフレームワークを熟知する必要があるため。Railsと認証の仕組みを理解すれば、deviseは便利と公式でも表記がありますね!
deviseのインストール方法
公式のREADMEにも当たり前ですが、使い方が載っています。
deviseって、rails4.1から使えるんですねgem 'devise'これをGemfileに記載し、bundle install
次に、ジェネレーターを実行する。
rails generate devise:install各環境のdevise用メールサーバの設定をするなら、config/environments/development.rbに以下の記述を追加すること。
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }ジェネレーターはdeviseの全ての設定オプションのinitializerをインストールしてくれる・・・
終わったらdeviseを好きなモデルに用意します。rails generate devise MODELモデルはアプリケーションのユーザーを表す名前にすること(UserやAdmin)。
さらにジェネレーターは、config/routes.rbファイルにDeviseコントローラを指すルーティングを用意してくれる。もしモデルに追加のオプション(メール確認やアカウントロックなど)があれば、migrationファイルを確認しコメントをはずし、そのあとrails db:migrateを実行。
これらが終わったら、一度アプリケーションを終了し、サーバーを再起動すれば、deviseの機能が使えるようになります。もし再起動しなかったら、エラーが発生する可能性があります。
以上で基本的な導入は完了!!
ヘルパーやフィルター
deviseを導入すれば、コントローラやビューで利用可能なヘルパーメソッドを生成してくれます!
メソッド 用途 before_action :authenticate_user! コントローラーに設定して、ログイン済ユーザーのみにアクセスを許可する user_signed_in? ユーザーがサインイン済みかをチェックする current_user 現在サインイン中のユーザーを表示する user_session セッション情報にアクセスする ※例えばモデル名がUser以外の場合、メソッドの名前ももちろん書き換わる。
(例) User → Admin
before_action :authenticate_admin!
admin_signed_in?
current_admin
admin_sessionまた、deviseはリダイレクトする際rootパスを探すので、ルーティングにrootを設定する必要があります。
root to: 'home#index'モデル
モデルの中でもdeviseメソッドを利用すれば、モジュールの設定を行うことができる!
devise :database_authenticatable, :registerable, :confirmable, :recoverable, stretches: 13:stretchesは、 :pepper、 :encryptor、 :confirm_within、 :remember_for、 :timeout_in、 :unlock_in のオプションを定義している。
必要であればってかんじでしょうか・・・
ストロングパラメータ
ビューをカスタマイズする際、フォームに新しい属性を追加する必要がある。
たとえば、以下の通り。
- sign_in(Devise::SessionsController#create) - 認証キーのみ許可
- sign_up(Devise::RegistrationsController#create) - 認証キーに加え、passwordとpassword_confirmationを許可
- account_update(Devise::RegistrationsController#update) - 認証キーに加え、passwordとpassword_confirmation、current_passwordを許可
もしその他のパラメータを追加する場合は、before_actionを用いてApplicationControllerに追加。
class ApplicationController < ActionController::Base before_action :configure_permitted_parameters, if: :devise_controller? protected def configure_permitted_parameters devise_parameter_sanitizer.permit(:sign_up, keys: [:username]) end end以下はaccepts_nested_attributes_forを利用した例
class ApplicationController < ActionController::Base before_action :configure_permitted_parameters, if: :devise_controller? protected def configure_permitted_parameters devise_parameter_sanitizer.permit(:sign_up, keys: [:first_name, :last_name, address_attributes: [:country, :state, :city, :area, :postal_code]]) end endそしてこちらは、ユーザー名とemailを許可する例
def configure_permitted_parameters devise_parameter_sanitizer.permit(:sign_in) do |user_params| user_params.permit(:username, :email) end endそんでもってこれは、登録の際、ユーザーにロールを割り当てるためのチェックボックスがある例
def configure_permitted_parameters devise_parameter_sanitizer.permit(:sign_up) do |user_params| user_params.permit({ roles: [] }, :email, :password, :password_confirmation) end end複数のdeviseモデルが存在したら以下のような記述になる。
class User::ParameterSanitizer < Devise::ParameterSanitizer def initialize(*) super permit(:sign_up, keys: [:username, :email]) end endclass ApplicationController < ActionController::Base protected def devise_parameter_sanitizer if resource_class == User User::ParameterSanitizer.new(User, :user, params) else super # Use the default one end end endビュー
認証を利用するアプリケーションを簡単に開発するためのdeviseは、
ジェネレーターを使えばビューの生成も行ってくれます!rails generate devise:viewsそして、ビューも簡単にカスタマイズができる。
しかもそれは、config/initializers/devise.rbファイルにconfig.scoped_views = trueをセットするだけ!さらにdeviseを使えば、ロール(userとかadminとか)ごとにビューを持つこともできる。
rails generate devise:views usersコントローラー
ビューのカスタマイズだけでは足りない場合、コントローラもカスタマイズすることができる。
rails generate devise:controllers [scope]例えば、usersを使いたい場合、app/controllers/user/に作成され、
その中から一つ例を出すなら、セッションコントローラはこんな感じ。class Users::SessionsController < Devise::SessionsController # GET /resource/sign_in # def new # super # end ... end次に、ルーティングを設定する。
devise_for :users, controllers: { sessions: 'users/sessions' }この場合、devise/sessionsはデフォルトのビューとして扱われなくなる。
最後に、コントローラ上でアクションを変更もしくは拡張する。
(コントローラのアクションの完全オーバーライドも可能)class Users::SessionsController < Devise::SessionsController def create # custom sign-in code end end以下のように単に新しくすることもできる。
class Users::SessionsController < Devise::SessionsController def create super do |resource| BackgroundWorker.trigger(resource) end end enddeviseは、サインインの成功・失敗時にflashメッセージを使用するようになっていて、その際flash[:notice]やflash[:alert]を利用すればOK。
特定の環境においては:timeoutキーをflashハッシュとして追加するので、もしハッシュをそのまま表示するつもりなら、このキーは削除する必要があるみたい。ルーティング
deviseは、デフォルトでルーティングを設定してくれ超便利!
もしカスタマイズしたければ、devise_forメソッドを用いてカスタマイズOK。
また、i18n対応のパスを許可するものを含め、:class_nameや:path_prefixなどのオプションも使用可能。すごいぞdevise。devise_for :users, path: 'auth', path_names: { sign_in: 'login', sign_out: 'logout', password: 'secret', confirmation: 'verification', unlock: 'unblock', registration: 'register', sign_up: 'cmon_let_me_in' }例えば"/users/sign_in"に加え、"/sign_in"というルーティングを許可したいなど、
追加でカスタマイズが必要な時は通常通りルーティングの設定を行い、devise_scopeブロックで囲うだけでOK。devise_scope :user do get 'sign_in', to: 'devise/sessions#new' enddeviseのマッピングはするけど、skipして何も設定しない。
つまりcurrent_userだけのルーティングを設定したいなど任意のルーティングを設定するとき
以下のように記述するだけ。devise_for :users, skip: :allI18n
deviseは、:noticeや:alertというflashキーで接続されたI18nのflashメッセージを利用しているので、
アプリケーションをカスタマイズするためにlocaleファイルを設定しなければならないそう。en: devise: sessions: signed_in: 'Signed in successfully.'ルーティング内で特定可能な名前を利用すれば、リソースごとに異なるメッセージを作成できる!
en: devise: sessions: user: signed_in: 'Welcome user, you are signed in.' admin: signed_in: 'Hello admin!'以下の例はメーラーを使用する場合の記述。
en: devise: mailer: confirmation_instructions: subject: 'Hello everybody!' user_subject: 'Hello User! Please confirm your email' reset_password_instructions: subject: 'Reset instructions'「利用可能なメッセージについて、以下のlocalを参照せよ」とのこと。
https://github.com/plataformatec/devise/wiki/I18nここで注意! deviseのControllersはApplicationControllerを継承しているので、アプリ内で複数のlocaleを利用する際にはApplicationControllerでI18n.localeを設定しなくてはならないようです。
テストヘルパー
deviseはtest helperまでも持っている!
使用するには、対応するtest cases/specs.にコードを追加すればOK!コントローラのテスト
コントローラーのテストでは、include Devise::TestHelpersを使用。
Rails5の場合、Devise::Test::IntegrationHelpers を使用。class PostsControllerTest < ActionController::TestCase include Devise::Test::ControllerHelpers endRSpecを利用している場合、spec/support/devise.rbかspec/spec_helper.rb(もしrspec-railsを利用しているのであればspec/rails_helper.rb)というファイルに以下のコードを追加。
RSpec.configure do |config| config.include Devise::Test::ControllerHelpers, type: :controller config.include Devise::Test::ControllerHelpers, type: :view end上記は、require 'rspec/rails'の下に追加しないと動かないので気をつけること!
これで、sign_inやsign_outメソッドがテストのコントローラを利用できます!
sign_in @user sign_in @user, scope: :admin※ 「devise内部のコントローラや、devise自体を継承したコントローラをテストする場合、リクエストの前にどのマッピングが使うのか教えなくてはなりません。なぜならdeviseがルータからこの情報を得るためですが、テストはルータを通さないので、ルーターを明確にする必要があります」と公式に書いてありました。
例えば、userスコープをテストする場合、以下のように書きます。test 'GET new' do # Mimic the router behavior of setting the Devise scope through the env. @request.env['devise.mapping'] = Devise.mappings[:user] # Use the sign_in helper to sign in a fixture `User` record. sign_in users(:alice) get :new # assert something endインテグレーションテスト
インテグレーションテストをする際はDevise::Test::IntegrationHelpersをモジュールに追加。
class PostsTests < ActionDispatch::IntegrationTest include Devise::Test::IntegrationHelpers endこれで、sign_inやsign_outメソッドがインテグレーションテストでも利用可能に!
sign_in users(:bob) sign_in users(:bob), scope: :admin sign_out :userRSpecは、IntegrationHelpersモジュールを:feature specsに持っているらしい・・・
RSpec.configure do |config| config.include Devise::Test::IntegrationHelpers, type: :feature endRSpecでのRails3、Rails4のコントローラのテストについては以下参照。
https://github.com/plataformatec/devise/wiki/How-To:-Test-controllers-with-Rails-(and-RSpec)OmniAuth(オムニオース)
deviseは様々な認証を利用できるOmniAuthをサポートしているので、利用するにはOmniAuthの設定をconfig/initializers/devise.rbに記載してあげればOK。
config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo'詳しくは以下参照
https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview複数モデルのセットアップ
deviseは好きなだけモデルを設定可能なんです。
例えば、Userモデルに加え、認証にタイムアウト機能を備えたAdminモデルを作りたい場合は、以下のように記述してあげます。# Create a migration with the required fields create_table :admins do |t| t.string :email t.string :encrypted_password t.timestamps null: false end # Inside your Admin model devise :database_authenticatable, :timeoutable # Inside your routes devise_for :admins # Inside your protected controller before_action :authenticate_admin! # Inside your controllers and views admin_signed_in? current_admin admin_sessionあるいは、deviseジェネレーターを呼ぶだけでOK。
※ 「これらのモデルは完全に異なるルーティングになるので注意が必要です。サインイン、サインアウトなどは、コントローラを共有することはありませんし、できません。」
ここ、すごい強調されてました。(まぁそうか)
ActiveJob Integration
アクティブジョブインテグレーションは、Rails4.2とActiveJobを使っている時、モデル内のsend_devise_notificationメソッドをオーバーライドすることでdeviseのメールを送信することができるようになる機能・・・・
使ってみないとわからないやw
def send_devise_notification(notification, *args) devise_mailer.send(notification, self, *args).deliver_later endパスワードリセットトークンとRailsのログ
公式によると、
「Recoverableのモジュールを使用により、もしパスワードリセットのトークンが盗まれたら攻撃者がアプリケーションにアクセスできてしまうことに注意してください。deviseは、パスワードにランダムなトークンを生成し、データベースにトークンのdigestのみを保存してくれることを覚えておきましょう。」つまり、セキュリテイの強化まで勝手にやってくれると!
Other ORMs
deviseは、ActiveRecordとMongoidをサポート。
他のORMを利用するためには、initializerファイルでrequireします。モンゴロイドって、また調べてみます。
Additional information
Heroku
Ruby on Rails 3.2のHeroku上でdeviseを使う時は以下のように設定が必要です!
config.assets.initialize_on_precompile = falseWarden
deviseはWardenをベースにしています。Wardenは、Daniel Neighmanによって構築されたRackベースの認証フレームワークです。Wardenについては以下が参考になります。
https://github.com/hassox/wardenコントリビューター
deviseにはたくさんのコントリビューターがいます。すごい数や・・・
https://github.com/plataformatec/devise/graphs/contributors
ライセンス
MIT License. Copyright 2009-2019 Plataformatec. http://plataformatec.com.br
You are not granted rights or licenses to the trademarks of Plataformatec, including without limitation the Devise name or logo.
読み終えて
正直、途中からまだまだわからないことだらけでした・・・
理解が浅はかな点がいくつか見えたので、deviseを使う際にはもう一度公式ドキュメントを読んで、
ぜひマスターしたいものです。ここまで読んでいただき、ありがとうございました。




