20191101のRailsに関する記事は15件です。

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のHostAuthorizationokcomputer gemを利用し、/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となりました!

もう少しスマートな対応方法ありましたら、教えていただけると嬉しいです

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

[メモ]Railsで特定のページで条件分岐する方法

例えば、page1というページの場合に特定の処理を行いたい場合

<% if request.path.include?('page1') %>
    [処理を書く]
<% end %>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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: true

object-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】動画データのメタデータのみ読み込みされる
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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からの連番になります。

****************************************
プログラミング初級者が自身の備忘録も兼ねて書いた記事ですのでご指摘等ありましたら気軽にコメントください。なにか同様の問題でお困りの方にお役に立てたら嬉しいです。

テーブルのリレーションによっては本記事の番号振り直し自体がエラーになる場合がありますので、テーブル同士のリレーションおよび関係性を確認して記述の修正、一時コメントアウト等適宜行い、実行してください。

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

テーブルの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からの連番になります。

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

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からの連番になります。

****************************************
プログラミング初級者が自身の備忘録も兼ねた記事ですのでなにか同様の問題でお困りの方にお役に立てたら嬉しいです。

テーブルのリレーションによっては本記事の番号振り直し自体がエラーになる場合がありますので、テーブル同士のリレーションおよび関係性を確認して記述の修正等適宜行い、実行してください。

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

【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」を導入

Gemfile
gem 'i18n-js'
terminal
$ bundle install

JavaScriptでI18nを利用する場合、config/ja.ymlを直接使える訳ではなく、.jsに変換してそれを読み込んで利用します。
i18n-jsはその変換出力のためのgemです。

i18n-js.ymlを作成

どのように変換出力するかのルールを設定するファイルです。

公式などを見ると一般的に使われる設定ではtranslation.jsという1つのファイルに全ての言語の設定を詰め込むため、読み込みが重くなってしまいます。
なので言語別に出力されるよう設定します。

config/i18n-js.yml
translations:
- file: "app/assets/javascripts/i18n/%{locale}.js"

許可するlocaleを限定

