20191101のRubyに関する記事は17件です。

【はじめてのWebAPI】RubyでのHTTPClientの基本構文

はじめに

RubyでHTTPClientを使うときの基本構文について記載しました。
Web APIを使って外部データを引っ張るための第一歩!

この記事が役立つ方

  • Web APIを触ったことがなくて
  • HTTPクライアントを使ったことのない
  • Ruby初心者

この記事のメリット

  • 外部からデータを引っ張る第一障壁をクリア出来る

環境

  • OS: macOS Mojave version 10.14.6
  • ターミナルのシェル: zsh
  • Ruby 2.6.3

HTTPClientとは?

Rubyで標準で入っているnet/httpよりも機能面が充実しているHTTPクライアントライブラリ。

これを使うことにより、プログラムで外部へHTTPリクエストを送ることが出来るようになります。

導入

まずは以下のようにgemをインストールして下さい。

gem install httpclient

基本コード

以下が基本のコードです。
ここからは活用したいデータによって書き方が異なります。

# HTTPClientを呼び出す
require 'httpclient'

#ベースとなるURLを設定(e-Statからデータを引っ張る場合)
url = 'https://api.e-stat.go.jp/rest/2.1/app/json/getStatsData'

# 新しいインスタンスを作成
client = HTTPClient.new

#クエリの設定(appIdとstatsDataIdはサンプルです。)
query = { 
  'appId' => 'XXXXXXXXXXXXXXXXXXX'
  'statsDataId' => '0000000000'
}
#APIリクエスト
res = client.get(url, query)
#ハッシュ化して返す
return JSON.parse(res.body)

おわりに

今回はかなり部分的な内容となってしまったので、また後日加筆修正します。

e-Statのデータを取り出す方法についてもまとめるつもりです。

外部データを引っ張ると、ハッシュ in 配列 in ハッシュみたいな複雑な構造が多く、勉強になりますね。
政府統計の総合窓口(e-Stat)−API機能へようこそ | 政府統計の総合窓口(e-Stat)−API機能

参考にさせて頂いたサイト(いつもありがとうございます)

Class: HTTPClient — Documentation for httpclient (2.8.3)
Ruby HTTPクライアントの比較表 - Qiita
Rubyを使って天気予報を取得してみた - Qiita

  • このエントリーをはてなブックマークに追加
  • 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で続きを読む

privateなgemサーバの構築とgem作成から利用まで

privateなgemサーバをローカルでDockerで起動し、オリジナルのgem作成からそれを利用するまでの流れを試しましたので、手順を残しておきます。この記事の一番下に載せたリンクを参考にしました。

3段階の手順です。手順ごとにディレクトリを作ります。

  • Dockerイメージ作成とgemサーバ起動 (Gem in a Box)
  • gemを作成してgemサーバに登録 (gem inabox)
  • そのgemを利用

Docker、Ruby、gem、bundleなどはすでに入っているものとします。

Dockerイメージ作成とgemサーバ起動

Gem in a Boxというプライベートなgemサーバを作るツールを使います。

$ mkdir docker
$ cd docker

このディレクトリに以下の3ファイルを作成します。

Dockerイメージ作成のためのファイル

Dockerfile
FROM ruby:2.6.4

RUN mkdir /geminabox-data
COPY . /geminabox-app

WORKDIR /geminabox-app
RUN bundle install

Dockerイメージの中にGem in a Boxをインストールするためのファイル

Gemfile
source "https://rubygems.org"

gem "geminabox"

Gem in a Boxの設定ファイル

config.ru
require "rubygems"
require "geminabox"

Geminabox.data = "/geminabox-data"

use Rack::Session::Pool, expire_after: 1000 # sec
use Rack::Protection

run Geminabox::Server

この3ファイルのあるディレクトリでDockerイメージを作成します。

$ ls
config.ru  Dockerfile  Gemfile
$ docker build -t geminabox .

以下のコマンドでDockerイメージを起動すると、Gem in a Boxが動きます。ターミナルにはそのログが吐き出されます。

