- 投稿日:2020-04-05T23:28:21+09:00
Dockerを使ってrailsのAPIモードの環境構築
はじめに
今回は、Dockerを使ってRailsのAPIモードの環境構築をしていく記事です。
コマンド、設定などを詳細に書いていきます。記事の最後までの所要時間は30分以内です。意外と簡単でした。
APIモードとは
APIモードとはRails5から追加された機能で、APIのようなRailsアプリケーションを作れる機能だそうです。
MVCのうち、モデルとコントローラーのみが作成されます。
APIモードで作成されたアプリのURLにリクエストを送ると、json形式のデータがレスポンスとして返ってきます。環境構築
では、環境構築をしていきます。
$ mkdir sample_app $ cd sample_app $ docker pull ruby:2.5.1 $ docker run --rm -v "$PWD":/usr/src/sample_app -w /usr/src/sample_app ruby:2.5.1 bundle init $ docker build -t developer_name/sample_app .ここで、
Dockerfile
、docker-compose.yml
、Gemfile
、Gemfile.lock
の4つのファイルが必要となるので、sample_app
以下にそれぞれ作っていきます。$ touch 各ファイル
Dockerfile
のsample_app
はそれぞれのディレクトリ名に変更してください。Dockerfile# Debianがベースのrubyイメージを指定 FROM ruby:2.5.1 # 必要なものをインストール RUN apt-get update -qq && apt-get -y install \ build-essential \ libpq-dev \ nodejs \ mysql-client # rails用のディレクトリを作成 RUN mkdir /sample_app # ローカルマシン(Mac)からコンテナの中にファイルをコピー COPY Gemfile /API_sample COPY Gemfile.lock /sample_app # 作業ディレクトリを指定 WORKDIR /sample_app # 上でコピーしたGemfileに従ってGemをインストール RUN gem install bundler && bundle install続いて、
docker-compose.yml
です。
MYSQL_ROOT_PASSWORD
は、後で作成するdatabase.yml
のパスワードに合わせます。docker-compose.ymlversion: '3' services: web: build: . ports: - "3000:3000" depends_on: - db volumes: - .:/API_sample command: bundle exec rails s -p 3000 -b '0.0.0.0' db: image: mysql:5.7 volumes: - mysql_data:/var/lib/mysql/ environment: MYSQL_ROOT_PASSWORD: password ports: - "3306:3306" volumes: mysql_data:Railsアプリの作成
新規アプリ作成時に、後ろに
--api
をつけるとAPIモードでアプリが作成されます。$ docker-compose run web rails new . --force --database=mysql --api $ docker-compose run --rm web rails generate scaffold User name:string $ docker-compose run --rm web rails db:create $ docker-compose run --rm web rails db:migratescaffoldでUserを作ったら、ファイルを見てみましょう。
普通のrailsアプリで作られるassets
やview
が無いことが確認できると思います。ページを開く
それでは、アプリをlocalhostで開いてみましょう。
http://localhost:3000/users真っ白なページに、
[]
とだけ表示されているはずです。
これは、データが空であるということを表しています。では、
curl
コマンドでデータのリクエストを送ってみます。curlはURLシンタックスを用いてファイルを送信または受信するコマンドラインツールである。(Wikipediaより)
下記の例を簡単に説明すると、指定したURLに対して、POSTメソッドを使用してターミナルからjsonファイルを送信しているということです。
$ curl -X POST -H "Content-Type: application/json" -d '{"name": "hoge"}' http://localhost:3000/usersそして、http://localhost:3000/users に接続すると
[{"id":1,"name":"hoge","created_at":"","updated_at":""}]
というデータが表示されると思います。(日付はカットしました)これで完了です!意外とあっさりできますよね。
他にも、GET、PUT、DELETEも使えるので色々と試してみてください。感想
APIモードと聞いて最初はよくわからないな、怖いなと思っていました。
ですが、やってみると簡単ですし、今まで深く考えていなかったHTTPについて調べたり知ったりするきっかけになったので良かったです。駆け出しエンジニアにとっても簡単なのでぜひやってみてはいかがでしょうか?
- 投稿日:2020-04-05T23:24:48+09:00
MacにてRailsの環境構築を試みる
はじめに
Ruby on Railsの環境構築について、最低限必要なソフトウェアとインストールのコマンドについてまとめてみました。
Rails環境構築の全体像が掴むための記事となっています。環境構築に必要なソフトウェア用語について
railsの環境構築に必要なソフトウェアは下記に示すものになります。
・Xcode
・homebrew
・rbenv
・ruby
・gem
・rails
・bundlerそれぞれの関係性は下図のようになっています。
Xcode
Apple社が開発・リリースしている、アプリケーション開発に特化したソフトウェアです。
homebrew
MacOS X上でソフトウェアのインストールを単純化するためのパッケージ管理システムのことです。
わかりやすく言うと、ソフトウェアをインストールする際に、パッケージやライブラリの依存関係をうまいこと調整してインストールしてくれるシステムのことです。
ソフトウェアをインストールする前にこいつをインストールしておきましょう。[homebrewとは](https://qiita.com/omega999/items/6f65217b81ad3fffe7e6}
rbenv
rubyのバージョンを切り替えるツール。
環境ごとやディレクトリごとにバージョンを切り替えることもできる。ruby
プログラミング言語のひとつ。オブジェクト指向型のスクリプト言語。
ちなみにスクリプト言語とは、javaやC言語のようにコンパイルすることが不要で、簡単に実行できる特徴を持った言語のことをいいます。比較的簡単に実装できるため、比較的取り組みやすいプログラミング言語になります。gem
gemはある機能がパッケージされたものになります。
パッケージとは、プログラムの部品であり、便利な機能をひとまとめにしたものになります。
例えばユーザーログインシステムを作成するための機能がまとまったgemがあり、インストールすることで簡単にログイン機能を実装することができるようになります。rails
rubyのフレームワークです。Webシステムなどを開発するための機能がまとまっているgemです。
rubyでは主にこのフレームワークを用いて開発が進められています。bundler
gemを管理するためのツールです。
gemをインストールする際に必要になります。各ソフトウェアのインストール
Command Line Tools for Xcodeのインストール
まずはターミナルを開き、下記コマンドによりXCodeをインストールします。
$ xcode-select --installhomebrewのインストール
homebrewの公式サイトからインストールを行いましょう。
https://brew.sh/index_ja.htmlこのページに書かれているインストールのコマンドをターミナルに打ち込んでインストールを行いましょう。
rbenvのインストール
次にrubyのバージョンを管理するrbenvをインストールしましょう。
ちなみに「rbenv」の読み方はだいたい「アールビーエンブ」と呼ばれているようです。
確かではありませんが、
"rb"→ruby
"env"→environment(環境)
の2つをつなげてrbenvとなっていると思われます。
rubyの環境を整えると言う意味合いで使われているのであろうと推測できます。インストールのコマンドは以下になります。
rbenvとともに、ruby-buildというrbenvのプラグインも同時にインストールしておきましょう。$ brew install rbenv ruby-build正常にインストールされたかどうかは
rbenv -vを打ち込み、バージョンが確認できればOKです。
PATHを通す
ここでPATHの設定をしておきます。
PATHを通すとは、あるファイルの実行を、ファイル名を打ち込むだけで実行できるようにする設定です。ファイルをターミナルから開く際には、そのファイルが置かれている場所のフルパスを打ち込むことが必要です。
しかし毎回毎回フルパスを書くのは効率が悪いですね。
そこでPATHの設定をしておくことでファイル名だけで実行ができるようになると言う仕組みです。
このことを「PATHを通す」といいます。
※参考記事
https://qiita.com/sta/items/63e1048025d1830d12fd・rbenvのPATHを通すコマンド
$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile・ターミナルを起動したときに自動的にrbenvを使用できるようにする設定
$ echo 'if which rbenv > /dev/null; then eval "$(rbenv init -)"; fi' >> ~/.bash_profile※参考記事
https://qiita.com/soarflat/items/d5015bec37f8a8254380最後にsourceコマンドを打ち、ファイルを再読み込みしておきましょう。
source ~/.bash_profilerubyのインストール
rbenvがインストールできたら早速rubyをインストールします。
先ほどインストールしたrbenvのコマンドを使い、バージョン管理しながらインストールを行っていきます。
rubyをインストールする前に、現在インストールできるrubyのバージョンを確認しておきます。
$ rbenv install -l下図のようにインストール可能なバージョンが一覧で表示されます。(一部抜粋)
それではインストールしたいRubyのバージョンを指定して実行します。今回はバージョン2.6.5をインストールすることにします。$ rbenv install 2.6.5こちらもインストールできたかの確認をしておきましょう。
ruby -vgemのインストール
下記の2つのgemをインストールしていきます。
・bundler
・rails$ gem install bundler今回はrailsの5.2.0のバージョンをインストールすることにします。
$ gem install rails --version="~>5.2.0"こちらも
$ rails -vによりインストール完了の確認をしておきましょう
最後にデータベースのインストール
最後にデータベースのインストールをして環境構築は終了です!
今回はよく使われるmysqlというデータベースをインストールしておきます。
バージョンは5.7をインストールします。$ brew install mysql@5.7こちらもPATHを通す作業を行っておきます。
echo 'export PATH="/usr/local/opt/mysql@5.7/bin:$PATH"' >> ~/.bash_profileその後下記コマンドにより、設定の再読み込みをします。
source ~/.bash_profileここまでできたらmysqlを起動するコマンドを打ち込み、起動させましょう。
$ brew services start mysql@5.7下記のように表示されれば正しく起動しています。
Starting MySQL SUCCESS!環境構築終了!
簡素的ですが、これで一通りrailsを使っていく環境が整いました。
環境構築はコマンドを実行していくだけの簡単な作業に思えるかも知れませんが、様々なソフトウェアをインストールする際にエラーが発生しやすく初心者殺しと言われる1つの大きな壁です。
今回は最低限必要なソフロウェアをインストールするコマンドについて記しましたが、
おそらくインストールを行っている途中でエラーが発生してうまく行かないところが出てくるかも知れません。その時はエラーの内容を調べてどうにか頑張ってみてください。
以上、簡単ですが環境構築の手助けになればと思います。
- 投稿日:2020-04-05T23:13:21+09:00
[Rails]画像選択時にプレビュー表示
本記事投稿のいきさつ
アプリの中で画像投稿機能を実装したとき、ただフォームを作成するだけでは画像を選択しても表示がされず何を選んだのか確認をすることが出来ません。
そこで、画像を選択した時点でプレビュー表示することができればいいなと思い、実際に機プレビュー機能を作成したため、記録として残したいと思います。
今回はユーザーのプロフィール画像の編集画面を想定します。
そのため、既に登録されている画像は最初からプレビューさせた状態で表示をさせます。前提
- 変種画面はprofile_edit.html.haml
- 画像の保存先は Usersテーブル: imageカラム
- file_field本体は隠し、画像が選択されていない時はiconを、 選択されている時はプレビュー画像をクリックすることで画像選択できるようにします。
- jQueryを使用しますが、必要なGemのインストール等は既に出来ているとします。
- ユーザー機能はDeviseを使用しています。
- cssは今回の内容に含まれません。
フォーム作成
まず、今回はhamlでビューのフォームを作成します。
profile_edit.html.haml= form_for current_user, url: {action: 'profile_update'} do |f| .form-group .image_form .image_form__contents -# ラベルでfile_fieldとicon、プレビュー画像を紐付けます = f.label :image, class: 'image_label' do .prev-contents -# 既に登録されている画像があれば表示をさせます - if current_user.image.present? .prev-content = image_tag current_user.image.url, alt: "preview", class: "prev-image" -# 既に登録されている画像がなければiconを表示させます - else = icon('fas', 'image', class: 'photo-icon') -# file_fieldはdisplay: none;で隠します = f.file_field :image, class: 'image_form__contents__field hidden_file'FileReader
今回はFileReaderを使用します。
FileReaderとはHTML5世代の機能でユーザーのPC内にあるファイルやバッファ上の生データに対して、読み取りアクセスを行えるオブジェクトです。jsファイルの編集
今回はimage_preview.jsを作成して、そこに記述していきます。
image_preview.js$(document).on('turbolinks:load', function () { $(function () { // 画像をプレビュー表示させる.prev-contentを作成 function buildHTML(image) { var html = ` <div class="prev-content"> <img src="${image}", alt="preview" class="prev-image"> </div> ` return html; } // 画像が選択された時に発火します $(document).on('change', '.hidden_file', function () { // .file_filedからデータを取得して変数fileに代入します var file = this.files[0]; // FileReaderオブジェクトを作成します var reader = new FileReader(); // DataURIScheme文字列を取得します reader.readAsDataURL(file); // 読み込みが完了したら処理が実行されます reader.onload = function () { // 読み込んだファイルの内容を取得して変数imageに代入します var image = this.result; // プレビュー画像がなければ処理を実行します if ($('.prev-content').length == 0) { // 読み込んだ画像ファイルをbuildHTMLに渡します var html = buildHTML(image) // 作成した.prev-contentをiconの代わりに表示させます $('.prev-contents').prepend(html); // 画像が表示されるのでiconを隠します $('.photo-icon').hide(); } else { // もし既に画像がプレビューされていれば画像データのみを入れ替えます $('.prev-content .prev-image').attr({ src: image }); } } }); }); });上記で出てくるDataURISchemeとは、
簡単にいうと、画像やらJavascriptやらそういったHTMLのコンテンツを文字列として定義出来るものです。
以上でで、画像が表示されます。終わり
最後まで見ていただきありがとうございました。
- 投稿日:2020-04-05T22:53:30+09:00
gem annotate の README を翻訳しました
概要
gem annotate の README を翻訳しました。
Annotate (aka AnnotateModels)
下記のファイルの上部あるいは下部に現在の DB スキーマを要約したコメントを追加します。
- ActiveRecord models
- Fixture files
- Tests and Specs
- Object Daddy exemplars
- Machinist blueprints
- Fabrication fabricators
- Thoughtbot's factory_bot factories, i.e. the
(spec|test)/factories/<model>_factory.rb
filesroutes.rb
file (for Rails projects)スキーマコメントは下記のように記載されます。
# == Schema Info # # Table name: line_items # # id :integer(11) not null, primary key # quantity :integer(11) not null # product_id :integer(11) not null # unit_price :float # order_id :integer(11) # class LineItem < ActiveRecord::Base belongs_to :product . . .また、
SpatialAdapter
,PostgisAdapter
,PostGISAdapter
のいずれかを使用したときは、geom
タイプやsrid
タイプのような幾何学的なカラムにも注釈をつけます。# == Schema Info # # Table name: trips # # local :geometry point, 4326 # path :geometry line_string, 4326また、
-r
オプションを渡すと、rake routes
の出力をroutes.rb
にコメントとして追加します。3.Xにアップグレードするとモデルへの注釈が動作しない?
バージョン 2.7.X では、引数が何も渡されない場合は、gem annotate はデフォルトでモデルに注釈を追加していました。
デフォルトでは、gem annotate は routes とモデルが一緒に注釈を追加されることを許可していません。
#647 で変更が追加されました。
詳細はこちらでご覧ください。この問題を修正する方法はいくつかあります。
- CLI を使用している場合は、
--models
を使用してモデルフラグを明示的に渡してください。あるいは
a)
rails g annotate:install
を実行し、デフォルト設定がmodels
オプション'true'
になるように上書きします。b)
lib/tasks/auto_annotate_models.rake
においてmodels
のキーと値を追加します。Annotate.set_defaults( ... 'models' => 'true', ...インストール
rubygems.org から 追加
group :development do gem 'annotate' endGithub から 追加
group :development do gem 'annotate', git: 'https://github.com/ctran/annotate_models.git' endrubygems.org からインストール
gem install annotateGithub のチェックアウトからインストール
git clone https://github.com/ctran/annotate_models.git annotate_models cd annotate_models rake build gem install pkg/annotate-*.gem利用方法
もし Gemfile 経由でインストールをしているなら、
bundle exec
を下記コマンドにつけてください。Rails での利用方法
すべてのモデル、テスト、フィクスチャ、ファクトリに注釈をつける。
cd /path/to/app annotateモデル、テスト、ファクトリのみに注釈をつける。
annotate --models --exclude fixturesモデルのみに注釈をつける。
annotate --modelsroutes.rb に注釈をつける。
annotate --routesモデル、テスト、フィクスチャ、ファクトリ、シリアライザの注釈を削除する。
annotate --deleteroutes.rb の注釈を削除する。
annotate --routes --delete
db:migrate
を実行するたびに自動的に注釈をつけるためには、
rails g annotate:install
を実行するか、Rakefile
にAnnotate.load_tasks
を追加してください。詳細は Rails における設定 をご覧ください。
Rails の外での利用方法
--routes
オプションが意味をなさないことを除けば Rails 外の利用でも上述のすべてが適用されます。明示的に1つあるいは複数の--require
オプションと--model-dir
オプションを設定することで、annotate
にプロジェクトの構造を知らせ、プロジェクトが起動し関連のあるコードを読み込むことを助ける必要があります。設定
もし特定のモデルで注釈を常に飛ばしたいときは、モデルファイルの任意の場所に下記の文字列を追加してください。
# -*- SkipSchemaAnnotationsRails における設定
設定ファイル(
.rake
ファイル形式)を生成して、デフォルトオプションを設定するためには下記のコマンドを実行してください。rails g annotate:installこのファイルを編集することで、注釈がファイルの上下どちらに追加されるかや、どのタイプのファイルに注釈が記載されるかといったような、出力形式などを制御します。
生成される rake ファイルである
lib/tasks/auto_annotate_models.rake
はAnnotate.load_tasks
も含みます。この rake ファイルはコマンドラインの機能と重複するいくつかの rake タスクを追加します。rake annotate_models # Add schema information (as comments) to model and fixture files rake annotate_routes # Adds the route map to routes.rb rake remove_annotation # Remove schema information from model and fixture filesデフォルトでは、一旦設定ファイルを生成したあとは、
rake db:migrate
が実行されるたびに annotate が実行されます(development 環境のみ)。
この挙動を永続的に無効にしたいときは、.rake
ファイルを編集し、下記のように変更してください。'skip_on_db_migrate' => 'false',上記の記述から下記の記述へ変更する。
'skip_on_db_migrate' => 'true',1回だけ annotate なしで
rake db:migrate
を実行したいときは、.rake
ファイルを編集する代わりにシンプルな環境変数をつけることでそれを実現できます。ANNOTATE_SKIP_ON_DB_MIGRATE=1 rake db:migrateオプション
--additional-file-patterns
コンマで区切った注釈を行う追加のファイルパスあるいは glob(例:
/foo/bar/%model_name%/*.rb,/baz/%model_name%.rb
)を記載する。
-d, --delete
すべてのモデルファイルあるいは routes.rb ファイルから注釈を削除する。
-p [before|top|after|bottom], --position
model/test/fixture/factory/route/serializer ファイルの上部(前)あるいは下部(後)に注釈を置く。
--pc, --position-in-class [before|top|after|bottom]
model ファイルの上部(前)あるいは下部(後)に注釈を置く。
--pf, --position-in-factory [before|top|after|bottom]
factory ファイルの上部(前)あるいは下部(後)に注釈を置く。
--px, --position-in-fixture [before|top|after|bottom]
fixture ファイルの上部(前)あるいは下部(後)に注釈を置く。
--pt, --position-in-test [before|top|after|bottom]
test ファイルの上部(前)あるいは下部(後)に注釈を置く。
--pr, --position-in-routes [before|top|after|bottom]
routes.rb ファイルの上部(前)あるいは下部(後)に注釈を置く。
--ps, --position-in-serializer [before|top|after|bottom]
serializer ファイルの上部(前)あるいは下部(後)に注釈を置く。
--w, --wrapper STR
パラメーターとして渡されたテキストで注釈をラップします。
--w が使用された場合は、同じテキストが始端と終端に使用されます。
--wo, --wrapper-open STR
注釈の始端をラップするテキスト。
--wc, --wrapper-close STR
注釈の終端をラップするテキスト。
-r, --routes
'rake routes' の出力で routes.rb に注釈を付ける。
--models
ActiveRecord モデルに注釈を付ける。
-a, --active-admin
active_admin モデルに注釈を付ける。
-v, --version
この gem の現在のバージョンを表示する。
-m, --show-migration
注釈にマイグレーションのバージョン番号を含める。
-k, --show-foreign-keys
注釈にテーブルの外部キー制約の一覧を載せる。
--ck, --complete-foreign-keys
注釈に完全な外部キーの名前を載せる。
-i, --show-indexes
注釈にテーブルのインデックスの一覧を載せる。
-s, --simple-indexes
注釈内のカラムの関連したインデックスを結合する。
--model-dir dir
app/models ではないディレクトリに保存されたモデルファイルに注釈を付ける。ディレクトリ名はカンマで区切る。
--root-dir dir
ルートディレクトリのプロジェクト内に保存されたファイルに注釈を付ける。ディレクトリ名はカンマで区切る。
--ignore-model-subdirects
モデルディレクトリのサブディレクトリを無視する。
--sort
作成順ではなくアルファベット順でカラムをソートする。
--classified-sort
アルファベット順にカラムをソートする。ただし、一番目には id 、その次が残りのカラム、タイムスタンプカラム、関連付けカラムの順となる。
-R, --require path
モデルを読み込む前に必要とする追加のファイル。このファイルは複数回使用される。
-e [tests,fixtures,factories,serializers], --exclude
tests,fixtures,factories,serializers ファイルに注釈を付けないようにする。
-f [bare|rdoc|yard|markdown], --format
プレインテキスト/RDoc/YARD/Markdown としてスキーマ情報を記述する。
--force
変更がない場合でも新しい注釈を強制的に記述する。
--frozen
注釈の変更を許可しない。ファイルに変更がある場合は、ゼロ以外の値で終了します。
--timestamp
注釈にタイムスタンプを含ませる。
--trace
ファイルに注釈を付けられない場合は、例外メッセージだけでなく、スタックトレース全体を表示する。
-I, --ignore-columns REGEX
与えられた正規表現に合致するカラムに注釈をつけないようにする(例:
annotate -I '^(id|updated_at|created_at)'
)。
--ignore-routes REGEX
与えられた正規表現に合致する routes に注釈をつけないようにする(例:
annotate -I '(mobile|resque|pghero)'
)。
--hide-limit-column-types VALUES
与えられたカラムタイプに limit 値を表示させない。カラムタイプはコンマで区切る(例:
integer,boolean,text
)。
--hide-default-column-types VALUES
与えられたカラムタイプに default 値を表示させない。カラムタイプはコンマで区切る(例:
json,jsonb,hstore
)。
--ignore-unknown-models
不正なモデルファイルに対して警告を表示させない。
--with-comment
モデルの注釈にデータベースコメントを含める。
オプション:
additional_file_patterns
CLI:
--additional-file-patterns
Ruby::additional_file_patterns
注釈を行うために追加のパスを提供します。このパスは glob を含むことができます。絶対パスを使用することを推奨します。下記に例を記載します。
/app/lib/decorates/%MODEL_NAME%/*.rb
/app/lib/forms/%PLURALIZED_MODEL_NAME%/**/*.rb
/app/lib/forms/%TABLE_NAME%/*.rb
適切なモデルは
%*%
構文を用いて推論され、一致するファイルに注釈が付けられます。これは既存のファイル名解決とともに動作します(annotate_models.rb
のresolve_filename
メソッドの中で発見されるオプション)。Rails の設定の中で使用するときは、下記を使用できます。
File.join(Rails.application.root,
'app/lib/forms/%PLURALIZED_MODEL_NAME%/***/**.rb')ソート
デフォルトでは、カラムはデータベース順でソートされます(つまりマイグレーションが行われた順番)。
もしアルファベット順にソートしてマイグレーションを実行した順番とは関係なく注釈の結果を一致させたいときは、
--sort
オプションを使用してください。マークダウン
生成されるフォーマットは実際には MultiMarkdown で、テーブルのための構文拡張機能を利用しています。もしこのフォーマットを使用したいときはパーサーとして
kramdown
を使用することを推奨しています。もしドキュメントを生成するためにyard
を使用している場合は、.yardopts
ファイルにkramdown
を追加することでプロバイダとしてkramdown
をマークダウンのフォーマットに指定してください。--markup markdown --markup-provider kramdown
Gemfile
にも同様に kramdown を追加するようにしてください。gem 'kramdown', groups => [:development], require => false警告
自動作成されたコメントブロックの後にテキストを追加しないでください。annotate によって以前にコメントブロックが追加された可能性があるとき、annotate はモデル内の始端・終端のコメントブロックを削除することがあります。
annotate が行った変更を必ず確認するようにしてください。Git を使用している場合は、
annotate
を実行した後にプロジェクトのステータスを確認することができます。$ git statusVCS(Git や Subversion など)を使っていない人は、特に注意して annotate を扱い、1つの VCS の利用を検討してください。
リンク集
- Factory Bot: http://github.com/thoughtbot/factory_bot
- Object Daddy: http://github.com/flogic/object_daddy
- Machinist: http://github.com/notahat/machinist
- Fabrication: http://github.com/paulelliott/fabrication
- SpatialAdapter: http://github.com/pdeffendol/spatial_adapter
- PostgisAdapter: http://github.com/nofxx/postgis_adapter
- PostGISAdapter: https://github.com/dazuma/activerecord-postgis-adapter
ライセンス
Ruby と同じライセンスでリリースしています。サポートと保証はありません。
作者
AUTHORS.md をご覧ください。
- 投稿日:2020-04-05T22:53:30+09:00
gem annotate のドキュメントを翻訳しました
概要
gem annotate の README を翻訳しました。
Annotate (aka AnnotateModels)
下記のファイルの上部あるいは下部に現在の DB スキーマを要約したコメントを追加します。
- ActiveRecord models
- Fixture files
- Tests and Specs
- Object Daddy exemplars
- Machinist blueprints
- Fabrication fabricators
- Thoughtbot's factory_bot factories, i.e. the
(spec|test)/factories/<model>_factory.rb
filesroutes.rb
file (for Rails projects)スキーマコメントは下記のように記載されます。
# == Schema Info # # Table name: line_items # # id :integer(11) not null, primary key # quantity :integer(11) not null # product_id :integer(11) not null # unit_price :float # order_id :integer(11) # class LineItem < ActiveRecord::Base belongs_to :product . . .また、
SpatialAdapter
,PostgisAdapter
,PostGISAdapter
のいずれかを使用したときは、geom
タイプやsrid
タイプのような幾何学的なカラムにも注釈をつけます。# == Schema Info # # Table name: trips # # local :geometry point, 4326 # path :geometry line_string, 4326また、
-r
オプションを渡すと、rake routes
の出力をroutes.rb
にコメントとして追加します。3.Xにアップグレードするとモデルへの注釈が動作しない?
バージョン 2.7.X では、引数が何も渡されない場合は、gem annotate はデフォルトでモデルに注釈を追加していました。
デフォルトでは、gem annotate は routes とモデルが一緒に注釈を追加されることを許可していません。
#647 で変更が追加されました。
詳細はこちらでご覧ください。この問題を修正する方法はいくつかあります。
- CLI を使用している場合は、
--models
を使用してモデルフラグを明示的に渡してください。あるいは
a)
rails g annotate:install
を実行し、デフォルト設定がmodels
オプション'true'
になるように上書きします。b)
lib/tasks/auto_annotate_models.rake
においてmodels
のキーと値を追加します。Annotate.set_defaults( ... 'models' => 'true', ...インストール
rubygems.org から 追加
group :development do gem 'annotate' endGithub から 追加
group :development do gem 'annotate', git: 'https://github.com/ctran/annotate_models.git' endrubygems.org からインストール
gem install annotateGithub のチェックアウトからインストール
git clone https://github.com/ctran/annotate_models.git annotate_models cd annotate_models rake build gem install pkg/annotate-*.gem利用方法
もし Gemfile 経由でインストールをしているなら、
bundle exec
を下記コマンドにつけてください。Rails での利用方法
すべてのモデル、テスト、フィクスチャ、ファクトリに注釈をつける。
cd /path/to/app annotateモデル、テスト、ファクトリのみに注釈をつける。
annotate --models --exclude fixturesモデルのみに注釈をつける。
annotate --modelsroutes.rb に注釈をつける。
annotate --routesモデル、テスト、フィクスチャ、ファクトリ、シリアライザの注釈を削除する。
annotate --deleteroutes.rb の注釈を削除する。
annotate --routes --delete
db:migrate
を実行するたびに自動的に注釈をつけるためには、
rails g annotate:install
を実行するか、Rakefile
にAnnotate.load_tasks
を追加してください。詳細は Rails における設定 をご覧ください。
Rails の外での利用方法
--routes
オプションが意味をなさないことを除けば Rails 外の利用でも上述のすべてが適用されます。明示的に1つあるいは複数の--require
オプションと--model-dir
オプションを設定することで、annotate
にプロジェクトの構造を知らせ、プロジェクトが起動し関連のあるコードを読み込むことを助ける必要があります。設定
もし特定のモデルで注釈を常に飛ばしたいときは、モデルファイルの任意の場所に下記の文字列を追加してください。
# -*- SkipSchemaAnnotationsRails における設定
設定ファイル(
.rake
ファイル形式)を生成して、デフォルトオプションを設定するためには下記のコマンドを実行してください。rails g annotate:installこのファイルを編集することで、注釈がファイルの上下どちらに追加されるかや、どのタイプのファイルに注釈が記載されるかといったような、出力形式などを制御します。
生成される rake ファイルである
lib/tasks/auto_annotate_models.rake
はAnnotate.load_tasks
も含みます。この rake ファイルはコマンドラインの機能と重複するいくつかの rake タスクを追加します。rake annotate_models # Add schema information (as comments) to model and fixture files rake annotate_routes # Adds the route map to routes.rb rake remove_annotation # Remove schema information from model and fixture filesデフォルトでは、一旦設定ファイルを生成したあとは、
rake db:migrate
が実行されるたびに annotate が実行されます(development 環境のみ)。
この挙動を永続的に無効にしたいときは、.rake
ファイルを編集し、下記のように変更してください。'skip_on_db_migrate' => 'false',上記の記述から下記の記述へ変更する。
'skip_on_db_migrate' => 'true',1回だけ annotate なしで
rake db:migrate
を実行したいときは、.rake
ファイルを編集する代わりにシンプルな環境変数をつけることでそれを実現できます。ANNOTATE_SKIP_ON_DB_MIGRATE=1 rake db:migrateオプション
--additional-file-patterns
コンマで区切った注釈を行う追加のファイルパスあるいは glob(例:
/foo/bar/%model_name%/*.rb,/baz/%model_name%.rb
)を記載する。
-d, --delete
すべてのモデルファイルあるいは routes.rb ファイルから注釈を削除する。
-p [before|top|after|bottom], --position
model/test/fixture/factory/route/serializer ファイルの上部(前)あるいは下部(後)に注釈を置く。
--pc, --position-in-class [before|top|after|bottom]
model ファイルの上部(前)あるいは下部(後)に注釈を置く。
--pf, --position-in-factory [before|top|after|bottom]
factory ファイルの上部(前)あるいは下部(後)に注釈を置く。
--px, --position-in-fixture [before|top|after|bottom]
fixture ファイルの上部(前)あるいは下部(後)に注釈を置く。
--pt, --position-in-test [before|top|after|bottom]
test ファイルの上部(前)あるいは下部(後)に注釈を置く。
--pr, --position-in-routes [before|top|after|bottom]
routes.rb ファイルの上部(前)あるいは下部(後)に注釈を置く。
--ps, --position-in-serializer [before|top|after|bottom]
serializer ファイルの上部(前)あるいは下部(後)に注釈を置く。
--w, --wrapper STR
パラメーターとして渡されたテキストで注釈をラップします。
--w が使用された場合は、同じテキストが始端と終端に使用されます。
--wo, --wrapper-open STR
注釈の始端をラップするテキスト。
--wc, --wrapper-close STR
注釈の終端をラップするテキスト。
-r, --routes
'rake routes' の出力で routes.rb に注釈を付ける。
--models
ActiveRecord モデルに注釈を付ける。
-a, --active-admin
active_admin モデルに注釈を付ける。
-v, --version
この gem の現在のバージョンを表示する。
-m, --show-migration
注釈にマイグレーションのバージョン番号を含める。
-k, --show-foreign-keys
注釈にテーブルの外部キー制約の一覧を載せる。
--ck, --complete-foreign-keys
注釈に完全な外部キーの名前を載せる。
-i, --show-indexes
注釈にテーブルのインデックスの一覧を載せる。
-s, --simple-indexes
注釈内のカラムの関連したインデックスを結合する。
--model-dir dir
app/models ではないディレクトリに保存されたモデルファイルに注釈を付ける。ディレクトリ名はカンマで区切る。
--root-dir dir
ルートディレクトリのプロジェクト内に保存されたファイルに注釈を付ける。ディレクトリ名はカンマで区切る。
--ignore-model-subdirects
モデルディレクトリのサブディレクトリを無視する。
--sort
作成順ではなくアルファベット順でカラムをソートする。
--classified-sort
アルファベット順にカラムをソートする。ただし、一番目には id 、その次が残りのカラム、タイムスタンプカラム、関連付けカラムの順となる。
-R, --require path
モデルを読み込む前に必要とする追加のファイル。このファイルは複数回使用される。
-e [tests,fixtures,factories,serializers], --exclude
tests,fixtures,factories,serializers ファイルに注釈を付けないようにする。
-f [bare|rdoc|yard|markdown], --format
プレインテキスト/RDoc/YARD/Markdown としてスキーマ情報を記述する。
--force
変更がない場合でも新しい注釈を強制的に記述する。
--frozen
注釈の変更を許可しない。ファイルに変更がある場合は、ゼロ以外の値で終了します。
--timestamp
注釈にタイムスタンプを含ませる。
--trace
ファイルに注釈を付けられない場合は、例外メッセージだけでなく、スタックトレース全体を表示する。
-I, --ignore-columns REGEX
与えられた正規表現に合致するカラムに注釈をつけないようにする(例:
annotate -I '^(id|updated_at|created_at)'
)。
--ignore-routes REGEX
与えられた正規表現に合致する routes に注釈をつけないようにする(例:
annotate -I '(mobile|resque|pghero)'
)。
--hide-limit-column-types VALUES
与えられたカラムタイプに limit 値を表示させない。カラムタイプはコンマで区切る(例:
integer,boolean,text
)。
--hide-default-column-types VALUES
与えられたカラムタイプに default 値を表示させない。カラムタイプはコンマで区切る(例:
json,jsonb,hstore
)。
--ignore-unknown-models
不正なモデルファイルに対して警告を表示させない。
--with-comment
モデルの注釈にデータベースコメントを含める。
オプション:
additional_file_patterns
CLI:
--additional-file-patterns
Ruby::additional_file_patterns
注釈を行うために追加のパスを提供します。このパスは glob を含むことができます。絶対パスを使用することを推奨します。下記に例を記載します。
/app/lib/decorates/%MODEL_NAME%/*.rb
/app/lib/forms/%PLURALIZED_MODEL_NAME%/**/*.rb
/app/lib/forms/%TABLE_NAME%/*.rb
適切なモデルは
%*%
構文を用いて推論され、一致するファイルに注釈が付けられます。これは既存のファイル名解決とともに動作します(annotate_models.rb
のresolve_filename
メソッドの中で発見されるオプション)。Rails の設定の中で使用するときは、下記を使用できます。
File.join(Rails.application.root,
'app/lib/forms/%PLURALIZED_MODEL_NAME%/***/**.rb')ソート
デフォルトでは、カラムはデータベース順でソートされます(つまりマイグレーションが行われた順番)。
もしアルファベット順にソートしてマイグレーションを実行した順番とは関係なく注釈の結果を一致させたいときは、
--sort
オプションを使用してください。マークダウン
生成されるフォーマットは実際には MultiMarkdown で、テーブルのための構文拡張機能を利用しています。もしこのフォーマットを使用したいときはパーサーとして
kramdown
を使用することを推奨しています。もしドキュメントを生成するためにyard
を使用している場合は、.yardopts
ファイルにkramdown
を追加することでプロバイダとしてkramdown
をマークダウンのフォーマットに指定してください。--markup markdown --markup-provider kramdown
Gemfile
にも同様に kramdown を追加するようにしてください。gem 'kramdown', groups => [:development], require => false警告
自動作成されたコメントブロックの後にテキストを追加しないでください。annotate によって以前にコメントブロックが追加された可能性があるとき、annotate はモデル内の始端・終端のコメントブロックを削除することがあります。
annotate が行った変更を必ず確認するようにしてください。Git を使用している場合は、
annotate
を実行した後にプロジェクトのステータスを確認することができます。$ git statusVCS(Git や Subversion など)を使っていない人は、特に注意して annotate を扱い、1つの VCS の利用を検討してください。
リンク集
- Factory Bot: http://github.com/thoughtbot/factory_bot
- Object Daddy: http://github.com/flogic/object_daddy
- Machinist: http://github.com/notahat/machinist
- Fabrication: http://github.com/paulelliott/fabrication
- SpatialAdapter: http://github.com/pdeffendol/spatial_adapter
- PostgisAdapter: http://github.com/nofxx/postgis_adapter
- PostGISAdapter: https://github.com/dazuma/activerecord-postgis-adapter
ライセンス
Ruby と同じライセンスでリリースしています。サポートと保証はありません。
作者
AUTHORS.md をご覧ください。
- 投稿日:2020-04-05T22:09:30+09:00
undefined method 'page' for # <Array:0x000........>が出たときの対処法
はじめに
gem kaminariについて、新しい発見があったので、記録として残す。
今回のエラー
controller.rbインスタンス変数 = オブジェクト.page(:params[:page]).per(10)index.html.haml= paginate インスタンス変数と定義したところ、エラーが出た。
エラー文
undefined method 'page' for # <Array:0x000........>なぜ???
実は、、、
私の解釈では、、
controller.rbインスタンス変数 = オブジェクト.page(:params[:page]).per(10)のつもりだったのが、
controller.rbインスタンス変数 = 配列.page(:params[:page]).per(10)の間違いだった。
解決策
kaminariの公式ページを読めばわかるのだが、
通常.pageメソッドはActive Recordのオブジェクトにしか適用されないらしい。
今回はそうではなく、配列(Array)だったのでエラーが出ていたようだ。
そこでkaminariでは、配列にも.pageメソッドを使用できるやり方がある。
controller.rbインスタンス変数 = Kaminari.paginate_array(配列).page(params[:page]).per(10)これで解決した。
おわりに
あまり深く理解せず使用していたジェムがたくさんあるが、こういうエラーがきっかけで、
改めて公式レファレンスを読むことの重要性を感じた。公式レファレンスを読み進めていくと、新しい発見もたくさんあるので非常に楽しいので、皆さんもいろんなgemの公式レファレンスを読んでみてほしい。
参考記事
公式レファレンス
https://github.com/kaminari/kaminari/blob/master/README.mdkaminariでundefined method `page' for #<Array:0x000xxxxxxと出た
https://haayaaa.hatenablog.com/entry/2019/03/11/215042
- 投稿日:2020-04-05T22:05:26+09:00
rails newするとCould not load command "rails/commands/server/server_command". Error: uninitialized constant URI::Generic.と表示される時の対処法
Vagrantを使って環境構築をしている際、エラーに遭遇したので記録を残しておきます。
構築環境
Ruby 2.5.0
Ruby on rails 5.1.7
Vagrant 2.2.7
Virtual Box 6.1.4
rbenv 1.1.2発生したエラー
$ rails new #省略 [WARNING] Could not load command "rails/commands/server/server_command". Error: uninitialized constant URI::Generic.解決した方法
Rubyのバージョンを2.5.7に上げるとこのエラーは解消されました。
#バージョン2.5.7のRubyをインストール $ rbenv install 2.5.7 #省略 #使用する全体のrubyのバージョンを指定 $rbenv global 2.5.7 #Rubyのバージョンを確認 $ruby -v ruby 2.5.7p206 (2019-10-01 revision 67816) [x86_64-linux] $rails new #うまくいきましたhttps://stackoverflow.com/questions/59961343/failing-to-start-up-default-rails-server
この質問を参考にしてバージョンを変えてみたんですが、よく読むと2.5.7でも同じ現象が起こったって書かれてますね...。原因が分かる方は教えていただきたいです。
- 投稿日:2020-04-05T21:36:25+09:00
アカウントの有効化〜Railsチュートリアル11章〜
いよいよRailsチュートリアル11章に入っていきます。11章の体感としてはProgateの内容でも少し触った内容であったので割とスムーズにすすめることができました。
それではまとめていきます。アカウントの有効化
現時点でのApplicationは新規登録したユーザーははじめからすべての機能にアクセスできるようになっている。
ここではアカウントを有効化するステップを新規登録の途中に差し込むことで本当にそのメールアドレスの持ち主なのかどうかを確認できるようにする。
大まかな流れ
(1)有効化トークンやダイジェストを関連付けておいた状態で
(2)有効化トークンを含めたリンクをユーザーにメールで送信し
(3)ユーザーがそのリンクをクリックすると有効化できるようにする
というものである。基本的な手順
1.ユーザーの初期状態は「有効化されていない」にしておく
2.ユーザー登録が行われたときに有効化トークンとそれに対応する有効化ダイジェストを生成する。
3.有効化ダイジェストはデータベースに保存しておき、有効化トークンはメールアドレスと一緒にユーザーに送信する有効化用メールのリンクに仕込んでおく
4.ユーザーがメールのリンクをクリックしたらApplicationはメールアドレスをキーにしてユーザーを探し、データベース内に保存しておいた有効化ダイジェストと比較することでトークンを認証する。
5.ユーザーが認証できたら、ユーザーのステータスを「有効化されていない」から「有効化済み」に変更する。AccountActivationsリソース
Session機能を使ってアカウントの有効化という作業を「リソース」としてモデル化する。アカウントの有効化リソースはActive Recordのモデルとは関係ないので両者を関連付けることはしない。その代わりにこの作業に必要なデータ(有効化トークンや有効化ステータス)をUserモデルに追加する。
普段のリソースとは異なる点
有効化用のリンクにアクセスして有効化のステータスを変更する部分では、RESTのルールに従うとPATCHリクエストとUpdateアクションになるべきである。しかし有効化リンクはメールでユーザーに送られる。ユーザーがこのリンクをクリックすればそれはブラウザで普通にクリックしたときと同じであり、その場合ブラウザから発行されるのはGETリクエストになってしまう。このためユーザーからのGETリクエストを受けるためにEDITアクションに変更して使っていく。アカウント有効化に使うリソースを追加する
Rails.application.routes.draw do resources :account_activations, only: [:edit] ↑ #有効化のメールにedit_account_activation_url (activation_token, ...) を使用したいのでeditアクションへ名前付きルートが必要になる。 そこで上記のResourcesを追加する。AccountActivationのデータモデル
有効化のメールには一意の有効化トークンが必要であるも送信メールとデータベースのそれぞれに同じ文字列をおいておく方法だと情報漏えいが起こった際多大な被害につながる。
そこでデータベースに仮想的な属性をつけてハッシュ化した文字列をデータベースに保存するようにする。具体的には仮想属性の有効化トークンにアクセスし、user.activation_tokenでユーザーを認識できるようにする。$ rails generate migration add_activation_to_users \ > activation_digest:string activated:boolean activated_at:datetime ↑をデータベースにmigrateする。アクティブトークンのコールバック
ユーザーが新しい登録を完了するためには必ずアカウントの有効化が必要になるので有効化トークンや有効化ダイジェストはユーザーオブジェクトが作成される前に作成しておく必要がある。
そこでbefore_createコールバックが必要となる。before_create :create_activation_digest上のコードはメソッド参照と呼ばれるもので、こうするとRailsはcreate_activation_digestというメソッドを探し、ユーザーを作成する前に実行するようになる。create_activation_digestメソッド自体はUserモデル内でしか使わないので、外部に公開する必要はない。
よってprivateキーワードを指定してこのメソッドを隠蔽する。self.activation_token = User.new_token self.activation_digest = User.digest(activation_token)このコードを9章で作成した永続Sessionのためのユーザー登録した時と比べる。
9章では記憶トークンとダイジェストはすでにデータベースにいるユーザーのために作成されるのに対し、before_createコールバックはユーザーが作成される前に呼び出されることなので更新される属性がまだない。
このコールバックがあることでUser.newで新しいユーザーが定義されるとactivation_token属性やactivation_digest属性が得られるようになる。class User < ApplicationRecord attr_accessor :remember_token, :activation_token before_save :downcase_email before_create :create_activation_digest validates :name, presence: true, length: { maximum: 50 } . . . private # メールアドレスをすべて小文字にする def downcase_email self.email = email.downcase end # 有効化トークンとダイジェストを作成および代入する def create_activation_digest self.activation_token = User.new_token self.activation_digest = User.digest(activation_token) end endアカウント有効化のメール送信
データのモデル化が終わったのでアカウント有効化メールの送信に必要なコードを追加する。このメソッドではActionMailerライブラリを使ってUserのメイラーを追加する。メイラーは、モデルやコントローラと同様にrails generateで生成できる。メイラーの構成はコントローラのアクションとよく似ている。テンプレートはビューと同じようなもの。このテンプレートの中に有効化トークンとメールアドレス (= 有効にするアカウントのアドレス) のリンクを含め、使っていく。
Userメイラーで
account_activationメソッドと、第12章で必要となるpassword_resetメソッドを生成する。
生成したメイラーごとにビューのテンプレートが2つずつ生成される。
1つはテキストメール用のテンプレート
1つはHTML用のテンプレートである。生成されたApplicationメイラーにはデフォルトのformアドレスがある。
最初に生成されたテンプレートをカスタマイズして実際に有効化メールで使えるようにする。
app/mailers/application_mailer.rb class ApplicationMailer < ActionMailer::Base default from: "noreply@example.com" layout 'mailer' end次にユーザーを含むインスタンス変数を作成してビューで使えるようにし、user.emailにメール送信を行う。subjectキーはmailの件名に当たる。
class UserMailer < ApplicationMailer def account_activation(user) @user = user mail to: user.email, subject: "Account activation" endedit_account_activation_url(@user.activation_token, ...)
ここで思い出してみる。edit_user_url(user)
上のメソッドは、次の形式のURLを生成します。http://www.example.com/users/1/editこれに対応するアカウント有効化リンクのベースURLは次のようになります。
http://www.example.com/account_activations/q5lt38hQDc_959PVoo6b7A/editクエリパラメータを使って、このURLにメールアドレスもうまく組み込んでみましょう。クエリパラメータとは、URLの末尾で疑問符「?」に続けてキーと値のペアを記述したものです。
account_activations/q5lt38hQDc_959PVoo6b7A/edit?email=foo%40example.comこのとき、メールアドレスの「@」記号がURLでは「%40」となっている点に注目してください。これは「エスケープ」と呼ばれる手法で、通常URLでは扱えない文字を扱えるようにするために変換されています。Railsでクエリパラメータを設定するには、名前付きルートに対して次のようなハッシュを追加します。
edit_account_activation_url(@user.activation_token, email: @user.email)送信メールのプレビュー
Railsでは、特殊なURLにアクセスするとメールのメッセージをその場でプレビューすることができます。
development環境のメール設定 config/environments/development.rb Rails.application.configure do . config.action_mailer.raise_delivery_errors = true config.action_mailer.delivery_method = :test host = 'example.com' # 自分のクラウドIDEのリンクを貼る config.action_mailer.default_url_options = { host: host, protocol: 'https' } . end# Preview all emails at http://localhost:3000/rails/mailers/user_mailer class UserMailerPreview < ActionMailer::Preview # Preview this email at # http://localhost:3000/rails/mailers/user_mailer/account_activation def account_activation user = User.first user.activation_token = User.new_token UserMailer.account_activation(user) end # Preview this email at # http://localhost:3000/rails/mailers/user_mailer/password_reset def password_reset UserMailer.password_reset end endメールtestの実装
test/mailers/user_mailer_test.rb require 'test_helper' class UserMailerTest < ActionMailer::TestCase test "account_activation" do user = users(:michael) user.activation_token = User.new_token mail = UserMailer.account_activation(user) assert_equal "Account activation", mail.subject assert_equal [user.email], mail.to assert_equal ["noreply@example.com"], mail.from assert_match user.name, mail.body.encoded assert_match user.activation_token, mail.body.encoded assert_match CGI.escape(user.email), mail.body.encoded end endアカウントの有効化
AccountActivationsコントローラのeditアクションを書いていく。
authenticated?メソッドの抽象化
app/models/user.rb
class User < ApplicationRecord . . . # トークンがダイジェストと一致したらtrueを返す def authenticated?(attribute, token) digest = send("#{attribute}_digest") return false if digest.nil? BCrypt::Password.new(digest).is_password?(token) end . . . endmodule SessionsHelper . . . # 現在ログイン中のユーザーを返す (いる場合) def current_user if (user_id = session[:user_id]) @current_user ||= User.find_by(id: user_id) elsif (user_id = cookies.signed[:user_id]) user = User.find_by(id: user_id) if user && user.authenticated?(:remember, cookies[:remember_token]) log_in user @current_user = user end end end``アカウントを有効化するeditアクション
app/controllers/account_activations_controller.rb class AccountActivationsController < ApplicationController def edit user = User.find_by(email: params[:email]) if user && !user.activated? && user.authenticated?(:activation, params[:id]) user.update_attribute(:activated, true) user.update_attribute(:activated_at, Time.zone.now) log_in user flash[:success] = "Account activated!" redirect_to user else flash[:danger] = "Invalid activation link" redirect_to root_url end end end本日はここまで
- 投稿日:2020-04-05T18:36:34+09:00
【解決方法】Mysql2::Error: Table 'users' already exists
Mysql2::Error: Table 'users' already existsエラーに遭遇
Mysql2::Error: Table 'users' already exists
どうやらusersテーブルが既に存在しているため、マイグレートが実行できない様子
解決方法として既に存在するusersテーブルを削除し、再びマイグレートすれば良さそうだ
ターミナルで以下のコマンドを実行
$ rails db:すると
Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 490 Server version: 5.6.47 Homebrew Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql>
長々と文章が出てくるが、とりあえず次のコマンドを実行
mysql> SHOW TABLES;
mysqlのテーブルが表示される
+---------------------------+ | Tables_in_app_development | +---------------------------+ | ar_internal_metadata | | posts | | schema_migrations | | users | +---------------------------+ここからusersテーブルを消すために、次のコマンドを実行
mysql> drop table テーブル名;今回はusersテーブルなので
mysql> drop table users;Query OK, 0 rows affected (0.04 sec)削除完了。 sequelProで中身を確認してところ、無事消えていた。
ターミナル上の操作はなかなか覚えられないが、こうした作業ができるのを知っておくのが大切かなと。
- 投稿日:2020-04-05T18:34:40+09:00
【rails】haml導入した際のメモ
- 投稿日:2020-04-05T17:19:22+09:00
[Rails][data-vocabulary.org スキーマのサポートは終了します。]gem Gretelをschema.orgに対応させる方法。
data-vocabulary.org スキーマのサポートは終了します。
2020年4月6日からGoogleで「data-vocabulary.org」を利用した構造化データがリッチリザルトとしてサポートされなくなるので、引き続きリッチリザルトを利用したい場合は「schema.org」を利用した構造化データに移行する必要があります。
パンくずリスト | Google 検索デベロッパー ガイド | Google Developers
https://developers.google.com/search/docs/data-types/breadcrumb?hl=jaGem Gretelとは
Gretel( https://rubygems.org/gems/gretel/versions/3.0.7 )は設定ファイルを書くことで、簡単にパンクズリストを出力することができるようになるGemです。
パンクズの出力のオプションでsemantic: true
をつけることによりリッチリザルトにも対応していました(data-vocabulary.org)。しかし、このGemはメンテナンスが長いこと止まっており、Googleの「schema.org」を利用するにはパッチを当てる必要がります。
自分で検索した所同じような対応をしている人が散見されたので、僕の方法を示して行こうと思います。※ 本来は別のGemなどに移行することをオススメしますが、昔から使っている人がお手軽に対応できる方法を本記事にしています。
モンキーパッチを当てる
Gretel Gemを使っているRailsプロジェクトで
config/initializers/gretel.rb
を作成してruby# frozen_string_literal: true module Gretel module ViewHelpers delegate :breadcrumbs_json_ld, to: :gretel_renderer end class Renderer # rubocop:disable Rails/OutputSafety def breadcrumbs_json_ld { "@context": 'http://schema.org/', "@type": 'BreadcrumbList', "itemListElement": links.map.with_index do |link, i| { '@type': 'ListItem', 'position': i + 1, 'item': { '@id': "#{root_url.chop}#{link}", 'name': link.text } } end }.to_json.html_safe end # rubocop:enable Rails/OutputSafety end endYamitake gist gretel.rb https://gist.github.com/yamitake/3659b9d87404ad975f8a881b05971e33
使い方
breadcrumbs_json_ld
を宣言したので、viewファイル側で下記のように宣言することにより、schema.orgに対応したjsonLDが出力されます。.breadcrumbs == breadcrumbs = tag.script(breadcrumbs_json_ld, type: 'application/ld+json')おわりに
今までGretelで開発してきた人が暫定対応としては上記の方法でお手軽に対応できますが、gretelはメンテナンスが長いことされていないので別のGemを探すか自前でパンクズの実装をした方がいいと思います。
- 投稿日:2020-04-05T16:43:06+09:00
Rails × jquery 爆速でGoogleカレンダーつぽいアプリを作ってみよう(FullCalenderバージョン)
今日の目標
爆速でGoogleカレンダーっぽいアプリを作ってみる
機能
月別、週別、日別の表示が可能
イベントをドラッグして作成および編集が可能(今回は未実装)
Googleカレンダーとの同期もできる(今回は未実装)
今回は爆速バージョンということでイベントタイトル、説明、開始日、終了日を登録し、カレンダーに登録するところまでの実装とします。
環境
Ruby 2.5.1
Ruby on rails 5.2.4
Sqlite3 1.4.2gemの記載
Gemfileに使うgemを追加
Gemfilegem 'jquery-rails', '4.3.3' gem 'fullcalendar-rails' gem 'momentjs-rails'bundle installを実行
application.js
assets/javascripts/application.js//= require jquery //= require moment //= require fullcalendar今回は単一機能のアプリであるので application.jsに直書きします。
assets/javascripts/application.js$(function () { function eventCalendar() { return $('#calendar').fullCalendar({}); }; function clearCalendar() { $('#calendar').html(''); }; });一つ目の関数ではFullCalendarの設定を読み込み、二つ目の関数ではFullCalendarを削除します。
そして、RailsにはTurbolinksというツールを使ってページ遷移を高速にさせています。この機能がないと、Turbolinksを使っているときにカレンダーが複数回表示されることが起きてしまいます。関数を追加したら、今度は呼び出すコードをfunction clearCalender()の後ろに記述します。
application.js$(document).on('turbolinks:load', function () { eventCalendar(); }); $(document).on('turbolinks:before-cache', clearCalendar);application.css
*= require fullcalendarを追加
assets/application.css*= require_tree . *= require_self *= require fullcalendar */これで、viewのerbファイルに
<div id="calendar"></div>
と書き込むだけでカレンダーが表示されます。(が、まだこれではイベント表示機能を付けた時に上手く表示されないときがあります。この後改修していきます。)
要ルーティングの設定。scaffoldで爆速でEventモデル、コントローラ等作成する
イベントにはタイトル、説明、開始日、終了日が必要です。
今回はscaffoldを用いて爆速でモデル、コントローラを作成します。*scaffoldを使うとCRUD機能を爆速で実装出来ます。(テストアプリ向け)
CRUD とは Create(作成) / Read(表示) / Update(更新) / Delete(削除) の略でアプリケーションを実現するために必要十分な機能群のことを指します。
そして、Rails の Scaffold を利用することによって、その CRUD を素早く実現できるので実際に試してみましょう。
$ rails g scaffold Event title:string description:text start_date:datetime end_date:datetimeマイグレーションファイルが以下のように作成されているか確認しましょう
ルーティング
scaffoldでモデル、コントローラを作成した後はルーティングを設定しましょう。
config/routes.rbRails.application.routes.draw do resources :events root 'events#index' endJSONファイルの作成
Fullcalendarにイベントの情報を表示するには、JSONファイルを使ってあげます。
JSONを渡すために、Railsのjbuilderというものを使っていきます。
scaffoldによってjson.jbuilderファイルが自動で作られています。ここに以下の記述を追加します。
app/views/_event.json.jbuilderjson.array!(@events) do |event| json.extract! event, :id, :title, :description json.start event.start_date json.end event.end_date json.url event_url(event, format: :html) endapplication.js
ここまでの記述のまとめ
assets/javascripts/application.js$(function () { function eventCalendar() { return $('#calendar').fullCalendar({}); }; function clearCalendar() { $('#calendar').html(''); }; $(document).on('turbolinks:load', function () { eventCalendar(); }); $(document).on('turbolinks:before-cache', clearCalendar); $('#calendar').fullCalendar({ events: '/events.json' }); });このままでも作動するのですが 若干turbo-linksの不具合が生じます。
if ($('#calendar').length) { function eventCalendar() { return $('#calendar').fullCalendar({ });という形で lengthを呼び出すことで、#calendarが存在していた場合はtrueの処理がされ、無い場合はnillを返すという記述をすることで Turbo-linksが正常に動作するようになります。
application.js
完成記述 オプションを付け加える場合には 基本的に以下の記述に追加する
$(function () { $(document).on('turbolinks:load', function () { if ($('#calendar').length) { function eventCalendar() { return $('#calendar').fullCalendar({}); }; function clearCalendar() { $('#calendar').html(''); }; $(document).on('turbolinks:load', function () { eventCalendar(); }); $(document).on('turbolinks:before-cache', clearCalendar); $('#calendar').fullCalendar({ events: '/events.json' }); } }); });Turbo-linksの記述位置に注意です。
見本完成形
ドラッグ機能、Googleカレンダーとの同期も含め、オプションは豊富なので 是非研究してみてください。
公式ドキュメントを読み込む力は必須なのでこちらも読み込みましょう。
オプション等の記事はまた次の機会に
- 投稿日:2020-04-05T14:31:16+09:00
Request SpecでDeviseのsing_in userを実施する
Request specでDeviseのsign_inを実施する
検索するとModuleを利用したものや、認証用モデル作成としてFactory-girlを利用したやや複雑かつやや古いものが多く、少し困ったため
Rails6環境での実施を記録します。実施環境
- Rails 6.0.2.2
- Factory-bot-rails 5.1.1
- Devise 4.7.1
- RSpec 3.9
下記を実施して、devise用ユーザーとpostモデルを作成しておきます。
rails generate devise user rails generate scaffold post body:stringmigrateも忘れずに
rails db:migratespec実施時に、Deviseのhelperを呼び出せるように設定
spec/rails_helper.rbRSpec.configure do |config| #色々書いてある下に下記行を追記 config.include Devise::Test::IntegrationHelpers, type: :request endspecからrails_helperを通してDeviseのsigin_in等のヘルパー機能を呼び出せるようになります。
posts_controllerの設定
app/controller/posts_controller.rbclass PostsController < ApplicationController 自動生成されたbefore_actionがありますが、今回は下記のように修正 before_action :authenticate_user!, expect: [:index] #省略 endapp/config/routes.rbRails.application.routes.draw do devise_for :users #先頭にくるようにしてください resources :posts # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html end認証処理なしで一度spec(自動生成されています)を実行
rspec spec/requests/posts_spec.rbFailures: 1) Posts GET /posts works! (now write some real specs) Failure/Error: expect(response).to have_http_status(200) expected the response to have status code 200 but it was 302 # ./spec/requests/posts_spec.rb:7:in `block (3 levels) in <main>' Finished in 0.19729 seconds (files took 3.08 seconds to load) 1 examples, 1 failure Failed examples: rspec ./spec/requests/posts_spec.rb:5 # Posts GET /posts works! (now write some real specs)失敗の内容から、レスポンスステータス200を期待した結果302(ログイン画面へのredirect)が返却され失敗となっています。
factory_Bot未使用の簡易な実装
spec実施時に認証用モデルを都度作成することで、簡易に実現できます。
spec/requests/posts_spec.rbrequire 'rails_helper' RSpec.describe "Posts", type: :request do describe "GET /posts" do before do #認証ユーザーを作成します。 #各変数の中身は何でも良いです。passwordとpassword_confirmationが一致することだけ確認してください。 @user = User.create(email: 'test@test.com', password: "password", password_confirmation: "password") end it "works! (now write some real specs)" do #認証処理を行います sign_in @user get posts_path expect(response).to have_http_status(200) end end end非常に簡易ですが、これだけでDevise認証を必要とするspecの作成は可能です。
実行結果
Finished in 0.12959 seconds (files took 1.07 seconds to load) 1 example, 0 failuresfactory_botを利用したDevise認証
fixturesのデファクトであるfactory_bot(旧factory_girl)を利用した実装です。
factory_bot利用できるように設定
spec配下にsupportディレクトリを作成し下記のファイルを作成
spec/support/factory_bot.rbRSpec.configure do |config| config.include FactoryBot::Syntax::Methods end併せて、下記ファイルのコメントアウトを削除し有効にします。
spec/rails_helper.rbDir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f }テスト用modelを作成します。
spec/factories/users.rbFactoryBot.define do factory :user do email { "test@test.com"} #下記の値は同じになるようにしてください password { "password" } password_confirmation { "password"} end endspecでfactoryを利用して認証ユーザーを取り出すようにします。
spec/requests/posts_spec.rbrequire 'rails_helper' RSpec.describe "Posts", type: :request do describe "GET /posts" do before do #factory_botを利用して認証モデルを作成します。 @user = create(:user) end it "works! (now write some real specs)" do #認証処理を行います sign_in @user get posts_path expect(response).to have_http_status(200) end end end実行結果
Finished in 0.11056 seconds (files took 1.28 seconds to load) 1 example, 0 failuresサンプルコード
各verのサンプルコードはgithubへ上げてありますのでご参考までに。
factory_bot未使用
factory_bot利用
- 投稿日:2020-04-05T11:44:02+09:00
【Docker】Railsサーバが起動しない場合の対処
はじめに
とあるDockerの教材を学習していた時に表題の通り
railsサーバが起動しなかったため備忘録として記載していますrails&Docker初心者のため間違った見解があればご指摘いただけると嬉しいです。結論
忙しい人のために先にどうやって解決したかを記載します
▼server.pidファイルを削除
$ rm tmp/pids/server.pid▼削除確認されるので「yes」
$remove tmp/pids/server.pid? #yes▼コンテナを立ち上げる
$docker-compose up -dサーバー起動で無事解決♪
問題
【Docker】を使ったrailsの環境構築を以下の流れで設定
$docker-compose run web rails new . --force --database=mysql //省略// $docker-compose build //dockerfileからイメージをビルド// $docker-compose up -d //現在のディレクトリにあるdocker-compose.ymlに基づいて コンテナを起動する// $docker-compose run web bundle exec rake db:create //railsで使用するデータベースをMySQLサーバ上に作成// $rails s //立ち上がらない...//状態
▼
$docker-compose ps
でコンテナの起動状態を確認$docker-compose ps Name Command State Ports ----------------------------------------------------------------------------- original_db_1 docker-entrypoint.sh mysqld Up 3306/tcp, 33060/tcp original_web_1 bundle exec rails s -p 300 Exit 1
original_web_1
のStateがExit1になっていました...▼
$docker logs original_web_1
でログを確認$docker logs original_web_1 => Booting Puma => Rails 5.0.7.2 application starting in development on http://0.0.0.0:3000 => Run `rails server -h` for more startup options A server is already running. Check /app/tmp/pids/server.pid. Exitingサーバはすでに立ち上がっていて
Check /app/tmp/pids/server.pid.
を確認してくれーと言われていますserver.pid とは
WEB開発サーバを起動するときに書き込まれ、停止すると削除されるファイルみたいです。
server.pid に pid が書かれていると開発用WEBサーバが起動中と判断されてしまいます。
今回はこのserver.pidが書き込まれている状態のため、railsサーバーが起動しなかったんですね〜解決策
ということで
$ rm tmp/pids/server.pidでserver.pidファイルを削除で無事解決しました♪
- 投稿日:2020-04-05T11:04:19+09:00
Railsアプリのテスト実行中に cookies.signed がエラー(undefined) になったときの対処法
こんにちは、ペーパーエンジニアのよしこです。
Ruby on Railsのテストで、Cookies周りのバグに対応しました。
RSpecテスト環境での日本語情報が少なかったので、私と同じ初心者向けに情報共有します。バグの内容
ControllerやHelperなどで使われている
cookies.signed[:foo]
をテストで呼び出すと、
NoMethodError: undefined method `signed' for #<Rack::Test::CookieJar:0x0>とエラーになりました。※
cokkies.permanent
やcookies.encrypted
でも同様のエラーになります。hoges_controller.rbclass hogesController < ApplicationController def hogehoge pp cookies.signed[:foo] = "bar" end end上のコントローラー(もしくはヘルパー)のRSpecテストを書きます。
hoges_request_spec.rbRSpec.describe "Hoges", type: :request do it { expect(hogehoge).to eq "bar" } end実行結果は、エラーとなります。
#ターミナル $ rspec Failures: 1) Hoges #hogehoge Failure/Error: pp cookies.signed[:foo] = "bar" NoMethodError: undefined method `signed' for #<Rack::Test::CookieJar:0x00007ffddefd5460> # ./app/helpers/hoges_controller.rb:3:in対処方法(結論)
Rack::Test::CookieJarの未定義メソッド (undefined method) を定義し直します。
./spec/support/cookies.rb
というファイル(名前は任意)を作成し、下のコードで保存します。cookies.rb# RSpecでcookies.signedがエラーになる対処 class Rack::Test::CookieJar def signed self end def permanent self end def encrypted self end endこれで、 テストはパスできるはずです。
この解決方法は、GitHubのRSpec Issuesのコメントに記載されていました。
【GitHub】Signed cookies not available in controller specs - rspec-rails 3.5.0, rails 5.0 #1658
こちらの最下部コメントがヒントになりました。@wangthony wangthony commented on 10 Nov 2018
@ivko999 's solution worked for me - thanks!
Even cleaner, just put it in a spec/support file:# spec/support/cookies.rb class ActionDispatch::Cookies::CookieJar def encrypted; self; end def signed; self; end def permanent; self; end # I needed this, too endなぜ動かないのか
Railsのcookieクラスは、環境によって参照元が変わります。
# テスト環境以外 ActionDispatch::Cookies::CookieJar # テスト環境 Rack::Test::CookieJarテスト環境のRack::Test::CookieJarが、
signed
permanent
encrypted
メソッドをサポートしていないので、
テスト実行時にエラーになってしまいます。※ ActionController::TestCaseではサポートしているとのことなので、Controllerテストではサポートしているのかもしれません。
【GitHub】Signed cookies not available in controller tests #27145参考にしたブログ記事
Railsのインテグレーションテストでcookies.signedを使いたい以上となります。
少しでもお力になれれば幸いです。
- 投稿日:2020-04-05T10:16:13+09:00
ユーザーの更新・表示・削除機能を追加します〜Railsチュートリアル10章〜
この章ではユーザー機能を充実させてRESTアクションを完成させます。
この章で行うことは
プロフィールの更新、認可モデルの実装。ユーザー一覧の追加。ユーザーの削除機能を追加していきます。ユーザーを更新する
ユーザー情報を編集するパターンは新規ユーザーの作成と似通っている。
ユーザーを編集するためのeditアクションを作成する。
patchリクエストに応答するUpdateアクションを作成する。
またユーザー情報を更新できるのはそのユーザー自身だけであるよう設定する。まずeditに対応するアクションとビューを追加する。
アクション
def edit @user = User.find(params[:id]) endビュー
<% provide(:title, "Edit user") %> <h1>Update your profile</h1> <div class="row"> <div class="col-md-6 col-md-offset-3"> <%= form_for(@user) do |f| %> <%= render 'shared/error_messages' %> <%= f.label :name %> <%= f.text_field :name, class: 'form-control' %> <%= f.label :email %> <%= f.email_field :email, class: 'form-control' %> <%= f.label :password %> <%= f.password_field :password, class: 'form-control' %> <%= f.label :password_confirmation, "Confirmation" %> <%= f.password_field :password_confirmation, class: 'form-control' %> <%= f.submit "Save changes", class: "btn btn-primary" %> <% end %> <div class="gravatar_edit"> <%= gravatar_for @user %> <a href="http://gravatar.com/emails" target="_blank">change</a> </div> </div> </div>WebブラウザはネイティブではPATCHリクエスト (RESTの慣習として要求されている) を送信できないので、RailsはPOSTリクエストと隠しinputフィールドを利用してPATCHリクエストを「偽造」しています
ユーザーのeditビューで使われているtarget="_blank"ですが、これを使うとリンク先を新しいタブ(またはウィンドウ)で開くようになるので、別の Webサイトへリンクするときなどに便利です。target="_blank"で新しいページを開くと、フィッシングサイトのような、悪意のあるコンテンツを導入させられてしまう可能性があります。対処方法は、リンク用のaタグのrel(relationship)属性に、"noopener"と設定します。
編集の失敗
編集に失敗した場合について扱う。まずupdateアクションの作成から始める。update_attributesを使って送信されたparamsハッシュに基いてユーザーを更新します。無効な情報が送信された場合、更新の結果としてfalseが返され、elseに分岐して編集ページをレンダリングします。
def create @user = User.new(user_params) if @user.save log_in @user flash[:success] = "Welcome to the Sample App!" redirect_to @user else render 'new' end end def edit @user = User.find(params[:id]) end def update @user = User.find(params[:id]) if @user.update_attributes(user_params) # 更新に成功した場合を扱う。 else render 'edit' end end編集失敗のtest
require 'test_helper' class UsersEditTest < ActionDispatch::IntegrationTest def setup @user = users(:michael) end test "unsuccessful edit" do get edit_user_path(@user) assert_template 'users/edit' patch user_path(@user), params: { user: { name: "", email: "foo@invalid", password: "foo", password_confirmation: "bar" } } assert_template 'users/edit' end endtest内容
1 そのユーザーにとっての編集画面を開ける
2 user/editのビューが表示される
3 編集した内容(無効な情報)をpatchリクエストとして送る
4 user/editのビューが表示される編集成功のtest
require 'test_helper' class UsersEditTest < ActionDispatch::IntegrationTest def setup @user = users(:michael) end . . . test "successful edit" do get edit_user_path(@user) assert_template 'users/edit' name = "Foo Bar" email = "foo@bar.com" patch user_path(@user), params: { user: { name: name, email: email, password: "", password_confirmation: "" } } assert_not flash.empty? assert_redirected_to @user @user.reload assert_equal name, @user.name assert_equal email, @user.email end endこのままでは長さに対するバリデーションが有効となっているためREDとなってしまう。パスワードのバリデーションに対して例外処理を加える。
ユーザーmodelsへ
validates :password, presence: true, length: { minimum: 6 }, allow_nil: trueを追加する、これは新規ユーザー登録時には有効とならない処理である。
認可
認証 (authentication) はサイトのユーザーを識別することであり、認可 (authorization) はそのユーザーが実行可能な操作を管理すること。
editアクションとupdateアクションはセキュリティ上欠陥がある。それはどのユーザーでもあらゆるアクションにアクセスできるため、誰でも (ログインしていないユーザーでも) ユーザー情報を編集できてしまう。そこでユーザーにログインを要求し、かつ自分以外のユーザー情報を変更できないように制御する(こういったセキュリティ上の制御機構をセキュリティモデルと呼ぶ)。まずログインしたユーザーが保護されたページへアクセスしようとした際にログインページへ転送する方法と許可されていないページに対しアクセスするログイン済みのユーザーにはルートURLにリダイレクトさせるようにする。
ユーザーに対しログインを要求する
Usersコントローラの中でbeforeフィルターを使い、転送させる仕組みを作る。
class UsersController < ApplicationController before_action :logged_in_user, only: [:edit, :update] # ログイン済みユーザーかどうか確認 def logged_in_user unless logged_in? flash[:danger] = "Please log in." redirect_to login_url end endデフォルトでは、beforeフィルターはコントローラ内のすべてのアクションに適用されるので、ここでは適切な:onlyオプション (ハッシュ) を渡すことで、:editと:updateアクションだけにこのフィルタが適用されるように制限をかけている。unlessは条件が偽の時に対応する処理が作動する。
editとupdateアクションの保護に対するtest
class UsersControllerTest < ActionDispatch::IntegrationTest def setup @user = users(:michael) end . . . test "should redirect edit when not logged in" do get edit_user_path(@user) assert_not flash.empty? assert_redirected_to login_url end test "should redirect update when not logged in" do patch user_path(@user), params: { user: { name: @user.name, email: @user.email } } assert_not flash.empty? assert_redirected_to login_url end end正しいユーザーを要求する
ログインを要求するだけでは不十分であり、ユーザーが自分の情報だけを編集できるようにする必要がある。そこでUserコントローラのtestを補完するようにtestを追加する。
まずfixtureファイルに2人目のユーザーを追加する。
次に9章で定義したlog_in_asメソッドを使ってeditアクションとupdateアクションをtestする。require 'test_helper' class UsersControllerTest < ActionDispatch::IntegrationTest def setup @user = users(:michael) @other_user = users(:archer) end . . . test "should redirect edit when logged in as wrong user" do log_in_as(@other_user) get edit_user_path(@user) assert flash.empty? assert_redirected_to root_url end test "should redirect update when logged in as wrong user" do log_in_as(@other_user) patch user_path(@user), params: { user: { name: @user.name, email: @user.email } } assert flash.empty? assert_redirected_to root_url end end@other_user(二人目のユーザー)を定義。
上段のtestは2人目のユーザーが1人目のユーザーのedit_user_pathに入った場合、フラッシュがでるか。ルートURLへリダイレクトするのかを確認している。
下段のtestは二人目のユーザーが一人目のユーザーの情報を変更する内容のpatchリクエストを送信した場合にフラッシュがでてルートURLへ値ダイレクトされるかを確認している。下段のtestをパスするため、correct_userというメソッドを作成し、beforeフィルターからこのメソッドを呼び出せるようにする。
before_action :correct_user, only: [:edit, :update] # 正しいユーザーかどうか確認 def correct_user @user = User.find(params[:id]) redirect_to(root_url) unless @user == current_user endフレンドリーフォワーディング
これまでは保護されたページにアクセスしようとすると問答無用で自分のプロフィールページに移動させられてしまう。別の言い方をすればログインしていないユーザーが編集ページにアクセス使用としていたならば、ユーザーがログインした後にはその編集ページにリダイレクトされるようにするのが望ましい動作である。
フレンドドリーフォワーディングのtest
require 'test_helper' class UsersEditTest < ActionDispatch::IntegrationTest def setup @user = users(:michael) end . . . test "successful edit with friendly forwarding" do get edit_user_path(@user) log_in_as(@user) assert_redirected_to edit_user_url(@user) name = "Foo Bar" email = "foo@bar.com" patch user_path(@user), params: { user: { name: name, email: email, password: "", password_confirmation: "" } } assert_not flash.empty? assert_redirected_to @user @user.reload assert_equal name, @user.name assert_equal email, @user.email end end編集URLへアクセス。ログインした時、編集ページにリダイレクトされているか?
失敗するテストが書けたので、ようやくフレンドリーフォワーディングを実装する準備ができた。ユーザーを希望のページに転送するには、リクエスト時点のページをどこかに保存しておき、その場所にリダイレクトさせる必要があります。この動作をstore_locationとredirect_back_orの2つのメソッドを使って実現する。これらのメソッドはSessionsヘルパーで定義していますmodule SessionsHelper . . . # 記憶したURL (もしくはデフォルト値) にリダイレクト def redirect_back_or(default) redirect_to(session[:forwarding_url] || default) session.delete(:forwarding_url) end # アクセスしようとしたURLを覚えておく def store_location session[:forwarding_url] = request.original_url if request.get? end end転送先のURLを保存する仕組みは、ユーザーをログインさせたときと同じで、session変数を使います。requestオブジェクトも使っています (request.original_urlでリクエスト先が取得できます)。store_locationメソッドでは、 リクエストが送られたURLをsession変数の:forwarding_urlキーに格納しています。ただし、GETリクエストが送られたときだけ格納するようにしておきます。これによって、例えばログインしていないユーザーがフォームを使って送信した場合、転送先のURLを保存させないようにできる。
ログインユーザー用beforeフィルターにstore_locationを追加する。
class UsersController < ApplicationController before_action :logged_in_user, only: [:edit, :update] before_action :correct_user, only: [:edit, :update] def edit end private def user_params params.require(:user).permit(:name, :email, :password, :password_confirmation) end # beforeアクション # ログイン済みユーザーかどうか確認 def logged_in_user unless logged_in? store_location flash[:danger] = "Please log in." redirect_to login_url end end # 正しいユーザーかどうか確認 def correct_user @user = User.find(params[:id]) redirect_to(root_url) unless current_user?(@user) end endフォワーディング自体を実装するには、redirect_back_orメソッドを使います。リクエストされたURLが存在する場合はそこにリダイレクトし、ない場合は何らかのデフォルトのURLにリダイレクトします。デフォルトのURLは、Sessionコントローラのcreateアクションに追加し、サインイン成功後にリダイレクトします このコードは、値がnilでなければsession[:forwarding_url]を評価し、そうでなければデフォルトのURLを使っています。
またリストではsession.delete(:forwarding_url) という行を通して転送用のURLを削除している点にも注意してください。すべてのユーザーを表示する
indexアクションを追加していく。ここではすべてのユーザーの一覧表示を行っていく。
データベースにサンプルデータを追加する方法
ユーザー出力のページネーション用リンクの追加をするユーザーの一覧ページを実装するためにまずはセキュリティモデルについて考える。ユーザーのshowページは今後もサイトを訪れた全てのユーザーから見えるようにするがindexページはログインしたユーザーにしか見せないようにし、未登録のユーザーがデフォルトで表示できるページを制限する。
indexページを不正なアクセスから守るためにindexアクションが正しくリダイレクトするか検証するtestを書いてみる。
require 'test_helper' class UsersControllerTest < ActionDispatch::IntegrationTest def setup @user = users(:michael) @other_user = users(:archer) end test "should redirect index when not logged in" do get users_path assert_redirected_to login_url end . . . end次にbeforeフィルターのlogged_in_userにindexアクションを追加してこのアクションを保護する。
そしてすべてのユーザーを表示するために、全ユーザーが格納された変数を作成し、順々に表示するindexビューを実装します。
<% provide(:title, 'All users') %> <h1>All users</h1> <ul class="users"> <% @users.each do |user| %> <li> <%= gravatar_for user, size: 50 %> <%= link_to user.name, user %> </li> <% end %> </ul>そしてユーザー一覧ページのリンクをheaderに更新して動かせるようにする。
サンプルユーザーの追加
今のままでは一人しかユーザー一覧がないため、ここからはサンプルのユーザーを追加する。
サンプルのユーザーを作成するにはGemfileにFakergemを追加する。データベース上にサンプルユーザーを生成するRailsタスク
db/seeds.rb User.create!(name: "Example User", email: "example@railstutorial.org", password: "foobar", password_confirmation: "foobar") 99.times do |n| name = Faker::Name.name email = "example-#{n+1}@railstutorial.org" password = "password" User.create!(name: name, email: email, password: password, password_confirmation: password) endExample Userという名前とメールアドレスを持つ1人のユーザと、それらしい名前とメールアドレスを持つ99人のユーザーを作成します。
ページネーション
これで、最初のユーザーにも仲間ができたが、今度は逆に1つのページに大量のユーザーが表示されてしまっている。これを解決するのがページネーション (pagination) というもので、この場合は、例えば1つのページに一度に30人だけユーザーを表示するというものです。
これを使うためには、Gemfileにwill_paginate gem とbootstrap-will_paginate gemを両方含め、Bootstrapのページネーションスタイルを使ってwill_paginateを構成する必要があります。gem 'will_paginate', '3.1.6' gem 'bootstrap-will_paginate', '1.0.0'indexアクションにあるUser.allを、ページネーションを理解できるオブジェクトに置き換える必要もあります。まずは、ビューに特殊なwill_paginateメソッドを追加します。
app/views/users/index.html.erb <% provide(:title, 'All users') %> <h1>All users</h1> <%= will_paginate %> <ul class="users"> <% @users.each do |user| %> <li> <%= gravatar_for user, size: 50 %> <%= link_to user.name, user %> </li> <% end %> </ul> <%= will_paginate %>indexアクションでUsersをページネートする。
def index @users = User.paginate(page: params[:page]) endユーザー一覧のtest
今回のテストでは、ログイン、indexページにアクセス、最初のページにユーザーがいることを確認、ページネーションのリンクがあることを確認、といった順でテストしていく。
まずFixtureで30人のユーザーを追加する。次にページネーションを含めたUserIndexのtestを追加
test/integration/users_index_test.rb require 'test_helper' class UsersIndexTest < ActionDispatch::IntegrationTest def setup @user = users(:michael) end test "index including pagination" do log_in_as(@user) get users_path assert_template 'users/index' assert_select 'div.pagination' User.paginate(page: 1).each do |user| assert_select 'a[href=?]', user_path(user), text: user.name end end endユーザーの削除
ここではユーザーを削除するためのリンクを追加する。また削除に必要なdestroyアクションも実装する。しかしその前に、削除を実行できる権限をもつ管理(Admin)ユーザーのクラスを作成する。
まず特権を持つ管理ユーザーを識別するために論理値をとるadmin属性をUserモデルに追加する。こうすると自動的にadmin?メソッドも使えるようになるのでこれを使って管理ユーザーの状態をtestする。destroyアクション
Userリソースの最後の仕上げとしてdestroyアクションへのリンクを追加する。まずユーザーindexページの各ユーザーに削除用のリンクを追加し続いて管理ユーザーへのアクセスを制限する。これにより現在のユーザーが管理者のときに限り[delete]リンクが表示されるようになる。
ユーザー削除用リンクの実装
app/views/users/_user.html.erb <li> <%= gravatar_for user, size: 50 %> <%= link_to user.name, user %> <% if current_user.admin? && !current_user?(user) %> | <%= link_to "delete", user, method: :delete, data: { confirm: "You sure?" } %> <% end %> </li>この削除リンクが動作するためには、destroyアクションを追加する必要があります。このアクションでは、該当するユーザーを見つけてActive Recordのdestroyメソッドを使って削除し、最後にユーザーindexに移動します。ユーザーを削除するためにはログインしていなくてはならないので、で:destroyアクションもlogged_in_userフィルターに追加しています。
destroyアクションでは、findメソッドとdestroyメソッドを1行で書くために2つのメソッドを連結 (chain) している。
結果として、管理者だけがユーザーを削除できるようになります (より具体的には、削除リンクが見えているユーザーのみ削除できる)。しかし、実はまだ大きなセキュリティホールがあります。ある程度の腕前を持つ攻撃者なら、コマンドラインでDELETEリクエストを直接発行するという方法でサイトの全ユーザーを削除してしまうことができるでしょう。サイトを正しく防衛するには、destroyアクションにもアクセス制御を行う必要があります。これを実装してようやく、管理者だけがユーザーを削除できるようにします。
app/controllers/users_controller.rb class UsersController < ApplicationController before_action :logged_in_user, only: [:index, :edit, :update, :destroy] before_action :correct_user, only: [:edit, :update] before_action :admin_user, only: :destroy . . . private . . . # 管理者かどうか確認 def admin_user redirect_to(root_url) unless current_user.admin? end endユーザー削除のtest
Usersコントローラをテストするために、アクション単位でアクセス制御をテストします。削除をテストするために、DELETEリクエストを発行してdestroyアクションを直接動作させます。このとき2つのケースをチェックします。
・ログインしていないユーザーであれば、ログイン画面にリダイレクトされること。
・ログイン済みではあっても管理者でなければ、ホーム画面にリダイレクトされること。管理者権限の制御をアクションレベルでテストする green
test/controllers/users_controller_test.rbrequire 'test_helper' class UsersControllerTest < ActionDispatch::IntegrationTest def setup @user = users(:michael) @other_user = users(:archer) end . . . test "should redirect destroy when not logged in" do assert_no_difference 'User.count' do delete user_path(@user) end assert_redirected_to login_url end test "should redirect destroy when logged in as a non-admin" do log_in_as(@other_user) assert_no_difference 'User.count' do delete user_path(@user) end assert_redirected_to root_url end endassert_no_differenceメソッドを使って、ユーザー数が変化しないことを確認している点に注目してください。
このテストでは、管理者ではないユーザーの振る舞いについて検証していますが、管理者ユーザーの振る舞いと一緒に確認できるとよさそうです。そこで、管理者であればユーザー一覧画面に削除リンクが表示される仕様を利用して今回のテストを追加していくことにします。
assert_difference 'User.count', -1 do delete user_path(@other_user) endassert_differenceメソッドを使ってユーザーが作成されたことを確認しましたが、今回は同じメソッドを使ってユーザーが削除されたことを確認しています。具体的には、DELETEリクエストを適切なURLに向けて発行し、User.countを使ってユーザー数が
1
減ったかどうかを確認しています。したがって、管理者や一般ユーザーのテスト、そしてページネーションや削除リンクのテストをすべてまとめると、次のようになります。
削除リンクとユーザー削除に対する統合テスト green
test/integration/users_index_test.rb require 'test_helper' class UsersIndexTest < ActionDispatch::IntegrationTest def setup @admin = users(:michael) @non_admin = users(:archer) end test "index as admin including pagination and delete links" do log_in_as(@admin) get users_path assert_template 'users/index' assert_select 'div.pagination' first_page_of_users = User.paginate(page: 1) first_page_of_users.each do |user| assert_select 'a[href=?]', user_path(user), text: user.name unless user == @admin assert_select 'a[href=?]', user_path(user), text: 'delete' end end assert_difference 'User.count', -1 do delete user_path(@non_admin) end end test "index as non-admin" do log_in_as(@non_admin) get users_path assert_select 'a', text: 'delete', count: 0 end endとなります。
本日はここまで。
- 投稿日:2020-04-05T09:21:47+09:00
Javascriptとrails(未完成)
JavaScriptとは
こちらで紹介しています。JavaScriptについて(素人が浅い知識で書かせていただきました)
Ajax
サーバーとの通信でデータを受け取り、ページを書き換える時に、
処理をするために別のcontrollerに飛んで、処理後に再度今のページの中身を読み込んで戻ってくるのは処理が多くて遅くなる
↓
Ajaxを使えば今のページのままで、自分の命令が非同期でバックグラウンドで行割れる(今のページの再読み込みをせずに処理できる)。Ajaxの処理は全てJavaScriptが行わせている。Ajaxの実行の仕方
linkにAjaxを仕込む
↓
そのリンクが押されれば、今のページを表示したまま、別の処理を実行する(非同期処理)
↓
サーバサイドでその処理が完了すれば処理後の画面になるよう表示する。非同期処理後の画面表示をする処理は2種類あるため次の項目で示す注意:Ajaxでは現在のページを表示したまま、リンク先の処理非同期で実行するため、リンク先の処理(アクション内)にはriedirectを記述しない。
非同期処理後の画面表示
非同期処理後の画面表示をする処理は2種類ある。以下で削除ボタンにAjaxを仕込んだときの例で説明する
1
サーバーサイドからの反応で、Ajaxの成功、失敗を判断して、Ajax処理が成功すれば、rails-ujsによってAjaxを仕込んだリンクにAjax::successという値がつく
↓
Ajax::successになっていれば、そのリンクに関連した要素を非表示にする。この処理をJsファイルに記述。2(SJRというやり方)
サーバーサイドで処理を完了すれば、サーバーサイド側からJsの処理を命令するようにする。実際は、命令内容はjs.erbで書かれrubyでjsの処理を実行できるようにしてある。これはサーバーサイド川ではrubyでしか命令を行えなえずjsファイルでは命令実行ができないから、
注意:サーバーサイド側ではDOMを判断できない。しかし削除されたインスタンスのidを把握することはできるため、それを使って画面変更(削除)を行う。
↓
実際のやり方
削除したい要素に、そのインスタンスのidがわかるようにHTMLのid属性を追加する
↓
js.erbで任意のHTMLのid属性を持つ要素を削除するようにする。2のメリットはサーバー側でデータを使って、Jsの内容を作成できること。デメリットはサーバーサイドからのjs命令(js.erb)をviewディレクトリの下で作成するため、共通化や見直すのが大変
補足
ajaxの処理はrails-ujsによって行われており、ajaxの成功失敗の判断もこいつが行っている
参考文献は現場で使える Ruby on Rails 5速習実践ガイド
補足
coffeeScriptとは
これはJsの代替言語で、JSで表現したいことを簡単にかける。またアセットパイプラインによって最終的にjsに変換されのでrailsでも使用できる。しかし最近はcoffeeScriptのメリットが少なくなってきたため、使用しないケースもある
turbolinks
こちらで紹介しています。JavaScriptについて(素人が浅い知識で書かせていただきました)
またturbolinksの具体的な機能はgetを用いたページ移行を高速化すること。具体的にいうと、ページ移行が起きた時に共通部分なる部分(cssやjs)は前のページの内容を残したまま移行するようにする。どのページでも同じcssやjsファイルを読み込んでいるため、読み込みを無くし引き継ぎをすることで高速化を実現している
- 投稿日:2020-04-05T09:21:47+09:00
Javascriptとrails
JavaScriptとは
こちらで紹介しています。JavaScriptについて(素人が浅い知識で書かせていただきました)
アセットパイプライン
こちらで紹介しています。railsのアセットパイプラインと本番環境のデプロイについて
Ajax
サーバーとの通信でデータを受け取り、ページを書き換える時に、
処理をするために別のcontrollerに飛んで、処理後に再度今のページの中身を読み込んで戻ってくるのは処理が多くて遅くなる
↓
Ajaxを使えば今のページのままで、自分の命令が非同期でバックグラウンドで行割れる(今のページの再読み込みをせずに処理できる)。Ajaxの処理は全てJavaScriptが行わせている。Ajaxの実行の仕方
linkにAjaxを仕込む
↓
そのリンクが押されれば、今のページを表示したまま、別の処理を実行する(非同期処理)
↓
サーバサイドでその処理が完了すれば処理後の画面になるよう表示する。非同期処理後の画面表示をする処理は2種類あるため次の項目で示す注意:Ajaxでは現在のページを表示したまま、リンク先の処理非同期で実行するため、リンク先の処理(アクション内)にはriedirectを記述しない。
非同期処理後の画面表示
非同期処理後の画面表示をする処理は2種類ある。以下で削除ボタンにAjaxを仕込んだときの例で説明する
1
サーバーサイドからの反応で、Ajaxの成功、失敗を判断して、Ajax処理が成功すれば、rails-ujsによってAjaxを仕込んだリンクにAjax::successという値がつく
↓
Ajax::successになっていれば、そのリンクに関連した要素を非表示にする。この処理をJsファイルに記述。2(SJRというやり方)
サーバーサイドで処理を完了すれば、サーバーサイド側からJsの処理を命令するようにする。実際は、命令内容はjs.erbで書かれrubyでjsの処理を実行できるようにしてある。これはサーバーサイド川ではrubyでしか命令を行えなえずjsファイルでは命令実行ができないから、
注意:サーバーサイド側ではDOMを判断できない。しかし削除されたインスタンスのidを把握することはできるため、それを使って画面変更(削除)を行う。
↓
実際のやり方
削除したい要素に、そのインスタンスのidがわかるようにHTMLのid属性を追加する
↓
js.erbで任意のHTMLのid属性を持つ要素を削除するようにする。2のメリットはサーバー側でデータを使って、Jsの内容を作成できること。デメリットはサーバーサイドからのjs命令(js.erb)をviewディレクトリの下で作成するため、共通化や見直すのが大変
補足
ajaxの処理はrails-ujsによって行われており、ajaxの成功失敗の判断もこいつが行っている
参考文献は現場で使える Ruby on Rails 5速習実践ガイド
補足
coffeeScriptとは
これはJsの代替言語で、JSで表現したいことを簡単にかける。またアセットパイプラインによって最終的にjsに変換されのでrailsでも使用できる。しかし最近はcoffeeScriptのメリットが少なくなってきたため、使用しないケースもある
turbolinks
こちらで紹介しています。JavaScriptについて(素人が浅い知識で書かせていただきました)
またturbolinksの具体的な機能はgetを用いたページ移行を高速化すること。具体的にいうと、ページ移行が起きた時に共通部分なる部分(cssやjs)は前のページの内容を残したまま移行するようにする。どのページでも同じcssやjsファイルを読み込んでいるため、読み込みを無くし引き継ぎをすることで高速化を実現しているyarn
これはJsのパッケージマネージャー。Jsのパッケージをどんなバージョンでインストールするかを管理。インストール内容に一貫性を持たせたりできる。railsでいうgemみたいなもの。また同じJsのパッケージマネージャーのnpmとも互換性があるため、便利。
参考文献
yarnとは
高速で、信頼性が高く、そして安全な依存関係の管理webpacker
これはJsのビルドツール。ビルドツールとは実行環境で動作できるように組み立てるツールのこと。アセットパイプライン作成にはSprocketsが採用されていたが、webpackerを使用することで、より高度な処理をできるようにする。
- 投稿日:2020-04-05T04:51:40+09:00
[rails,payjp]カード登録の際に登録画面をリロードしないとトークンを作成できない時の解決例
1.原因
今回の筆者の問題はturbolinksが効いていたからでした。
2.なぜ起こった?
理由は、turbolinksの機能が影響範囲ページの遷移を非同期で行う(影響範囲の全てのviewページが合わさって1ページとして扱う)ためでした。
他画面を経由し複数で情報を持った状態でクレジットカードの登録をしようとすると、悪意のある情報を持っている危険性があり安全性を保てないと見なされてしまいpayjpからの返答を受けることができなくなっていました。3.解決方法
クレジットカード登録画面のみturbolinks(非同期通信)を切ってページ遷移するように記述することで筆者は解決しました。
具体的には
app/views/layouts/apprication.html.haml(全体のbodyの記述部分)
とapp/views/cards/index(ページ遷移元)
を下記のように修正しましたapp/views/layouts/apprication.html.haml〜前略(header部分の記述は省略します)〜 %body - if content_for?(:body_attributes) = yield(:body_attributes) = render 'layouts/notification' = yieldapp/views/cards/index〜前略〜 = link_to "/cards/new", class: 'method-of-payment__body__button__icon',"data-turbolinks": false do #app/views/cards/newに遷移する記述の部分に "data-turbolinks": false をつけました 〜後略〜4.参考記事
https://gist.github.com/saboyutaka/8727377
https://qiita.com/Cheekyfunkymonkey/items/216bf7426493e6213927
https://qiita.com/keitah/items/05f02efe4e11ab2473e8
- 投稿日:2020-04-05T01:26:58+09:00
CircleCI で並列実行した RSpec のカバレッジを Coveralls に送る
Coveralls に以下のドキュメントがあるのだけど、書いてある通りにやってもうまくいかなかったので、なんとかうまくいった方法を書いておきます。
やりたいこと
RSpec を並列で実行し、すべてのインスタンスの終了を待って、別のジョブで各インスタンスのカバレッジの結果をマージして Coveralls に送信したい。
- ドキュメントには
Coveralls.wear_merged!
を呼んで最後にcoveralls:push
を実行しろとあるけれど、coveralls:push
(Coveralls.push!
) で使われているSimpleCov::ResultMerger.merged_result
は 同じ環境で実行された 複数のテストのカバレッジ結果をマージするものであり、違う環境で実行された結果をマージできるわけではない。- Webhookを使う方法もあるけれど、テストを実行するジョブと結果を送信するジョブが違うので、結果を送信するときに
payload[build_num]
を指定することができない。やり方
https://github.com/lemurheavy/coveralls-ruby
Gemfilegroup :test do gem 'coveralls', '~> 0.8.23', require: false endRSpec
Coveralls.wear!
は Coveralls にカバレッジを送信するけれど、Coveralls.wear_merged!
は送信しない(SimpleCov を実行してるだけ)。spec/rails_helper.rbif ENV['COVERALLS_REPO_TOKEN'] require 'coveralls' Coveralls.wear_merged!('rails') end # [...]カバレッジ結果をマージ・送信する Rake Task をつくる
SimpleCov の README にある "Merging test runs under different execution environments" の通りにやればいいのだけど、Coveralls の gem が依存している SimpleCov のバージョンが古くて、
SimpleCov.collate
が存在しない。よって自分でつくる必要がある。lib/tasks/coverage.rakenamespace :coverage do desc 'Collate all result sets and push to Coveralls' task push: %i[environment collate] do require 'coveralls' Coveralls.push! end desc 'Collate all result sets generated by the different test runners' task collate: :environment do require 'simplecov' # coverage/.resultset-*.json を coverage/.resultset.json にまとめる # see: https://github.com/colszowka/simplecov/blob/v0.18.5/lib/simplecov.rb#L80 results = Dir['coverage/.resultset-*.json'].flat_map do |filename| (JSON.parse(File.read(filename)) || {}).map do |command_name, coverage| SimpleCov::Result.from_hash(command_name => coverage) end end SimpleCov::ResultMerger.merge_results(*results).tap do |result| SimpleCov::ResultMerger.store_result(result) end end endCircleCI
.circleci/config.ymlversion: 2.1 executors: app: docker: - image: circleci/ruby:2.6.5-node-browsers environment: BUNDLE_PATH: vendor/bundle RAILS_ENV: test jobs: test: executor: app parallelism: 2 steps: - checkout # [...] - persist_to_workspace: root: . paths: - . - run: name: RSpec in parallel command: bin/rspec $(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings) # coverage/.resultset.json にカバレッジ結果が生成されているので、 # 名前がぶつからないように別の名前を付けたファイルを persist_to_workspace する - run: name: Prepare to collate coverage results command: cp coverage/.resultset.json "coverage/.resultset-${CIRCLE_NODE_INDEX}.json" - persist_to_workspace: root: . paths: - coverage/.resultset-*.json report: executor: app steps: - attach_workspace: at: . # こんな感じになっているはず # ./coverage # .resultset-0.json # .resultset-1.json - run: bin/rake coverage:push workflows: version: 2 test-report: jobs: - test - report: requires: - testできた
#!/bin/bash -eo pipefail bin/rake coverage:push Running via Spring preloader in process 81 [Coveralls] Submitting to https://coveralls.io/api/v1 [Coveralls] Job #132.1 [Coveralls] https://coveralls.io/jobs/XXXXXXXX Coverage is at 100.0%. Coverage report sent to Coveralls. CircleCI received exit code 0
- 投稿日:2020-04-05T01:13:49+09:00
【Rails】deviseを使用した簡単なログイン機能まとめ
はじめに
学習中の備忘録です。
概要
新規アプリ作成の際にdeviseのコマンドなど忘れるのでまとめ。
- 導入
- devise設定ファイル作成
- モデル作成
- ビューファイル作成
- deviseによって設定されるPrefixの一部
前提
rails 5.2.3
導入
gemファイルに追記
Gemfilegem 'devise'インストール
ターミナル$ bundle installサーバー再起動
ターミナル$ rails sdeviseの設定ファイルを作成
ターミナル$ rails g devise:install新規作成されるファイル
- config/initializers/devise.rb
- config/locales/devise.en.yml
モデル作成
ターミナル$ rails g devise user新規作成されるファイル
- app/models/user.rb
- db/migrate/20XXXXXXXXXXXX_devise_create_users.rb
- test/fixtures/users.yml
- test/models/user_test.rb
また、config/routes.rbに以下の様な記述が自動的に追記されます。
【例】config/routes.rbRails.application.routes.draw do devise_for :users #以下略devise_for :usersの記述により、ログイン・新規登録で必要なルーティングが生成されます。
作成されたmigrationファイルを実行
ターミナル$ rails db:migrateビューファイル作成
ターミナル$ rails g devise:views新規作成されるファイル
- app/views/devise以下のディレクトリにあるビューファイル各種
deviseによって設定されるPrefixの一部
リクエスト Prefix パス devise/sessions#new new_user_session /users/sign_in devise/registrations#new new_user_registration /users/sign_up devise/sessions#destroy destroy_user_session /users/sign_out あとは好きな場所に上記のリンクをはれば完成です。
まとめ
ユーザー情報の編集などは必要に応じて追記するかもです。