後述するrake i18n:js:exportをこのまま実行してしまうと、許可されている全ての言語のjsファイルが生成されてしまいます。(私の場合90個ぐらいでした:imp:
日本で開発されている方であれば、日本語と英語だけで十分かと思いますので今回はその2言語のみ生成されるようにします。

config/application.rb
# デフォルトのlocaleを日本語(:ja)にする
config.i18n.default_locale = :ja

# 許可するlocaleを日本語(:ja)と英語(:en)に限定する
config.i18n.available_locales = %i[ja en]

これでja.ymlja.jsに、en.ymlen.jsに変換出力されるようになります。

rake i18n:js:exportで出力

js用のlocaleファイルを変換するコマンドを実行します。

terminal
$ rake i18n:js:export

スクリーンショット 2019-10-31 19.03.00.png
en.jsja.jsは確認できましたか?
中を見てみるとyamlファイルで定義しているものを数行に凝縮していますね。
最終的にtメソッドはこれらのファイルからマッチするものを探してきます。

i18n.jsを編集

同時にpublic/javascript/i18n.jsも出来ました。
機能の根幹となるメソッドがたくさん書いてあるファイルです。

この中からdefaultLocalelocaleを必要に応じて変更します。
railsのgemi18nとは別物なので、別途定義が必要です。
スクリーンショット 2019-11-01 10.45.08.png
日本語であれば"ja"ですね。

また、以下については通常行わないのかもしれませんが、
public/javascript/i18n.jsapp/assets/javascript/i18n.jsに移動してください。

私はしばらくconsoleで確認しても

  • i18nが認識されない
  • default_localeが"en"から変わらなかった

ので、i18n/ja.jsと同じapp/assets/javascript/に置くことで解決しました。

もしより良い解決策をご存知の方いらっしゃいましたらコメントお願いいたします。:cop_tone1:

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のデベロッパーツールで画像のように打ち込んで確認してみましょう。
スクリーンショット 2019-11-01 10.35.10.png
2つ目はご自身のアプリで定義してあるものを適当に呼び出してみてくださいね。

vueファイルでI18nコマンドを省略するためのmixinを作成

i18n-jsによりjsファイルでは使えるようになりましたが、
vueファイルではまだ使えません。
そこでmixinを作成し、そのjsファイルを読み込むことでvueファイルでも使えるようにします。
どうせなら省略形でもメソッドが動いてくれるように工夫してみましょう。

mixins/i18n.js
export 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.rb
config.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

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

rails generateでのpolymorphic associationの生成

要約

要はreferencesを使ってpolymorphic associationを作りたい

model構成

UserがいいねするためのLikeモデルで、いいねする対象がpolymorphicになっている

書き方

bundle exec rails g model Like user:references likable:references{polymorphic}:index

### 参考
https://railsguides.net/advanced-rails-model-generators/
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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_sandbox

User の CRUD を作成する

$ bin/rails g scaffold User name

request spec を編集する

spec/requests/users_spec.rb を編集します。

ここで response.content_typeresponse.media_type のテストを追加していることに注意してください。

spec/requests/users_spec.rb
require '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.rb

Rails 5 では

Rails 5.2.3 では、 content_typetext/html を返すため spec が失敗します。
つまり、以下のように書くと、 spec が通ります。

spec/requests/users_spec.rb
      expect(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

参考情報

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

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のアセットパイプラインについて解説する


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

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は

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

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 execpipenv 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

で良いようです。

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

Railsの便利機能「Application Template」で rails newと初期設定を自動化できた!

Railsアプリの新規作成から初期設定までをrails newrails 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.rb

GitHubなど外部からテンプレファイルを取得する場合

$ 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

-Bbundle 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の初期設定の自動化を夢見てきたので感激です(´;ω;`)

以上です。

参照

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

rescueでエラーを拾ってくれない問題

BackGround

Postmanを使ってRailsのアクションを設計どうりに処理してくれるかテストしていました。
問題になったのはこのuser_controllerのshowアクション

user_controller.rb
 class 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!って返って来るはず♪
724920E8-E512-415C-BC37-CF18099F38E6_1_105_c.jpeg
ん?404???error!じゃなくて??
404までは期待どうり。だけどそのあとの処理が拾われていない??
rescueとは・・・

Research Solution

大人しく、チャレキャラのメンターさんに質問しました。
その中でも、日頃お世話になっているアルバイト先のBig Bossに助けてもらいました?

Solution

user_controller.rb
 class 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に変更

724920E8-E512-415C-BC37-CF18099F38E6_1_105_c.jpeg
できた!!!

Why??

理由としては、userがnillなのに、errorメソッドを呼んで、errorを返してしまうってこと*らしい
確かにnillってオブジェクトでもないわけだからそれにメソッド呼んでも処理ができるはずはない。
だもんで、戻り値にエラーを吐かないようにしてかつ、statusを返すようにしたわけですね!

+ α

そもそも、rescueは多用しないほうがいいという知見をいただきました。
自分も使い慣れてないし、当分はif-else分岐で行こうかと思い、書き直してみよう!

user_controller.rb
 class 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

チャレキャラのメンターさん達みたいになりたい

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

【Ruby on Rails】gem「devise」のREADMEを読んでみた

はじめに

オープンソースのソフトウェアやプログミング言語、ライブラリには、間違いなく公式のドキュメントが存在します。
学習のために無料のラーニングシステムを使うこと、書籍を購入することもいいですが、

個人的には、公式ドキュメントには必ず一度は目を通すべきものだと思ってます。

なぜなら出版されてしまった本とは異なり、常に最新の状態にアップグレードされ、多くの人が目にするので間違いが日々修正されているからです。

英語が読めない? 長くて読む気がでない? ならばググりましょう! 
例えば英語がわからないなら、この世の中便利な時代なので、英語のドキュメントについてすでに読んだ人の記事などが検索してヒットするはずです)

やったこと

Ruby on Railsの開発環境下で、認証機能を実装したい際に利用することが多いgem「devise」のREADMEを読んでみました。
※2019年10月時点の情報です。

https://github.com/plataformatec/devise

deviseが持っているモジュール(簡単に言えば機能)

  1. Database Authenticable: サインインに必要なパスワードを暗号化し、DBに保存してくれる機能
  2. Omniauthable: OmniAuthをサポートしてくれる機能(今回の記事ではあまり触れません)
  3. Confirmable: サインインの際,そのアカウントが確認済みか否かチェックし,メールを送信する機能
  4. Recoverable: ユーザーのパスワードをリセットに関する機能
  5. Registerable: 登録プロセスを通りユーザーがサインアップした後、ユーザー情報の編集や削除ができる機能
  6. Rememberable:ユーザー情報をcookieに保存できるよう、トークンを生成・削除してくれる機能
  7. Trackable: サインイン回数、サインイン時間、IPアドレスを保存する機能
  8. Timeoutable:セッションの有効期限を一定時間で切る機能
  9. Validatable: email: emailとパスワードのバリデーションのための機能
  10. 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
end
class 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
end

deviseは、サインインの成功・失敗時に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'
end

deviseのマッピングはするけど、skipして何も設定しない。
つまりcurrent_userだけのルーティングを設定したいなど任意のルーティングを設定するとき
以下のように記述するだけ。

devise_for :users, skip: :all

I18n

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
end

RSpecを利用している場合、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 :user

RSpecは、IntegrationHelpersモジュールを:feature specsに持っているらしい・・・

RSpec.configure do |config|
  config.include Devise::Test::IntegrationHelpers, type: :feature
end

RSpecでの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 = false

Warden

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を使う際にはもう一度公式ドキュメントを読んで、
ぜひマスターしたいものです。

ここまで読んでいただき、ありがとうございました。

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