$ docker run -it --rm -p 9292:9292  geminabox /usr/local/bundle/bin/rackup --port 9292 --host 0.0.0.0

Gem in a Boxで動く流れをつかむための一時的な環境です。このコマンドでDockerを起動してgemを登録しても、Dockerを止めたらgemは消えてしまいます。

このGem in a Boxを動かしたまま、次以降の手順に入りますので別のターミナルからもとのディレクトリ(dockerディレクトリの上の階層)に入ります。

gemを作成してgemサーバに登録

gemを作成

以下のコマンドでgem作成のテンプレートを作ることができます。パラメータはgemの名前です。単純にhelloworldだとすでに誰かがRubyGemsで公開しているgemと名前が被ってしまって試行錯誤するには混乱しやすいので、被らなそうなものにして試します。

$ bundle gem helloworld-suzuki
$ cd helloworld-suzuki

helloworld-suzuki.gemspecというファイルが生成されているのでそれを編集します。TODOという記述が含まれているといけないらしいので、その個所を以下のように書き換えます。

helloworld-suzuki.gemspec
  spec.summary       = %q{Hello, world!}
  spec.description   = %q{Hello, world!}
  spec.homepage      = "http://www.example.com/"

spec.metadataの設定にもTODOが含まれますが、それらの記述4行をまるごと消してしまいました。

パッケージのソースの本体となるファイルにサンプルのメソッドを書きます。以下のようにしました。

lib/helloworld/suzuki.rb
require "helloworld/suzuki/version"

module Helloworld
  module Suzuki
    class Error < StandardError; end
    def self.say
      print "Hello, World!\n"
    end
  end
end

以下のコマンドを実行するとパッケージが生成されます。

$ rake build

pkg/helloworld-suzuki-0.1.0.gemにファイルが生成されます。

gemサーバに登録

できあがったパッケージファイルをさきほどのDockerで動いているGem in a Boxに登録したいと思います。ブラウザでhttp://localhost:9292/にアクセスしてもいいらしいのですが、ここではコマンドでやってみます。

gem inaboxというコマンドでパッケージファイルをGem in a Boxに登録できるのですが、このコマンドは普通のgemをインストールしただけの環境にはなくて、geminaboxをインストールしないといけないようです。なので、ローカルにインストールします。

$ gem install geminabox

繰り返しですが、あくまでgem inaboxコマンドを使えるようにするためのインストールで、Gem in a Box自体はさきほどのDockerの中でGemfileをもとにインストールした環境ですでに動作中です。

次にgem inaboxコマンドでパッケージファイルをGem in a Boxに登録します。

$ gem inabox --host http://localhost:9292/  pkg/helloworld-suzuki-0.1.0.gem

これを実行すると、Dockerを実行しているターミナルにアクセスログが出力されます。

次の手順に入るためにいったん上の階層に戻ります。

$ cd ..

そのgemを利用

別のディレクトリを作成します。

$ mkdir sample
$ cd sample

先ほど作成したgemを利用するためのGemfileを作成します。

Gemfile
source "https://rubygems.org"

gem "helloworld-suzuki"

helloworld-suzukiという名前のgemは一般のRubyGemsにはないはずですので、このままですとエラーになるはずです。

$ bundle install
Fetching gem metadata from https://rubygems.org/.
Fetching gem metadata from https://rubygems.org/.
Could not find gem 'helloworld-suzuki' in any of the gem sources listed in your Gemfile.

はい、エラーになりました。

$ gem sources -a http://localhost:9292/

これを実行するとgemの取得元サーバが追加されます。以下のコマンドで設定状況を確認できます。

$ gem sources
*** CURRENT SOURCES ***

https://rubygems.org/
http://localhost:9292/

~/.gemrcというファイルにこの設定が書かれています。

このファイルにではなく、今回のsampleプロジェクトのみに適用したい場合はGemfileに以下のように書きます。

Gemfile
source "https://rubygems.org"

source "http://localhost:9292" do
  gem "helloworld-suzuki"
end

またはこのように書いてもよいです。

Gemfile
source "https://rubygems.org"

gem "helloworld-suzuki", :source => "http://localhost:9292"

helloworld-suzukiというgemだけhttp://localhost:9292からダウンロードすることを指定する設定です。複数のgemをhttp://localhost:9292からダウンロードする場合には1つ目のブロックでの書き方が便利です。

これをもとに再度bundle installを実行します。

$ bundle install
Fetching gem metadata from http://localhost:9292/..
Fetching gem metadata from https://rubygems.org/.
Resolving dependencies...
Using bundler 2.0.2
Fetching helloworld-suzuki 0.1.0
Installing helloworld-suzuki 0.1.0
Bundle complete! 1 Gemfile dependency, 2 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.

ちなみに以下のように書いてもとりあえずは動きますが、Gemfileに書いたすべてのgemをいちいち2つのサーバに見に行ってしまいます。

Gemfile
source "https://rubygems.org"
source "http://localhost:9292"

gem "helloworld-suzuki"

この環境でRubyを動かしてみます。

$ bundle exec ruby -rhelloworld/suzuki -e 'Helloworld::Suzuki.say'
Hello, World!

無事動きました。

参考

DockerでGem in a Boxを起動するのは次の記事を参考にしました。
Gem in a BoxでプライベートなRubyGemsをDockerで簡単に構築する - YOMON8.NET

今回の私の記事ではDockerでその場で動かしましたがちゃんとdaemon化するには次の記事が参考になります。
privateなgemサーバー構築のお話 - Qiita

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

ruby製静的サイトジェネレータjekyllをdocker-composeで起動する

会社を立ち上げたので会社サイトを作成するために静的サイトジェネレータを使用することにしました!
ruby案件お待ちしております!
使い慣れているrubyとdockerで立ち上げた記録です。

事前準備

Dockerfile
FROM ruby:2.5
RUN apt-get update -qq
RUN mkdir /myapp
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
COPY . /myapp

EXPOSE 4000
docker-compose.yml
version: '3'
services:
  web:
    build: .
    command: bundle exec jekyll serve --host=0.0.0.0
    volumes:
      - .:/myapp
      - bundle:/usr/local/bundle
    ports:
      - 4000:4000

volumes:
  bundle:

--host=0.0.0.0がないと、localhostでアクセスできないので要注意です。
jekyllはデフォルトで4000ポートです。

Gemfile
source "https://rubygems.org"

gem "jekyll"

空のGemfile.lockの作成

touch Gemfile.lock

セットアップ

docker-compose build

generateコマンドでjekyllファイルを生成
.--forceでDockerfileなどと同じ階層に作成します。
jekyll new mysiteのようにするとmysiteディレクトリに作成されます。

docker-compose run --rm web jekyll new . --force
$ pwd
corporate_site

$ ls
404.html  Dockerfile  Gemfile  Gemfile.lock  _config.yml  _posts  _site  about.markdown  docker-compose.yml  index.markdown

ファイルが作成されました!

起動

docker-composeを使用しているので、下記コマンドで起動可能です。

docker-compose up

http://localhost:4000
にアクセスします

Screenshot from 2019-11-01 15-59-30.png

???

  • このエントリーをはてなブックマークに追加
  • 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で続きを読む

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で続きを読む

ruby メソッドの作り方

ドットインストール(https://dotinstall.com/)を見て
自分なりにまとめたものです。

メソッド

def  sayHello
    puts "Hello word!!"
end

sayHello

実行結果:Hello word!!
 

  • メソッドを呼び出すときはメソッド名書くだけで呼びだせる
def  sayHello(name)
    puts "Hello #{name}!!"
end

sayHello ("Angela") #()は省略可能
  • 引数を渡すことも出来る

実行結果:Hello Angela!!

def  sayHello(name = "Angela")
    puts "Hello #{name}!!"
end
# nameを渡されなかった時に"Angela"が渡される
sayHello 

  • 引数にデフォルト値も設定できる

実行結果:Hello Angela!!

def  sayHello(name = "Angela")
    return "Hello #{name}!!"
end

p sayHello
  • メソッドは最後に評価された値を返す
  • returnで返されたのは"Hello #{name}!!"  p で返されたものを表示している。

実行結果: "Hello Angela!!"

ローカル変数の話

  • whetherはローカル変数だからdef~endの中でしか使えない
def  sayHello(name = "Angela")
    weather = "sunny"
    return "Hello #{name}!!"
end

p sayHello
p weather

実行結果:エラー

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

ruby while、for、loop、break、nextについて

while

 i = 0
 while i < 10 do
     puts "#{i}: hello" 
     i += 1
 end

※ 「i = i + 1」は「 i += 1 」と同様の意味

times

  • timesは数字オブジェクトのメソッド
10.times do |i|
puts "#{i}:hello"
end
  • do~endの中で繰り返したい処理を繰り返す
  • do の後で|i|を定義することでwhileの時と同じように何回ループしているかが分かる

上記のtimesは1行で書くことが出来る

10.times { |i|puts "10#{i}:hello" }

for文

  • doは省略出来る
 for i in 18..20 do
     p i
 end
 for color in ["red", "blue"] do
     p color
 end

 for name,score in {aratomai: 200, Mikkey: 500} do
     puts "#{name}: #{score}"
 end

実行結果:

  • 18
  • 19
  • 20
  • "red"
  • "blue"
  • aratomai: 200
  • Mikkey: 500

eachメソッドへの書き換え

 (18..20).each do |i|
     p i
 end
 ["red", "blue"].each do |color|
     p color
 end
 {aratomai: 200, Mikkey: 500}.each do |name, score|
     puts "#{name}: #{score}"
 end

実行結果:
上記と同じ

loop

  • breakしない限り永久ループ
i = 0
 loop do
     p i
     i += 1
     end

breakとnextについて

  • iが5になった時に処理が終わる
10.times do |i|
    if i == 5
        break
    end
    p i
end

実行結果:
0
1
2
3
4

  • iが5の時だけ処理をスキップする
10.times do |i|
    if i == 5
        next
    end
    p i
end

実行結果:
0
1
2
3
4
6
7
8
9

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

Ruby独特の代入演算子 ||= の意味について説明してみた

代入演算子とは

Rubyも含め、多くのプログラミング言語では、x1を加算する操作を以下のように記述1できます。

x = x + 1

この操作は、Ruby(ほか多くのプログラミング言語)において、以下のような短縮表記が可能です。

x += 1

このときの+=という演算子、並びに加算以外の演算に対して同様の動作を行うように定義された演算子を総称して「代入演算子」と呼びます。

+=以外の代入演算子

Rubyにおいては、+=以外の代入演算子としては以下のようなものが存在します。

# rails console
>> x = 1
=> 1
>> x += 1
=> 2
>> x *= 3
=> 6
>> x -= 8
=> -2
>> x /= 2
=> -1

||=という演算子の意味

一般的な代入演算子と異なり、こちらはRuby独特の代入演算子です。例えば以下のような形で使われます。

# rails console
>> @foo = nil
=> nil
>> @foo ||= "bar"
=> "bar"

上記のコードの意味は、下記のコードの意味と同じです。

# rails console
>> @foo = nil
=> nil
>> @foo  = @foo || "bar"
=> "bar"

その動作は以下の通りです。

  • 実行時点で左辺の変数がtrueと評価される場合
    • 代入は行わない
    • 右辺の式は評価しない
  • 実行時点で代入先の変数がfalseと評価される場合
    • 右辺の式を評価する
    • 右辺の式の評価結果を左辺の変数に代入する

Rubyにおいては、「変数の値がnilであれば変数に代入するが、nilでなければ代入しない」という操作が頻繁に登場します。同じくRubyの特徴である「falsenil以外の全てのオブジェクトは、真偽値として評価した場合、常にtrueとして評価される」という特徴と合わせて、このような場合に||=という演算子の存在が非常に便利なのです。


  1. なお、Ruby以外の言語では、x = x + 1x++と表記できるものがあります。こうした使い方をする++を「インクリメント演算子」と呼びます。しかしながら、Rubyではx++のような表記を使うことはできません。 

  • このエントリーをはてなブックマークに追加
  • 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で続きを読む