- 投稿日:2020-03-17T23:50:43+09:00
アプリ作成 アウトプット
- 投稿日:2020-03-17T23:24:15+09:00
Capybaraでネスト有りのルーティングパスにvisitコマンドでアクセスする for Ruby on Rails
ネスト有りのルーティングでテストしようとした
specファイルを書いていたとき、ネスト有りのルーティングのテストでvisitコマンドのパスはどう書くんだと?疑問に思いました。
viewファイルと同じ感じでいけるのか?いう疑問で、試してみるといけました。設定
routes.rb
ではこのような設定があるとします。routes.rbresources :categories do resources :products end
rails routes
とすると、こんな感じになります。結果ログcategory_products GET /categories/:category_id/products(.:format) products#index POST /categories/:category_id/products(.:format) products#create new_category_product GET /categories/:category_id/products/new(.:format) products#new edit_category_product GET /categories/:category_id/products/:id/edit(.:format) products#edit category_product GET /categories/:category_id/products/:id(.:format) products#show PATCH /categories/:category_id/products/:id(.:format) products#update PUT /categories/:category_id/products/:id(.:format) products#update DELETE /categories/:category_id/products/:id(.:format) products#destroy失敗例
一番上のpathにアクセスしようとして、やりがちなことですが、そのままパスを書くとエラーになる。
実行例let!(:category) { FactoryBot.create(:category) visit category_products_path結果ログActionController::UrlGenerationError: No route matches {:action=>"index", :controller=>"products"}, missing required keys: [:category_id]成功例
viewファイルと同じ感じで、ルーティングパスに変数を渡すと成功します。
root_path
から、ちまちまとclick_link
で移動するのも良いのですが、こういう手もありかなと思います。実行例let!(:category) { FactoryBot.create(:category) visit category_products_path(category)結果ログFinished in 1.05 seconds (files took 2.33 seconds to load) 1 example, 0 failures
- 投稿日:2020-03-17T23:24:15+09:00
Rspecでネスト有りのルーティングパスにvisitコマンドでアクセスする for Ruby on Rails
ネスト有りのルーティングでテストしようとした
specファイルを書いていたとき、ネスト有りのルーティングのテストでvisitコマンドのパスはどう書くんだと?疑問に思いました。
viewファイルと同じ感じでいけるのか?いう疑問で、試してみるといけました。routes.rbの設定
routes.rb
ではこのような設定があるとします。routes.rbresources :categories do resources :products end
rails routes
とすると、こんな感じになります。結果ログcategory_products GET /categories/:category_id/products(.:format) products#index POST /categories/:category_id/products(.:format) products#create new_category_product GET /categories/:category_id/products/new(.:format) products#new edit_category_product GET /categories/:category_id/products/:id/edit(.:format) products#edit category_product GET /categories/:category_id/products/:id(.:format) products#show PATCH /categories/:category_id/products/:id(.:format) products#update PUT /categories/:category_id/products/:id(.:format) products#update DELETE /categories/:category_id/products/:id(.:format) products#destroyvisitの失敗例
一番上のpathにアクセスしようとして、やりがちなことですが、そのままパスを書くとエラーになる。
実行例let!(:category) { FactoryBot.create(:category) visit category_products_path結果ログActionController::UrlGenerationError: No route matches {:action=>"index", :controller=>"products"}, missing required keys: [:category_id]visitの成功例
viewファイルと同じ感じで、ルーティングパスに変数を渡すと成功します。
root_path
から、ちまちまとclick_link
で移動するのも良いのですが、こういう手もありかなと思います。実行例let!(:category) { FactoryBot.create(:category) visit category_products_path(category)結果ログFinished in 1.05 seconds (files took 2.33 seconds to load) 1 example, 0 failures
- 投稿日:2020-03-17T23:24:10+09:00
【ruby】Docker開発環境へのGoogle Cloud Translation API (v2)導入手順
開発環境
ruby '2.6.3'
rails '6.0.2'Google Cloud Translation APIとは
- ウェブサイトやアプリを 100 以上の言語に瞬時に翻訳したい場合などに役立つのが Translation API です。
Translation API の料金
Google Cloud の無料枠
私の場合は12 か月間の無料トライアル(Google Cloud サービスで使用できる $300 相当のクレジット付き)。
なので無料です。導入手順
Cloud Translate API の有効化
- APIとサービスを有効化を押す
Cloud Translate API
を検索→有効化サービスアカウントキーの作成
サービスカウント: 「新しいサービスアカウント」を選択 サービスアカウント名: (任意) 役割: オーナー (Project > オーナー) サービスアカウントID: (任意) キーのタイプ: JSON
「作成」ボタンを押下すると、jsonファイルがダウンロードされます
サービスアカウントキーの適用,環境変数の設定
- GOOGLE_APPLICATION_CREDENTIALSという名前の環境変数を作成し、先ほどダウンロードしたjsonファイルのパスを設定します。
ターミナルvim .zshrc.zshrcexport GOOGLE_APPLICATION_CREDENTIALS="ダウンロードしたファイルパス"
- .zshrcの更新。
ターミナルsource ~/.zshrcこれでいつでもローカル環境では参照できるようになります。
保存されているか確認
ターミナルprintenv | grep GOOGLE => export GOOGLE_APPLICATION_CREDENTIALS="ダウンロードしたファイルパス"docker上でGOOGLE_APPLICATION_CREDENTIALSを適応
- 開発中のディレクトリにjsonファイルをコピーする。(ファイル名は変更しても問題ありません、今回はkey.jsonという名前で行います。)
- .gitignoreに追記する
.gitignore/key.json
- DockerfileでDocker内にコピーする
DockerfileCOPY key.json key.json ENV GOOGLE_APPLICATION_CREDENTIALS key.json
docker-compose build
# rails編
gem導入
gem 'google-cloud-translate'
私の場合は外部DBから取ってきた英文を日本語にして保存する感じなので下記を変えればいい感じですが。実際にviewから翻訳したい場合はリンクを参照してください。
seeds.rb# 最初に作ったプロジェクトのIDです。そのまま書くのはあまりよろしくないです。 project_id = "Your Google Cloud project ID" # 実際に訳す文です text = "The text you would like to translate" # 何に訳すかを指定します `"The ISO 639-1 code of language to translate to, eg. 'en'"` language_code = "en" require "google/cloud/translate" translate = Google::Cloud::Translate.new version: :v2, project_id: project_id translation = translate.translate text, to: language_code puts "Translated '#{text}' to '#{translation.text.inspect}'" puts "Original language: #{translation.from} translated to: #{translation.to}"私の場合require "google/cloud/translate" def translate(synopsis:) project_id = Rails.application.credentials.api[:id] text = synopsis language_code = 'ja' translate = Google::Cloud::Translate.new version: :v2, project_id: project_id translation = translate.translate text, to: language_code return translation.text.inspect end最後に
今回は(v2)のGoogle Translation APIということをお忘れなく。
おしまい
- 投稿日:2020-03-17T23:19:04+09:00
Ruby on RailsでWebAPIの作成
Ruby on RailsでWebAPIの作成
はじめに
この記事では、Ruby on RailsにおけるAPIの作り方を簡単に紹介します。
データベースへのユーザ登録、参照、消去、更新ができるAPIを作成し、いじりながら解説します。前提知識
- API
- JSON
- HTTPリクエスト、レスポンス
- GET, POST, DELETE, etc
環境
- ruby 2.6.5
- Rails 6.0.2
作り方
なにはともあれAPIの基盤の作成。
[tmp]$ rails new RailsApi --apiご存知
rails new [アプリ名]
とすることでアプリの基盤を作成することができるが、 --apiのオプションをつけることでAPIに必要なものだけに絞って作ってくれる。[tmp]$ cd RailsApiRailsApiフォルダに移動。
[RailsApi]$ rails g scaffold user user_id:string password:string
rails g (generate) scaffold [モデル名(単数形)] カラム名:データ型 (カラム名:データ型)
今回はユーザテーブルにIDとパスワードを持たせようと思うのでこの様に指定しました。IDのカラム名をidとしない様に注意。(自動生成されるカラム名のidと被るため)[RailsApi]$ rails db:create [RailsApi]$ rails db:migrateデータベースの作成とテーブルの作成を行います。
そしてなんと、、、
これでAPIの完成です。(マジ)詳しくはあとで解説するとしてこのAPIを試してみましょう。
作成したAPIを試す
まず、APIをいじるならhttpリクエスト送信とレスポンス受信ができるツールが必要なので、chromeの拡張機能であるAdvanced REST clientをダウンロードしておきましょう。
全件取得
[AppName]$ rails s上記コマンドでローカルサーバを起動し、
http://localhost:3000/users/
へGETリクエストを送ってみましょう。これは「データの全件取得」を意味します。
(rails g scaffold user ~
でuserのモデルを作成したためその複数形をパスに指定。)すると以下の様な空のレスポンスが返ってきます。これはまだデータ投入していないからです。
データ投入
ではデータ投入しましょう。
~/users/
へPOSTリクエストを送ります。これは「bodyのjsonを元にデータを作成する」ことを意味します。その際に、リクエストのBodyを以下の様に指定しましょう。
Body content type : application/json
Body : {"user_id":"hoge","password":"fuga"}
すると以下の様なレスポンスが返ってきてユーザが作られたことが分かります。
先ほど入れた2件のデータが両方取れます。
1件取得
次は、
~/users/2
へGETリクエストを送ってみましょう。これは「idが2である人のデータを取得する」ことを意味しており、以下の様なレスポンスが返ってきます。
削除
次は、
~/users/2
へDELETEリクエストを送ってみましょう。これは「idが2である人のデータを削除する」ことを意味しており、以下の様なレスポンスが返ってきます。
idが2のデータがなくなっていることがわかります。
更新
最後に、
~/users/1
へPATCHリクエスト(PUTでも可)を送ってみましょう。これは「bodyのjsonを元にidが1であるデータを更新する」ことを意味します。その際に、リクエストのBodyを以下の様に指定しましょう。
idが1のデータのuser_idがhogehogeに変更されているのがわかると思います。
メソッドとパスその効果をまとめると以下の様になります。
メソッド パス 効果 GET /users/ 全件取得 POST /users/ bodyのjsonでデータ投入 GET /users/:id/ 該当idのデータを取得 PATCH /users/:id/ 該当idのデータをbodyのjsonで更新 PUT /users/:id/ 該当idのデータをbodyのjson更新 DELETE /users/:id/ 該当idのデータを削除 さいごに
- なぜ
rails g scaffold ~
するだけでこの様なAPIが作成できるのか- ソースコードの中身
- 自分好みの仕様に作り替えるには
は別の記事で解説したいと思います。
ご質問などあれば気軽にどうぞ。
@ruemura3
- 投稿日:2020-03-17T23:19:04+09:00
【5分で出来る】Ruby on RailsでWeb APIの作成
1. はじめに
この記事では、Ruby on RailsにおけるAPIの作り方を簡単に紹介します。
Rails が非常に優秀なので作成は5分もあればできるでしょう。(Rails を使う環境が整っている前提)
データベースへのユーザ登録、参照、消去、更新ができるAPIを作成し、いじりながら解説します。前提知識
- API
- JSON
- HTTPリクエスト、レスポンス
- GET, POST, DELETE, etc
環境
- ruby 2.6.5
- Rails 6.0.2
- macOS Catalina 10.15.3
2. 作り方
なにはともあれAPIの基盤の作成。
[tmp]$ rails new RailsApi --apiご存知
rails new [アプリ名]
とすることでアプリの基盤を作成することができるが、 --apiのオプションをつけることでAPIに必要なものだけに絞って作ってくれる。[tmp]$ cd RailsApiRailsApiフォルダに移動。
[RailsApi]$ rails g scaffold user user_id:string password:string
rails g( or generate) scaffold [モデル名(単数形)] カラム名:データ型 (カラム名:データ型)
今回はユーザテーブルにIDとパスワードを持たせようと思うのでこの様に指定しました。IDのカラム名をidとしない様に注意。(自動生成されるカラム名のidと被るため)[RailsApi]$ rails db:create [RailsApi]$ rails db:migrateデータベースの作成とテーブルの作成を行います。
そしてなんと、、、
これでAPIの完成です。(マジ)詳しくはあとで解説するとしてこのAPIを試してみましょう。
3. 作成したAPIを試す
まず、APIをいじるならhttpリクエスト送信とレスポンス受信ができるツールが必要なので、chromeの拡張機能であるAdvanced REST clientをダウンロードしておきましょう。
全件取得
[AppName]$ rails s上記コマンドでローカルサーバを起動し、
http://localhost:3000/users/
へGETリクエストを送ってみましょう。これは「データの全件取得」を意味します。
(rails g scaffold user ~
でuserのモデルを作成したためその複数形をパスに指定。)すると以下の様な空のレスポンスが返ってきます。これはまだデータ投入していないからです。
データ投入
ではデータ投入しましょう。
~/users/
へPOSTリクエストを送ります。これは「bodyのjsonを元にデータを作成する」ことを意味します。その際に、リクエストのBodyを以下の様に指定しましょう。
Body content type : application/json
Body : {"user_id":"hoge","password":"fuga"}
すると以下の様なレスポンスが返ってきてユーザが作られたことが分かります。
先ほど入れた2件のデータが両方取れます。
1件取得
次は、
~/users/2
へGETリクエストを送ってみましょう。これは「idが2である人のデータを取得する」ことを意味しており、以下の様なレスポンスが返ってきます。
削除
次は、
~/users/2
へDELETEリクエストを送ってみましょう。これは「idが2である人のデータを削除する」ことを意味しており、以下の様なレスポンスが返ってきます。
idが2のデータがなくなっていることがわかります。
更新
最後に、
~/users/1
へPATCHリクエスト(PUTでも可)を送ってみましょう。これは「bodyのjsonを元にidが1であるデータを更新する」ことを意味します。その際に、リクエストのBodyを以下の様に指定しましょう。
idが1のデータのuser_idがhogehogeに変更されているのがわかると思います。
メソッドとパスその効果をまとめると以下の様になります。
メソッド パス 効果 GET /users/ 全件取得 POST /users/ bodyのjsonでデータ投入 GET /users/:id/ 該当idのデータを取得 PATCH /users/:id/ 該当idのデータをbodyのjsonで更新 PUT /users/:id/ 該当idのデータをbodyのjson更新 DELETE /users/:id/ 該当idのデータを削除 4. さいごに
理解するには自分でやってみるのが一番なので自分で作ってみてください。ユーザのAPIができたら投稿記事のAPIなんかも作ってみるといいと思います。
- なぜ
rails g scaffold ~
するだけでこの様なAPIが作成できるのか- ソースコードの中身
- 自分好みのAPIに作り替えるには
は別の記事で解説したいと思います。
ご質問などあれば気軽にどうぞ。
@ruemura3
- 投稿日:2020-03-17T23:19:04+09:00
【5分で出来る】Ruby on RailsでWebAPIの作成
1. はじめに
この記事では、Ruby on RailsにおけるAPIの作り方を簡単に紹介します。
Rails が非常に優秀なので作成は5分もあればできるでしょう。(Rails を使う環境が整っている前提)
データベースへのユーザ登録、参照、消去、更新ができるAPIを作成し、いじりながら解説します。前提知識
- API
- JSON
- HTTPリクエスト、レスポンス
- GET, POST, DELETE, etc
環境
- ruby 2.6.5
- Rails 6.0.2
2. 作り方
なにはともあれAPIの基盤の作成。
[tmp]$ rails new RailsApi --apiご存知
rails new [アプリ名]
とすることでアプリの基盤を作成することができるが、 --apiのオプションをつけることでAPIに必要なものだけに絞って作ってくれる。[tmp]$ cd RailsApiRailsApiフォルダに移動。
[RailsApi]$ rails g scaffold user user_id:string password:string
rails g( or generate) scaffold [モデル名(単数形)] カラム名:データ型 (カラム名:データ型)
今回はユーザテーブルにIDとパスワードを持たせようと思うのでこの様に指定しました。IDのカラム名をidとしない様に注意。(自動生成されるカラム名のidと被るため)[RailsApi]$ rails db:create [RailsApi]$ rails db:migrateデータベースの作成とテーブルの作成を行います。
そしてなんと、、、
これでAPIの完成です。(マジ)詳しくはあとで解説するとしてこのAPIを試してみましょう。
3. 作成したAPIを試す
まず、APIをいじるならhttpリクエスト送信とレスポンス受信ができるツールが必要なので、chromeの拡張機能であるAdvanced REST clientをダウンロードしておきましょう。
全件取得
[AppName]$ rails s上記コマンドでローカルサーバを起動し、
http://localhost:3000/users/
へGETリクエストを送ってみましょう。これは「データの全件取得」を意味します。
(rails g scaffold user ~
でuserのモデルを作成したためその複数形をパスに指定。)すると以下の様な空のレスポンスが返ってきます。これはまだデータ投入していないからです。
データ投入
ではデータ投入しましょう。
~/users/
へPOSTリクエストを送ります。これは「bodyのjsonを元にデータを作成する」ことを意味します。その際に、リクエストのBodyを以下の様に指定しましょう。
Body content type : application/json
Body : {"user_id":"hoge","password":"fuga"}
すると以下の様なレスポンスが返ってきてユーザが作られたことが分かります。
先ほど入れた2件のデータが両方取れます。
1件取得
次は、
~/users/2
へGETリクエストを送ってみましょう。これは「idが2である人のデータを取得する」ことを意味しており、以下の様なレスポンスが返ってきます。
削除
次は、
~/users/2
へDELETEリクエストを送ってみましょう。これは「idが2である人のデータを削除する」ことを意味しており、以下の様なレスポンスが返ってきます。
idが2のデータがなくなっていることがわかります。
更新
最後に、
~/users/1
へPATCHリクエスト(PUTでも可)を送ってみましょう。これは「bodyのjsonを元にidが1であるデータを更新する」ことを意味します。その際に、リクエストのBodyを以下の様に指定しましょう。
idが1のデータのuser_idがhogehogeに変更されているのがわかると思います。
メソッドとパスその効果をまとめると以下の様になります。
メソッド パス 効果 GET /users/ 全件取得 POST /users/ bodyのjsonでデータ投入 GET /users/:id/ 該当idのデータを取得 PATCH /users/:id/ 該当idのデータをbodyのjsonで更新 PUT /users/:id/ 該当idのデータをbodyのjson更新 DELETE /users/:id/ 該当idのデータを削除 4. さいごに
理解するには自分でやってみるのが一番なので自分で作ってみてください。ユーザのAPIができたら投稿記事のAPIなんかも作ってみるといいと思います。
- なぜ
rails g scaffold ~
するだけでこの様なAPIが作成できるのか- ソースコードの中身
- 自分好みのAPIに作り替えるには
は別の記事で解説したいと思います。
ご質問などあれば気軽にどうぞ。
@ruemura3
- 投稿日:2020-03-17T22:59:10+09:00
Rails アプリにGoogleMap APIを導入する
はじめに
投稿画面で、ユーザから入力された地名を、GoogleMap上に反映させるための機能実装をまとめます。
実装方法
1.ライブラリをインストール。
以下のライブラリをGemfileに追記します。
Gemfilegem 'gmaps4rails' gem 'geocoder'そして、installします。
terminal$ bundle install2.カラムの追加
次に、すでに存在しているpostsテーブルにカラムを追加していきます。
20200223012643_add_address_to_posts.rbclass AddAddressToPosts < ActiveRecord::Migration[5.2] def change add_column :posts, :address, :string add_column :posts, :latitude, :float add_column :posts, :longitude, :float end endaddress(住所), latitude(緯度), longitude(経度)カラムを追加します。
先ほど、インストールしたライブラリが、このaddressに格納された情報から緯度、経度を自動で計算をし、それぞれのカラムに格納してくれます。マイグレーションファイルをDBに反映させるのを忘れずに
terminal$ rails db:migrate3.Mapの表示部分を作る
GoogleMapを表示させたい部分に以下のコードを追加します。
index.html.erb<h3>釣行場所</h3> <div class="map"> <div id="map"> </div> </div> <div type="text/javascript"> <script> function initMap(){ let map = new google.maps.Map(document.getElementById('map'), { center: {lat: <%= @post.latitude %>, lng: <%= @post.longitude %> }, zoom: 15 }); } </script> <script src="https://maps.googleapis.com/maps/api/js?key=<%= ENV['API_KEY'] %>&callback=initMap" async defer></script>このままだと、表示される地図が大きすぎるので、任意のサイズに調整します。
posts.scss#map { height: 300px; width: 400px; }4.ユーザが地名を入力するフォームを作る
ユーザがpostsを投稿するformに以下のように追加をします。
new.html.erb<%= form_with(model: @post, local: true) do |f| %> ・ ・ <div class="form-group"> <%= f.label :address, '場所' %> <%= f.text_field :address, class: 'form-control' %> </div> ・ ・ <%= f.submit '投稿する', class: 'btn btn-primary btn-block' %>5. 最後に表示を確認
このように、投稿フォームで入力された場所をマップが表示していれば成功です。
おわりに
自分のアプリケーションにGoogleMapを搭載するのに、色々と試行錯誤しましたが、意外とシンプルなコードで実装することができました。
GoogleMapを使った機能を実装する際には、GoogleのAPIキーを取得する必要があるのですが、その辺りの詳細はまたの機会にまとめます。
- 投稿日:2020-03-17T21:06:37+09:00
Railsのバージョンを5から6にしたらBlocked Hostというエラーが出てきてびっくりした話
開発中のサービスのRailsのバージョンを5から6に上げたのですが、
Blocked host
というエラーが出るようになりこれまで使えていたユーザーの招待機能が使えなくなる事象に遭遇しました。Rails 6から導入された新しいセキュリティー対策のようです。
解決策としてエラー画面に表示されている通りconfigファイルに許可するホストを追加しました。development.rb or production.rb config.hosts << "app.survelion.com"バージョンアップの際は気をつけましょう。
参照記事: https://www.tmp1024.com/articles/solve-blocked-host-of-rails
- 投稿日:2020-03-17T19:47:42+09:00
Rails6でActiveJobのQueueAdapterがTestAdapterに上書きされてしまい非同期で実行されてしまう
Rails6の不具合で
RAILS_ENV=test
の場合、Railsのconfig.active_job.queue_adapter
の設定に関わらずActiveJobが非同期で実行されてしまう不具合が発生しています。これは現在(2020/2/28)の6-0-stable
でも修正されていません。今回はrspec-rails & sidekiqを利用しているという前提で書きます。
原因
Rails側のバグです。active_job/railtie.rb を6-0-stableと5-2-stableで比較してみると、
active_job.set_configs initializerにコードが追加されています。https://github.com/rails/rails/blob/5-2-stable/activejob/lib/active_job/railtie.rb
https://github.com/rails/rails/blob/6-0-stable/activejob/lib/active_job/railtie.rbactive_job/lib/active_job/railtie.rbActiveSupport.on_load(:action_dispatch_integration_test) do include ActiveJob::TestHelper endここでincludeされているActiveJob::TestHelperが原因です。
ActiveJob::TestHelperのbefore_setupで
queue_adapter_for_test
にハードコードされているActiveJob::QueueAdapters::TestAdapter
というadapterに上書きされてしまっていることで発生していました。activejob/lib/active_job/test_helper.rbdef before_setup # :nodoc: test_adapter = queue_adapter_for_test queue_adapter_changed_jobs.each do |klass| klass.enable_test_adapter(test_adapter) end # ... # ... # ... def queue_adapter_for_test ActiveJob::QueueAdapters::TestAdapter.new end対策
別のissueにこんなコードで修正できるのでは?とありますが、issueに反応が無いので取り込まれる可能性は低いかもしれません。。。
https://github.com/rails/rails/pull/37685#issuecomment-559625920
Rails側の修正を待つという手もありますが、
spec_helper
に下記のコードを追加することで対応できます。spec/spec_helper.rbRSpec.configure do |config| config.before(:each) do (ActiveJob::Base.descendants << ActiveJob::Base).each(&:disable_test_adapter) end endこれでRSpec & Sidekiqの環境でもTestAdapterの上書きをキャンセルできます。
issue
- 投稿日:2020-03-17T19:23:45+09:00
Dockerを使った既存のRailsアプリの環境構築に苦労したので、メモを残してみた
1.はじめに
2020年3月からDockerの勉強を始め、基礎を終えた後、Railsの環境構築に挑戦してみようと思ったが、思いの外、上手くいかなかったので、ここにメモを残すことにしました。誰かの参考になれば幸いです。
2.教材
・入門 Docker
・Docker/Kubernetes 実践コンテナ開発入門(書籍)
・Docker Hubの公式イメージ3.開発環境
・Play with Docker
(事前にDockerHubのアカウントが必要です。)
・Ruby:2.5.3
・Ruby on rails:5.2.2
・MySQL4.手順
4-1 クローンを取得
まずは、GitHubからgit cloneでアプリをクローンしておいてください。
git clone 'クローンしたいアプリのURL(GitHub参照)'これで、作成済みのアプリをローカルディレクトリに取り込むことができました。
4-2 Dockerfileとdocker-compose.ymlの作成
Dockerfileとdocker-compose.ymlを以下の配置になるように作成してください。
(作成済みのアプリをSampleAppと名付けています。)SampleApp---|--app |--bin |--config |--db |--lib |--log |--public |--storage |--tmp |--vendor |--.gitignore |--.ruby-version |--Dockerfile (これを追加) |--Gemfile |--Gemfile.lock |--README.md |--Rakefile |--config.ru |--docker-compose.yml (これを追加) |--package.jsonまた、Dockerfileとdocker-compose.ymlの中身は以下のようになります。
DockerfileFROM ruby:2.5.3 RUN apt-get update -qq && apt-get install -y build-essential libpq-dev node.js RUN mkdir /myapp WORKDIR /myapp COPY Gemfile /myapp/Gemfile COPY Gemfile.lock /myapp/Gemfile.lock RUN bundle install COPY . /myappdocker-compose.ymlversion: '3' services: db: image: mysql environment: MYSQL_ROOT_PASSWORD: password MYSQL_DATABASE: root command: --default-authentication-plugin=mysql_native_password web: build: . command: bundle exec rails s -p 3000 -b '0.0.0.0' volumes: - .:/myapp ports: - "3000:3000" depends_on: - dbこれで、実行する準備は完了です。
4-3 実行
アプリのディレクトリ内で以下のコマンドを実行してください。
$ docker-compose build $ docker-compose up -d $ docker-compose run web rake db:create $ docker-compose run web rake db:migrate完了です。
5. 最後に
何か間違えているところがあれば、ご指摘ください。
6. 参考記事
既存のRailsアプリにDockerを導入する手順
railsの環境構築 その1
プログラム好き大学生のDocker+Ruby on rails5で環境構築とgitの設定(初心者向け)
- 投稿日:2020-03-17T16:58:04+09:00
Rails + GitHub の導入
概要
Ruby on Rails 作成したアプリケーションを GitHub に登録して管理するまでの流れになります。
目次
- Rails アプリケーションのローカルリポジトリを作成
- GitHub にリモートリポジトリを作成
- ローカルリポジトリとリモートリポジトリを結びつける
- ローカルリポジトリをリモートリポジトリに反映
1. Rails アプリケーションのローカルリポジトリを作成
ターミナルで rails new コマンドを実行し、ローカルレポジトリを作成します。
ターミナル$ rails _<railsのバージョン>_ new <アプリの名前> -d <データベースの種類> # (例) # $ rails _5.2.3_ new test-github -d mysql # "5.2.3"バージョンで、データベースに "mysql" を使用し、"test-github" という名前のアプリを作成する。2. GitHub にリモートリポジトリを作成
GitHub で「+」メニューから「 New repository 」をクリックします。
リモートレポジトリ名を入力し、「 Create repository 」ボタンをクリックしてリポジトリを作成します。
以下の様な画面になれば、リモートリポジトリの作成は完了です。
3. ローカルリポジトリとリモートリポジトリを結びつける
次にコマンドで操作します。
ターミナル$ cd ~/test-github $ git remote add origin <先程コピーしたURL> # (例) # git remote add origin https://github.com/username/test-github.gitコマンド説明git remote add # ローカルリポジトリにリモートリポジトリの情報を付与して、紐づけを行うためのコマンドです。 origin # リモートリポジトリの場所の別名です。他の名前をつけることも出来ますが、GitHubのリモートリポジトリに対してはoriginとすることが一般的です。以上で紐づけは完了です。以下のコマンドで確認しましょう。
ターミナル$ git remote originここで origin と出力されれば完了です。
4. ローカルリポジトリをリモートリポジトリに反映
3.で紐づけが完了したので、ローカルリポジトリの現状の情報を、リモートリポジトリに反映します。
以下のコマンドを実行します。ターミナル$ cd ~/test-github $ git add . # すべて(.)の修正ファイルをインデックスに追加 $ git commit -m "first_commit" # コミットメッセージを付与してコミット $ git push origin masterコマンド説明git add <記録するファイル名> # インデックスに追加して、変更修正記録の対象とすることができます。 git commit -m "<コミットメッセージ>" # インデックスに追加されている変更修正を、コミットするためのコマンドです。-mのオプションはコミットメッセージと呼ばれ、どのような変更を行ったのかメモを残せます。 git push # ローカルリポジトリでのコミットをリモートリポジトリ(origin)に反映させる操作ができます。最後にブラウザで確認してみましょう。先程のリモートリポジトリ作成後のページをリロードしてください。
上記のような表示なっていれば正しく反映できています。以上で Rails + GitHub の導入は完了です。
- 投稿日:2020-03-17T15:38:24+09:00
画像アップロードとリサイズ
Carrierwaveとminimagick
画像アップロードするにはCarrierwaveを使います。
画像ファイルをリサイズするにはminimagickを使います。
ターミナル$ brew install imagemagickGemfileの一番下に
〜省略〜 gem 'carrierwave' gem 'mini_magick'ターミナル
$ bundle installターミナル
$ rails g uploader image【例】モデル名をMessageとします
app/models/message.rbclass Message < ApplicationRecord 〜省略〜 mount_uploader :image, ImageUploader endapp/uploaders/image_uploader.rbclass ImageUploader < CarrierWave::Uploader::Base # Include RMagick or MiniMagick support: # include CarrierWave::RMagick include CarrierWave::MiniMagick # storage :fog # 〜省略〜 process resize_to_fit: [800, 800] # 〜省略〜 endまずは必要なgemを導入します。「carrierwave」と「minimagick」をGemfileに追記し、ターミナルからbundle installを実行覚ます。
次に、画像のアップローダーを作成します。ターミナルで、rails g uploader imageコマンドを実行すると、app/uploadersディレクトリ以下にimage_uploader.rbが作成されます。
次に、Messageモデルを編集しimage_uploaderをマウントする記述を行います。
最後に、image_uploader.rbを編集して、MiniMagick経由で画像のリサイズを行えるようにします。
「include CarrierWave::MiniMagick」のコメントアウトを外します。
その後、任意の箇所に「process resize_to_fit: [800, 800]」と追記します。
resize_to_fitは縦横比を維持したまま、縦横を800px以内にリサイズするという意味です。
- 投稿日:2020-03-17T15:11:00+09:00
一時フォルダ内だからといってファイルを閉じ忘れてはいけない
結論
一時フォルダを消してもそのファイルが完全に消えずハードディスクを圧迫して困ります、ちゃんと閉じましょう
紹介: 一時フォルダ
Rubyでは簡単に一時フォルダが作れてブロックが終わるとフォルダが消えてくれるので作業フォルダとして扱いやすいです
Dir.mktmpdir('test') do |dir| # ファイル作ったり開いたり end失敗: ファイルを開く(閉じない)
どうせ一時フォルダで消えるのだからと Open して使うだけで閉じるのを忘れていると....
Dir.mktmpdir('test') do |dir| # ファイル生成処理 f = File.open(path) # 作業 end問題: ファイルが消えない
tmp フォルダは空っぽなのにハードディスクがどんどん圧迫されていく...
そう Linux だとプロセスが残る限り完全に消えていないのです
Rails server や Delayed Job Woker の再起動などを行い問題の処理のあるプロセスごと一旦落とさない限り残り続けてしまいます$ lsof | grep delete bundle 23931 (略) /tmp/test20200317-23931-cayd6g/test.pdf (deleted)※)上記例では プロセス 23931 が掴んでいるため仮削除状態
対処: 閉じましょう
ファイルが開放されるので一時フォルダの削除とともに完全に削除されます
これを行っていればプロセスごと落とす必要はありませんDir.mktmpdir('test') do |dir| # ファイル生成処理 File.open(path) do # 作業 end end参考
- 投稿日:2020-03-17T14:55:01+09:00
エラーメッセージ
errorsメソッド
【例】app/views/groups/の中に_form.html.hamlファイルを作成したとします
app/views/groups/_form.html.haml= form_for group do |f| - if group.errors.any? .chat-group-form__errors %h2= "#{group.errors.full_messages.count}件のエラーが発生しました。" %ul - group.errors.full_messages.each do |message| %li= message 〜省略〜group.saveのように変数groupの保存をしようとした時に、失敗するとgroupにエラーメッセージが格納されます。
その変数に対してerrorメソッドを使用するとエラーメッセージの取得ができます。
any?メソッドによって、エラーメッセージの有無を判定しています。
full_messagesメソッドによってエラーメッセージ全件の内容を取得しています。
- 投稿日:2020-03-17T14:48:22+09:00
【第1章】Rails チュートリアル サーバー立ち上げまで
はじめに
当記事ではRailsチュートリアルの学習記録をまとめております。
Railsチュートリアルを進めている中でエラーに困っている初心者の方は
もしかしたらこの記事で何かヒントを得られるかもしれません。※注意※
プログラミング初学者が執筆した記事であるため、
当記事の内容に誤りがある可能性がございます。前提条件
Ruby on Railsチュートリアル 第4版(5.1)
使用機器:MacBook Air
ブラウザ:google chrome
開発環境:AWS cloud9
リモート:GitHubアプリケーションの作成
1. railsのインストール
まずは開発環境にrailsをインストール。
と、その前に以下をコマンドラインに入力し実行する。$ printf "install: --no-document \nupdate: --no-document\n" >> ~/.gemrcこのコマンドの目的はRubyドキュメントをインストールしないことだが、
今の段階ではコマンドの意味は知らなくても良いとのこと。
意味が気になる?
printf ○○○ >> ~/.gemrc
→ ○○○の内容を~/.gemrcに反映。
今回の場合、
「install: --no-document
update: --no-document
を/.gemrc
に反映させろ」
→「インストール時、アップデート時にドキュメントを除外しろ」
というコマンドであることがわかる。
※/n
は改行の役目を果たしている。
その後、railsをインストールするため以下のコマンドを実行。
$ gem install rails -v 5.1.6
gem install
◯◯バージョン
→指定のバージョンの◯◯というgemをインストール。
つまり、「rails」とはgemの一つであることがわかる。
そもそもgemってなんだっけ?
Rubyのパッケージ(ライブラリ)。便利な機能がパッケージされたもの。
種類は幅広くて、gemをインストールすることで簡単にユーザー認証機能を実装できたりする。
RubyGemsにgemがいっぱい入っているので、暇なときに見てみよう。
ジャスティンビーバーの曲くらいダウンロードされている人気者。
2.アプリケーションの作成
まず、environmentディレクトリに移動する。
$ cd ~/environment補足情報:コマンドラインでは現在自分がどの位置にいるかが$の左側で示されている。
ec2-user:~/environment $
下のコマンドを実行し、アプリケーションを作成。
rails _5.1.6_ new hello_appこれで大量のディレクトリ、ファイルが生成された。
Bundlerのインストール
Bundlerとは?
→gemの互換性やバージョン管理をしてくれるgem。Gemfileを指定の内容に変更する。
gemのバージョンを固定することで、チュートリアルを同じ挙動で進めることができる。
その後、Bundle installを実行。$ bundle install※カレントディレクトリがhello_appであることを確認してから実行しよう。
※上記のコマンドを実行して、「bundle updateを実行してください」というエラーメッセージが出たら、先にBundle updateを実行しよう。railsサーバーの実行
これまでの準備で、サーバーを起動する準備が整った。
以下のコマンドで、実際にサーバーを立ち上げよう。$ cd ~/environment/hello_app/ $ rails server※今までのターミナルではなく、新しいターミナルで実行しよう。
※サーバーを終了するときはCtrl + C。これによりブラウザで表示できるようになったので確認してみよう。
参考
Bundlerとは:https://pikawaka.com/rails/bundler
- 投稿日:2020-03-17T14:33:06+09:00
【解決】Address already in use - bind(2) for 0.0.0.0:3000 (Errno::EADDRINUSE)
サーバースタートしたらエラー
miyajimayuki@miyajimayuukinoMacBook-Pro web_tech % ruby test.rb [2020-03-17 14:25:54] INFO WEBrick 1.4.2 [2020-03-17 14:25:54] INFO ruby 2.6.3 (2019-04-16) [x86_64-darwin19] Traceback (most recent call last): 11: from test.rb:2:in `<main>' 10: from test.rb:2:in `new' 9: from /Users/miyajimayuki/.rbenv/versions/2.6.3/lib/ruby/2.6.0/webrick/httpserver.rb:47:in `initialize' 8: from /Users/miyajimayuki/.rbenv/versions/2.6.3/lib/ruby/2.6.0/webrick/server.rb:108:in `initialize' 7: from /Users/miyajimayuki/.rbenv/versions/2.6.3/lib/ruby/2.6.0/webrick/server.rb:127:in `listen' 6: from /Users/miyajimayuki/.rbenv/versions/2.6.3/lib/ruby/2.6.0/webrick/utils.rb:65:in `create_listeners' 5: from /Users/miyajimayuki/.rbenv/versions/2.6.3/lib/ruby/2.6.0/socket.rb:762:in `tcp_server_sockets' 4: from /Users/miyajimayuki/.rbenv/versions/2.6.3/lib/ruby/2.6.0/socket.rb:227:in `foreach' 3: from /Users/miyajimayuki/.rbenv/versions/2.6.3/lib/ruby/2.6.0/socket.rb:227:in `each' 2: from /Users/miyajimayuki/.rbenv/versions/2.6.3/lib/ruby/2.6.0/socket.rb:764:in `block in tcp_server_sockets' 1: from /Users/miyajimayuki/.rbenv/versions/2.6.3/lib/ruby/2.6.0/socket.rb:201:in `listen' /Users/miyajimayuki/.rbenv/versions/2.6.3/lib/ruby/2.6.0/socket.rb:201:in `bind': Address already in use - bind(2) for 0.0.0.0:3000 (Errno::EADDRINUSE)原因
- サーバーをcontrol + Zで切ったら次にサーバーを立ち上げるとエラーになるようです。
解決
いま動いているport: 3000のサーバーをターミナルに出力して
% lsof -i:3000 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME ruby 2054 miyajimayuki 10u IPv6 0xb15f9119d06b6d43 0t0 TCP *:hbci (LISTEN) ruby 2054 miyajimayuki 11u IPv4 0xb15f9119cf61f0cb 0t0 TCP *:hbci (LISTEN)下記コマンドでプロセスを切る
% kill -9 {PID} 履歴 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME ruby 2054 miyajimayuki 10u IPv6 0xb15f9119d06b6d43 0t0 TCP *:hbci (LISTEN) ruby 2054 miyajimayuki 11u IPv4 0xb15f9119cf61f0cb 0t0 TCP *:hbci (LISTEN) miyajimayuki@miyajimayuukinoMacBook-Pro web_tech % kill -9 2054 miyajimayuki@miyajimayuukinoMacBook-Pro web_tech % [1] + killed ruby test.rbプロセスが切れたので再度サーバーが起動できるようになりました!
miyajimayuki@miyajimayuukinoMacBook-Pro web_tech % ruby test.rb [2020-03-17 14:32:34] INFO WEBrick 1.4.2 [2020-03-17 14:32:34] INFO ruby 2.6.3 (2019-04-16) [x86_64-darwin19] [2020-03-17 14:32:34] INFO WEBrick::HTTPServer#start: pid=2126 port=3000以上です!
- 投稿日:2020-03-17T14:16:41+09:00
redirect_toとrenderの違い
redirect_toの場合
redirect_to=>ルーティング=>コントローラー=>ビュー
新たなリクエストがされたのと同じ動きになり、コントローラーを経由してビューが表示されます。renderの場合
render=>ビュー
そのままビューが表示されます。redirect_toとrenderの違い
いずれも実行するとビューが表示されます。
しかしこれによって、元のインスタンス変数の値が上書きされるかどうかが違います。
【例】例えば@teamという変数があるとして、@teamの変数にはエラーメッセージが代入されているため、これが上書きされないようrenderによってビューを表示させる必要があります。def create @team = Team.new(team_params) if @team.save redirect_to root_path, notice: 'チームを作成しました' else render :new end end
- 投稿日:2020-03-17T13:59:41+09:00
【Rails】devise gemありきで、ユーザー情報を更新する方法
今回こまったこと
devise gemをbundle installして、アカウントを登録。
作ったアカウントを編集する画面を作ったものの、内容が反映されない・・・どうすれば!?と、言う事でググったら解決できたのでまとめます。
事前準備
devise用のuserテーブルには、カラムを追加してます。
name
ユーザー名
text
プロフィールコメント
prof_image
プロフィール画像↓コントローラーにお決まりの一文
このif: :devise_controller?
は、どうやら、deviseコントローラーで処理をしているかどうか。を判断するヘルパーメソッドみたいです。
ので、before_actionに記述して、ApplicationControllerの処理の前に、判別しているっぽいです。↓protected配下にこれまたお決まりの一文。
devise
にもともと用意されていない「:name,:prof_image,:text」の3つのテーブルへ書き込みを許可するぜ。って書いてあげてます。
これについては、sing_upの処理で許可するよ。って書かれてます。※今回はここの理解が甘かった。編集したプロフィールが反映されない問題
プロフィール詳細画面を作成して、ここから編集画面へ遷移するような導線を用意しました。で、以下がプロフィール編集画面です。ここの「更新」ボタンを押しても反映されない・・・!なぜ?
↓プロフィール編集画面(つっこみどころ満載ですが、ゆるしてください。レイアウトも作成中です(汗))
なぜ?仮定
エラーは出ないし、きっとコントローラーに記載されている処理が何か足りていない。と仮定。
それならばと思い、コントローラーの記載を確認。むむむ・・・今の自分の知識じゃ訳がわからない・・・。
ということで、ぐぐる。
どうやら、「devise_parameter_sanitizerメソッド」の理解が足りていなかったようだ!少しでもいいから、devise_parameter_sanitizerメソッドのこと思い出してください
この一文は僕が昔大好きだったゲームの一文のパロです。
はい、どうでもいいです。ごめんなさい。調べていったら、「devise_parameter_sanitizerメソッド」の引数部分の指定不足が原因だと言う事がわかりました。
そもそもdevise_parameter_sanitizerメソッドとは
deviseではサインアップ時に既存で用意されているカラム
password
のみを受け取るようにストロングパラメーターで設定してあります。
なので、独自で追加したカラムへのアクセス許可をしてあげる必要があります。
そこで登場するのが、このdevise_parameter_sanitizer
メソッドです。この
devise_parameter_sanitizer
メソッドには、第一引数でどのアクションの時に許可する?が指定できるみたいです。
第一引数書く値 意味 :sign_in ログイン時 :sing_up 新規登録時 :account_update レコード更新時 原因と解決
つまるところ、現状の実装だと
ApplicationController
にはsing_upの処理が走ったタイミングでしか追加したカラムの書き込みを許可していないって事になりますね。
なので実装を修正。はい。これで無事更新ができるようになりました!!
おわり
初の個人アプリ開発もエラー→ググる→トライ→エラー→ググる・・・・・解決!が定着化してきました。
色々な記事を投稿してくださっている先輩方には感謝しかありません!
僕も先輩方と同じように後からエンジニアを目指す人たちの助け舟を出せるような人に育っていきたいです。あと、補足や認識齟齬があればどうぞご指摘いただけますと幸いです!
自分の知識を正しいものにしていきたいので、是非ともよろしくお願いいたします。ではでは、ありがとうございました!
- 投稿日:2020-03-17T13:57:56+09:00
フラッシュメッセージ
フラッシュメッセージとは
ユーザーが、「サインアップ」「ログイン」「ログアウト」を行った直後にメッセージを出すことです。
flashオブジェクト
deviseを使用すると、ログイン時などに表示させるメッセージが「flashオブジェクト」に自動で格納されます。
flashオブジェクト内には、複数のメッセージがハッシュのように「キー」「バリュー」形式で保存されています。
【例】ファイルを_notificationsとしますapp/views/layouts/__notifications.html.haml.notification - flash.each do |key, value| = content_tag :div, value, class: keyeach文を使うと、これらを1つずつ取り出すことができ、今回は「キー」を「CSS用のクラス名」に、「バリュー」を「表示するメッセージ本文」として使っています。
フラッシュメッセージの表示
【例】renderしてるとします
app/views/layouts/application.html.haml!!! %html %head (中身) %body = render 'layouts/flashs' = yieldこれだとまだ英文が出てきてします。
flash.scssを作成
【例】ファイルをcolors.scsとします
stylesheets/config/colors.scss$white: #fff; $side_blue_dark: #253141; $side_blue_light: #2f3e51; $light_blue: #38AEF0; $light_gray: #999; $black: #434a54; $alert_orange: #F35500;次に「通知用」のメッセージと「アラート用」メッセージを作成します。
【例】ファイルをflash.scssとしますstylesheets/modules/flash.scss.notification { .notice { background-color: $light_blue; color: $white; text-align: center; } .alert { background-color: $alert_orange; color: $white; text-align: center; } }次にapplication.scssを編集し、作成しファイルが読み込まれるようにします。
app/assets/stylesheets/application.scss@import "reset"; @import "config/colors"; (そのほかの@import) @import "modules/flash";colors.scssの読み込みの順番
Railsは上から順番に読み込むためcolors.scssは、reset.scssの直後で読み込むようにしましょう。
colors.scssには、他のscssで利用している色についての変数が定義されています。
そのため、色についての変数を利用するCSSの前に先に読み込めていないと、エラーになってしまいます。日本語化
「config/locales」フォルダに、「devise.ja.yml」と「ja.yml」という名前のファイルを新規作成します。
devise.ja.yml
ja.yml
それぞれ中身を丸ごとコピーして貼り付けます。
日本語化のための設定をします。
【例】config/application.rbmodule ChatSpace class Application < Rails::Application (中身) config.i18n.default_locale = :ja end endこれで日本語でフラッシュメッセージの表示がされます。
- 投稿日:2020-03-17T13:28:16+09:00
Rubyによるデザインパターン(2)
Rubyによるデザインパターン(2)
本記事は初級エンジニアがRubyを使用したデザインパターンをアウトプットしたものになります。また、デザインパターンは種類が多いため、何回かに分けて掲載していきたいと思います。今回はTemplateMethodパターンとFactoryMethodパターンをご紹介します。なお、こちら記事は次のサイトを参考にしております。
TECHSCORE
酒と涙とRubyとRailsとTemplateMethodパターン
TemplateMethod パターンは、テンプレートの機能を持つパターンです。親クラスで処理の枠組み(テンプレート)を定め、子クラスでその具体的内容を実装します。親クラスで抽象度の高いロジックを組み込み、子クラスで抽象度の低い詳細なロジックを組み込みことで、役割を分担することができます。
サンプルソース
・Report(抽象的なベースの親クラス): レポートを出力する
・HTMLReport(子クラス): HTMLフォーマットでレポートを出力
・PlaneTextReport(子クラス): PlanTextフォーマットでレポートを出力レポートの出力を行うReportクラスは次のとおり
(Reportクラスは4つのメソッドを持つ)class Report def initialize @title = "html report title" @text = ["report line 1", "report line 2", "report line 3"] end # レポートを出力する順番を規程 def output_report output_start output_body output_end end # レポートの先頭で出力 def output_start end # レポートの本文で出力 def output_body @text.each do |line| output_line(line) end end # output_bodyの内容 # 今回は個別クラスに規定するメソッドとする。規定されてなければエラーを返す def output_line(line) raise 'Called abstract method !!' end # レポートの末尾で出力 def output_end end endHTML形式でのレポート出力を行うHTMLReportは以下のとおり
(ReportクラスのメソッドでHTML出力する際に変化する3つのメソッドを持つ)# HTML形式でのレポート出力を行う class HTMLReport < Report # レポートの先頭を出力 def output_start puts "" end # output_bodyの内容 def output_line(line) puts "#{line}" end # レポートの末尾を出力 def output_end puts "" end end最後にPlaneText形式(*で囲う)での出力を行うPlaneTextReportクラスは以下のとおり
(ReportクラスのメソッドでPlaneText形式で出力する際に変化する2つのメソッドを持つ)# PlaneText形式(*****で囲う)でレポートを出力 class PlaneTextReport < Report # レポートの先頭で出力 def output_start puts "**** #{@title} ****" end # output_bodyの内容 def output_line(line) puts line end end以上のコードを実際に実行すると次のようになります。
html_report = HTMLReport.new html_report.output_report # # report line 1 # report line 2 # report line 3 # plane_text_report = PlaneTextReport.new plane_text_report.output_report #**** html report title **** #report line 1 #report line 2 #report line 3結果から抽象度の高いメソッドを持つReportクラスから、HTML形式とPlaneText形式でレポートを出力することができました。なお、オブジェクトを初期化するメソッドinitializeは既存のinitializeをオーバーライドして、自由に初期化処理を行うことができます。つまりinitializeは広義でのTempleteMethodパターンとなります。続いて、FactoryMethodパターンを説明します。
FactoryMethodパターン
FactoryMethodパターンはオブジェクトの生成方法に一工夫加えることで、より柔軟なオブジェクトを生成することを目的としています。FactoryMethodパターンではインスタンスの生成を子クラスに行わせることでより柔軟に生成するインスタンスを選択することができるようになります。
それではFactoryMethodをコードを使用して説明していきます。ここではデスクトップパソコンとパソコンを製造する工場を例にします。デスクトップパソコンを表すDesktopクラスは、電源を入れる(start)メソッドを持っており、パソコン工場を表すPersonalComputerFactoryクラスはコンストラクタの引数でパソコンの数を受け取り、またパソコンを出荷するメソッド「ship_out」を持っています。DesktopクラスとPersonalComputerFactoryクラスは次のとおり
# デスクトップ (Product) class Desktop def initialize(name) @name = name end def start puts "デスクトップ #{@name} は電源を入れました" end end # パソコン工場 (Creator) class PersonalComputerFactory def initialize(number_desktops) @desktops = [] number_desktops.times do |i| desktop = Desktop.new("デスクトップ #{i}") @desktops << desktop end end # パソコンを出荷する def ship_out @tmp = @desktops.dup @desktops = [] @tmp end end上のプログラムを実行
factory = PersonalComputerFactory.new(3) desktops = factory.ship_out desktops.each { |desktop| desktop.start } #=> デスクトップ 0 は電源を入れました #=> デスクトップ 1 は電源を入れました #=> デスクトップ 2 は電源を入れましたここで、新たにラップトップ(Laptop)モデルを追加してみます
(インタフェースはデスクトップとまったく同じもの)# ラップトップ (Product) class Laptop def initialize(name) @name = name end def start puts "ラップトップ #{@name} は電源を入れました" end end先ほど作ったPersonalComputerFactoryモデルをもう一度確認
# パソコン工場 (Creator) class PersonalComputerFactory def initialize(number_desktops) @desktops = [] number_desktops.times do |i| desktop = Desktop.new("デスクトップ #{i}") @desktops << desktop end end # パソコンを出荷する def ship_out tmp = @desktops.dup @desktops = [] tmp end endラップトップモデルを追加する場合、一点問題が発生します。それはPersnalComputerFactoryクラスにおいて、コンストラクタ(initialize)でデスクトップを作っている点です(desktop = Desktop.new("デスクトップ #{i}"))。そこで、PersonalComputerFactoryクラスのデスクトップを生成している部分を子クラス(DesktopFacotory)で実装し、再度、ラップトップを生成するLaptopFactoryクラスを作成してみましょう。
class PersonalComputerFactory def initialize(number_personal_computers) @computers = [] number_personal_computers.times do |i| computer = new_computer("パソコン #{i}") @computers << computer end end # パソコンを出荷する def ship_out @tmp = @computers.dup @computers = [] @tmp end end # DesktopFactory: デスクトップを生成する (ConcreteCreator) class DesktopFactory < PersonalComputerFactory def new_computer(name) Desktop.new(name) end end # LaptopFactory: ラップトップを生成する (ConcreteCreator) class LaptopFactory < PersonalComputerFactory def new_computer(name) Laptop.new(name) end end上記のPersonalComputerFactoryではnew_computer(パソコンの生成)で処理を抽象化することで、追加されたラップトップモデルに対応することができます。それでは実際にプログラムを実行し、結果を確認してみましょう。
factory = DesktopFactory.new(3) desktops = factory.ship_out desktops.each { |desktop| desktop.start } #=> デスクトップ パソコン 0 は電源を入れました #=> デスクトップ パソコン 1 は電源を入れました #=> デスクトップ パソコン 2 は電源を入れました factory = LaptopFactory.new(3) laptops = factory.ship_out laptops.each { |laptop| laptop.start } #=> ラップトップ パソコン 0 は電源を入れました #=> ラップトップ パソコン 1 は電源を入れました #=> ラップトップ パソコン 2 は電源を入れました結果のとおり、デスクトップ/ラップトップの作成及び各パソコンの電源を入れることができるようになりました。このようにクラスの選択を子クラスに任せることを「FactoryMethod」と呼びます。
なお、ファクトリメソッドは次の3つで構成されています。
・Creator: ConcreteFactoryの共通部分の処理を行う(PersonalComputerFactory)
・ConcreteCreator: 実際にオブジェクトの生成を行う(DesktopFactory, LaptopFactory)
・Product: ConcreteFactoryによって生成される側のオブジェクト(desktop、laptop)以上で今回の説明を終了します。
- 投稿日:2020-03-17T12:24:32+09:00
Rails6 のちょい足しな新機能を試す 124(eager loading bug fix編)
はじめに
Rails 6 に追加された新機能を試す第124段。 今回は、
eager loading bug fix
編です。
Rails 6.0.0 では、app
ディレクトリの下にファイルを置くとrails server
を実行した時に エラーになるというバグがありました。この事象は、Ubuntu などでは発生しますが、MacOS/X では発生しないようです。
Rails 6.0.1 以降では修正されています。
Ruby 2.6.5, Rails 6.0.2.1, 6.0.1, Rails 6.0.0 で確認しました。(6.0.1で修正が入ってます。)
$ rails --version Rails 6.0.1今回は、
rails new
して、app
ディレクトリの下にファイルを作って確認してみます。Rails プロジェクトを作る
Rails プロジェクトを新たに作成します。
$ rails new rails_sandbox $ cd rails_sandboxapp の下にファイルを作成する
touch
コマンドでapp の下にファイルを作成します。touch app/file.txt
Rails 6.0.1 では
Rails 6.0.1 では、
rails server
してもエラーになりません。Rails 6.0.0 では
Rails 6.0.0 では、エラーになります。
$ rails server ... 1: from /usr/local/bundle/gems/rb-inotify-0.10.1/lib/rb-inotify/notifier.rb:200:in `new' /usr/local/bundle/gems/rb-inotify-0.10.1/lib/rb-inotify/notifier.rb:200:in `initialize': Not a directory @ dir_initialize - /app/app/file.txt (Errno::ENOTDIR)試したソース
参考情報
- 投稿日:2020-03-17T11:57:35+09:00
@importと、requireって何が違うの?
@impirtとは
@importはscssが用意しているメソッドです。そのため、application.scssと拡張子を変更しないと使えません。また、application.scssからscssファイルをインポートするために使用しなけばなりません。
scssはscss専用のメソッドなので、requireとは異なります。
reqireとは
requireはRailsのアセットパイプラインの仕組みを使ってファイルをインポートすることを指します。
アセットパイプラインとは
アセットパイプラインとは、JavaScriptやCSSのアセットを最小化 (minify: スペースや改行を詰めるなど) または圧縮して連結するためのフレームワークです。アセットパイプラインでは、CoffeeScriptやSass、ERBなど他の言語で記述されたアセットを作成する機能を追加することもできます。 アセットパイプラインはアプリケーションのアセットを自動的に他のgemのアセットと結合できます。たとえば、jquery-railsにはRailsでAJAXを使えるようにするjquery.jsが含まれています。
アセットパイプラインはsprockets-rails gemによって実装され、デフォルトで有効になっています。アプリケーションの新規作成中にアセットパイプラインを無効にするには、--skip-sprocketsオプションを渡します。
引用 - rails ガイドつまりは、cssファイルやJavaScriptのファイルを1つにまとめ、圧縮することで処理速度を早くするための仕組み。sprocketsというgemがこの機能を担ってるってことです。
両者の違い
こう書いてみると、@importもrequireも何かをひっぱてきているような感覚は同じですが、importはscssの専用メソッドで、ファイルを読み込む記述、対してrequireは、cssやjsのファイルを1つにまとめて圧縮したファイルを読み込んでいるという違いがあることが分かりました。
- 投稿日:2020-03-17T11:14:22+09:00
プログラミング王に、、俺はなる!!!
前回までのあらすじ
謎の赤髪の男から「このMacBookPRO16インチ(30万ベリー)をお前に預ける。。いつかきっと返しにこい。。。絶対壊すなよ?」
とノートPCをもらったNSぱんだまん。約2ヶ月間progateを学習しクソ雑魚海王類なら一撃で倒せる力を身に着けた。ここからNSぱんだまんの冒険が今始まる!!世はまさに!!!!大プログラミング時代!!!!
テンテンテンテンテンデッテーン♪ありったけのー言語〜使いこなーし〜
探しもの〜探〜し〜に〜ゆーくーのーさー!HELLO WORLD!!!!!
というわけで今回は、、、環境構築!!!
に取り掛かっていきたい。そう思うわけですよ。でもね、初心者からしたら訳わかんないのよ。環境構築って何?って感じだよね。
まず環境構築とは。っての調べてみたんだけど。
環境構築・・・環境構築とは、特定の装置やソフトウェア、システムなどが動作するように、コンピュータや情報システムの状態を整えること。特に、コンピュータにソフトウェアを導入したり設定を調整することで、対象のソフトウェアが動作する環境を作り上げる作業を意味する場合が多い。(IT用語辞典 引用)って書いてあるのをそのままコピペして貼り付けて見たんだけどさ。正直意味分かんないよこれ。笑
とりあえず自分のPCにRubyやRailsをインストール
↓
自分のPCでRubyやRailsを動かせるようにするってことみたい。うーん。。それはなんとなくわかるよ?このままじゃわからないしprogateみたいな画面にもできないからそもそもコード書けないしさ。
というわけで。。。
すごく親切な方が「環境構築についてはこのサイトがいいですよー」
って教えてくれたのが。。。
Rails Girls ガイド https://railsgirls.jp/
Ruby on Rails チュートリアル https://railstutorial.jp/
です。るっっっっっRuby on Rails チュートリアル...笑
私はRailsチュートリアルという呪縛から永遠に逃れることはできないようです。。
・・・まあいい。
環境構築さえわかったらこんなサイトすぐ辞めてやるぜ!!!!
というわけで少し見てみます。どうやら環境構築についてはテキストエディタ(NSぱんだまんはATOM)とコマンドライン(NSぱんだまんはMACなのでターミナル)を使う環境とIDE(統合開発環境)2つに分けることができるらしい。
IDE。。。また意味分かんない単語でてきたな。
IDE(統合開発環境)とは
プログラミングをする際に必要なソフトウェア(テキストエディタ・コンパイラ・デバッガ・コードバージョン管理等)を統合して、1つの画面で操作できるようにしたもの。英語で「Integrated Development Environment」の略なるほどね〜つまり
パルスのファルシのルシがパージでコクーンってわけね!
14年前の記憶が蘇りました。笑(注:FF12のネタです)
プログラミングの勉強しててほんと思うんだけど一個の単語調べたときの説明にまた意味分かんない単語あってそれ調べたらまた意味分かんない単語にぶつかって結果的に萎えるってよくありますよね。笑とりあえずIDEをまとめると
プログラムを作るために必要なものが揃ってるすげー開発環境
ってことです。
ちなみにデバッガとは「デバッグ(テストなどによって発見された誤作動・不具合について、その原因やプログラム上での位置を探索・特定し、意図したとおり動作するように修正する作業)作業を支援するソフトウェア」のこと
コンパイラとは「プログラミング言語で書かれたソースコードを読み込んで解析し、コンピュータが直に実行可能な機械語や、それに相当する中間言語などで記述されたオブジェクトコードに変更する作業(コンパイル)を行うソフトウェア。」のことみたいです。
ちゅーわけで今回はIDEを使用した環境構築をやろうと決めました。
IDEはいっぱい種類があるみたい。
例えば
⇨Eclipse
⇨IntelliJ IDEA
⇨NetBeans
⇨Visual Studio Community
⇨Xcode
⇨Android Studio
とか。上記のやつは無料で使えるらしい。今回使うのはそれともまた違ってクラウド上での統合開発環境ってやつでこれはPC上に環境を設定しなくて済むので準備が簡単にできるんだって!ちなみにクラウドってのはソルジャークラスfirstで金髪のバスターソード扱う青年のことです。
うん。。興味ないね。。
...すいません。
AWSのCloud9っての使います。
詳しい設定方法はRuby on Rails チュートリアルに載ってますよ。さ~て!!!速攻でローカル開発環境構築するぞー!!!!!!!!!
〜6時間経過〜
やーできたー簡単だったなーcloud9の設定。6時間で簡単にローカル環境構築できちゃった♡。。。まじで疲れました。
簡単とか書いてあったのに激ムズじゃねーか。。。
とりあえず流れざっくりと書くと
AWSに登録。(住所とかクレジット番号とか個人情報を入力)
↓
ルートユーザーIDを取得
↓
cloud9を設定しようとするも弾かれる
cloud9「ちょっと君君ー。ルートユーザーじゃだめだよおお?。IAMでアカウント作ってから出直してこいや。」
↓
IAMにてアカウント作成。グループ作成。
IAMアカウントからAWSにログイン。
↓
ここからcloud9へ。
cloud9さん「おっやっときたね〜。(ここまで3時間ほど費やす)Railsに会いにきたんでしょ?でもRails今はいないんだよね。呼んできてくれる?」
↓
railsをインストール(具体的な流れはrailsチュートリアルに記載あり)
とはいうもののRailsがはぐれメタル並に出てこない。
↓
...3時間苦戦しやっとローカル環境完成。
長かった。。。最後泣くほど嬉しかったです。
悩めば悩んだ分だけ解決できた時の嬉しさってはんぱないよね。
とりあえずここからいろいろ作っていこうと思います。あとやっぱRailsチュートリアルやっといたほうがいいわ。。
なんだかんだこれないとなんもできなかったし。railsチュートリアルと実際に簡単なアプリ作成を同時進行みたいな感じで進めていきたいと思います。
今回はここまで!!!
- 投稿日:2020-03-17T11:14:22+09:00
プログラミング王に、、俺はなる!!!(環境構築編)
前回までのあらすじ
謎の赤髪の男から「このMacBookPRO16インチ(30万ベリー)をお前に預ける。。いつかきっと返しにこい。。。絶対壊すなよ?」
とノートPCをもらったNSぱんだまん。約2ヶ月間progateを学習しクソ雑魚海王類なら一撃で倒せる力を身に着けた。ここからNSぱんだまんの冒険が今始まる!!世はまさに!!!!大プログラミング時代!!!!
テンテンテンテンテンデッテーン♪ありったけのー言語〜使いこなーし〜
探しもの〜探〜し〜に〜ゆーくーのーさー!HELLO WORLD!!!!!
というわけで今回は、、、環境構築!!!
に取り掛かっていきたい。そう思うわけですよ。でもね、初心者からしたら訳わかんないのよ。環境構築って何?って感じだよね。
まず環境構築とは。っての調べてみたんだけど。
環境構築・・・環境構築とは、特定の装置やソフトウェア、システムなどが動作するように、コンピュータや情報システムの状態を整えること。特に、コンピュータにソフトウェアを導入したり設定を調整することで、対象のソフトウェアが動作する環境を作り上げる作業を意味する場合が多い。(IT用語辞典 引用)って書いてあるのをそのままコピペして貼り付けて見たんだけどさ。正直意味分かんないよこれ。笑
とりあえず自分のPCにRubyやRailsをインストール
↓
自分のPCでRubyやRailsを動かせるようにするってことみたい。うーん。。それはなんとなくわかるよ?このままじゃわからないしprogateみたいな画面にもできないからそもそもコード書けないしさ。
というわけで。。。
すごく親切な方が「環境構築についてはこのサイトがいいですよー」
って教えてくれたのが。。。
Rails Girls ガイド https://railsgirls.jp/
Ruby on Rails チュートリアル https://railstutorial.jp/
です。るっっっっっRuby on Rails チュートリアル...笑
私はRailsチュートリアルという呪縛から永遠に逃れることはできないようです。。
・・・まあいい。
環境構築さえわかったらこんなサイトすぐ辞めてやるぜ!!!!
というわけで少し見てみます。どうやら環境構築についてはテキストエディタ(NSぱんだまんはATOM)とコマンドライン(NSぱんだまんはMACなのでターミナル)を使う環境とIDE(統合開発環境)2つに分けることができるらしい。
IDE。。。また意味分かんない単語でてきたな。
IDE(統合開発環境)とは
プログラミングをする際に必要なソフトウェア(テキストエディタ・コンパイラ・デバッガ・コードバージョン管理等)を統合して、1つの画面で操作できるようにしたもの。英語で「Integrated Development Environment」の略なるほどね〜つまり
パルスのファルシのルシがパージでコクーンってわけね!
14年前の記憶が蘇りました。笑(注:FF12のネタです)
プログラミングの勉強しててほんと思うんだけど一個の単語調べたときの説明にまた意味分かんない単語あってそれ調べたらまた意味分かんない単語にぶつかって結果的に萎えるってよくありますよね。笑とりあえずIDEをまとめると
プログラムを作るために必要なものが揃ってるすげー開発環境
ってことです。
ちなみにデバッガとは「デバッグ(テストなどによって発見された誤作動・不具合について、その原因やプログラム上での位置を探索・特定し、意図したとおり動作するように修正する作業)作業を支援するソフトウェア」のこと
コンパイラとは「プログラミング言語で書かれたソースコードを読み込んで解析し、コンピュータが直に実行可能な機械語や、それに相当する中間言語などで記述されたオブジェクトコードに変更する作業(コンパイル)を行うソフトウェア。」のことみたいです。
ちゅーわけで今回はIDEを使用した環境構築をやろうと決めました。
IDEはいっぱい種類があるみたい。
例えば
⇨Eclipse
⇨IntelliJ IDEA
⇨NetBeans
⇨Visual Studio Community
⇨Xcode
⇨Android Studio
とか。上記のやつは無料で使えるらしい。今回使うのはそれともまた違ってクラウド上での統合開発環境ってやつでこれはPC上に環境を設定しなくて済むので準備が簡単にできるんだって!ちなみにクラウドってのはソルジャークラスfirstで金髪のバスターソード扱う青年のことです。
うん。。興味ないね。。
...すいません。
AWSのCloud9っての使います。
詳しい設定方法はRuby on Rails チュートリアルに載ってますよ。さ~て!!!速攻でローカル開発環境構築するぞー!!!!!!!!!
〜6時間経過〜
やーできたー簡単だったなーcloud9の設定。6時間で簡単にローカル環境構築できちゃった♡。。。まじで疲れました。
簡単とか書いてあったのに激ムズじゃねーか。。。
とりあえず流れざっくりと書くと
AWSに登録。(住所とかクレジット番号とか個人情報を入力)
↓
ルートユーザーIDを取得
↓
cloud9を設定しようとするも弾かれる
cloud9「ちょっと君君ー。ルートユーザーじゃだめだよおお?。IAMでアカウント作ってから出直してこいや。」
↓
IAMにてアカウント作成。グループ作成。
IAMアカウントからAWSにログイン。
↓
ここからcloud9へ。
cloud9さん「おっやっときたね〜。(ここまで3時間ほど費やす)Railsに会いにきたんでしょ?でもRails今はいないんだよね。呼んできてくれる?」
↓
railsをインストール(具体的な流れはrailsチュートリアルに記載あり)
とはいうもののRailsがはぐれメタル並に出てこない。
↓
...3時間苦戦しやっとローカル環境完成。
長かった。。。最後泣くほど嬉しかったです。
悩めば悩んだ分だけ解決できた時の嬉しさってはんぱないよね。
とりあえずここからいろいろ作っていこうと思います。あとやっぱRailsチュートリアルやっといたほうがいいわ。。
なんだかんだこれないとなんもできなかったし。railsチュートリアルと実際に簡単なアプリ作成を同時進行みたいな感じで進めていきたいと思います。
今回はここまで!!!
- 投稿日:2020-03-17T11:14:22+09:00
プログラミング王に、、俺はなる!!!(Railsチュートリアル1章)
前回までのあらすじ
謎の赤髪の男から「このMacBookPRO16インチ(30万ベリー)をお前に預ける。。いつかきっと返しにこい。。。絶対壊すなよ?」
とノートPCをもらったNSぱんだまん。約2ヶ月間progateを学習しクソ雑魚海王類なら一撃で倒せる力を身に着けた。ここからNSぱんだまんの冒険が今始まる!!世はまさに!!!!大プログラミング時代!!!!
テンテンテンテンテンデッテーン♪ありったけのー言語〜使いこなーし〜
探しもの〜探〜し〜に〜ゆーくーのーさー!HELLO WORLD!!!!!
というわけで今回は、、、環境構築!!!
に取り掛かっていきたい。そう思うわけですよ。でもね、初心者からしたら訳わかんないのよ。環境構築って何?って感じだよね。
まず環境構築とは。っての調べてみたんだけど。
環境構築・・・環境構築とは、特定の装置やソフトウェア、システムなどが動作するように、コンピュータや情報システムの状態を整えること。特に、コンピュータにソフトウェアを導入したり設定を調整することで、対象のソフトウェアが動作する環境を作り上げる作業を意味する場合が多い。(IT用語辞典 引用)って書いてあるのをそのままコピペして貼り付けて見たんだけどさ。正直意味分かんないよこれ。笑
とりあえず自分のPCにRubyやRailsをインストール
↓
自分のPCでRubyやRailsを動かせるようにするってことみたい。うーん。。それはなんとなくわかるよ?このままじゃわからないしprogateみたいな画面にもできないからそもそもコード書けないしさ。
というわけで。。。
すごく親切な方が「環境構築についてはこのサイトがいいですよー」
って教えてくれたのが。。。
Rails Girls ガイド https://railsgirls.jp/
Ruby on Rails チュートリアル https://railstutorial.jp/
です。るっっっっっRuby on Rails チュートリアル...笑
私はRailsチュートリアルという呪縛から永遠に逃れることはできないようです。。
・・・まあいい。
環境構築さえわかったらこんなサイトすぐ辞めてやるぜ!!!!
というわけで少し見てみます。どうやら環境構築についてはテキストエディタ(NSぱんだまんはATOM)とコマンドライン(NSぱんだまんはMACなのでターミナル)を使う環境とIDE(統合開発環境)2つに分けることができるらしい。
IDE。。。また意味分かんない単語でてきたな。
IDE(統合開発環境)とは
プログラミングをする際に必要なソフトウェア(テキストエディタ・コンパイラ・デバッガ・コードバージョン管理等)を統合して、1つの画面で操作できるようにしたもの。英語で「Integrated Development Environment」の略なるほどね〜つまり
パルスのファルシのルシがパージでコクーンってわけね!
14年前の記憶が蘇りました。笑(注:FF12のネタです)
プログラミングの勉強しててほんと思うんだけど一個の単語調べたときの説明にまた意味分かんない単語あってそれ調べたらまた意味分かんない単語にぶつかって結果的に萎えるってよくありますよね。笑とりあえずIDEをまとめると
プログラムを作るために必要なものが揃ってるすげー開発環境
ってことです。
ちなみにデバッガとは「デバッグ(テストなどによって発見された誤作動・不具合について、その原因やプログラム上での位置を探索・特定し、意図したとおり動作するように修正する作業)作業を支援するソフトウェア」のこと
コンパイラとは「プログラミング言語で書かれたソースコードを読み込んで解析し、コンピュータが直に実行可能な機械語や、それに相当する中間言語などで記述されたオブジェクトコードに変更する作業(コンパイル)を行うソフトウェア。」のことみたいです。
ちゅーわけで今回はIDEを使用した環境構築をやろうと決めました。
IDEはいっぱい種類があるみたい。
例えば
⇨Eclipse
⇨IntelliJ IDEA
⇨NetBeans
⇨Visual Studio Community
⇨Xcode
⇨Android Studio
とか。上記のやつは無料で使えるらしい。今回使うのはそれともまた違ってクラウド上での統合開発環境ってやつでこれはPC上に環境を設定しなくて済むので準備が簡単にできるんだって!ちなみにクラウドってのはソルジャークラスfirstで金髪のバスターソード扱う青年のことです。
うん。。興味ないね。。
...すいません。
AWSのCloud9っての使います。
詳しい設定方法はRuby on Rails チュートリアルに載ってますよ。さ~て!!!速攻でローカル開発環境構築するぞー!!!!!!!!!
〜6時間経過〜
やーできたー簡単だったなーcloud9の設定。6時間で簡単にローカル環境構築できちゃった♡。。。まじで疲れました。
簡単とか書いてあったのに激ムズじゃねーか。。。
とりあえず流れざっくりと書くと
AWSに登録。(住所とかクレジット番号とか個人情報を入力)
↓
ルートユーザーIDを取得
↓
cloud9を設定しようとするも弾かれる
cloud9「ちょっと君君ー。ルートユーザーじゃだめだよおお?。IAMでアカウント作ってから出直してこいや。」
↓
IAMにてアカウント作成。グループ作成。
IAMアカウントからAWSにログイン。
↓
ここからcloud9へ。
cloud9さん「おっやっときたね〜。(ここまで3時間ほど費やす)Railsに会いにきたんでしょ?でもRails今はいないんだよね。呼んできてくれる?」
↓
railsをインストール(具体的な流れはrailsチュートリアルに記載あり)
とはいうもののRailsがはぐれメタル並に出てこない。
↓
...3時間苦戦しやっとローカル環境完成。
長かった。。。最後泣くほど嬉しかったです。
悩めば悩んだ分だけ解決できた時の嬉しさってはんぱないよね。
とりあえずここからいろいろ作っていこうと思います。あとやっぱRailsチュートリアルやっといたほうがいいわ。。
なんだかんだこれないとなんもできなかったし。railsチュートリアルと実際に簡単なアプリ作成を同時進行みたいな感じで進めていきたいと思います。
今回はここまで!!!
- 投稿日:2020-03-17T10:57:06+09:00
migrationファイルのnull: falseって?
migrationファイルのnull: falseって?
→指定したカラムが(データベースに)カラの状態で保存されることを防ぐ
rbclass CreateNotifications < ActiveRecord::Migration[5.2] def change create_table :notifications do |t| t.integer :visitor_id, null: false t.integer :visited_id, null: false t.string :action, default: '', null: false t.boolean :checked, default: false, null: false t.timestamps end add_index :notifications, :visitor_id add_index :notifications, :visited_id end endモデルに記載するvalidates :content, presence: trueと何が違うの?
似たバリデーションとして、presence: trueがあります。
これは、Railsの方でカラの情報を保存させないようにするためのものです。
データベース側ではSQLで保存することができてしまうのですね。
どちらを記載すれば良いのか?
どちらも記載しておくと安全ですね。
migrationファイルでは、データベースに対する設定なのに対して、
modelファイルでは、Rails側の設定。
結論:目的の場所が異なるので両方設定しておくことが良いですね。
- 投稿日:2020-03-17T10:31:40+09:00
railsで学ぶサーバーサイド(素人が浅い知識で書かせていただきました)
routingとcontrollerとview
rails newコマンドでアプリを作成するとroutingとcontrollerとviewが出来る。これらを使ってURLでデータを扱った処理ができる。
routingでやっている事
任意のURLに対してどのcontrollerのどの関数に飛ばすかを決める。controllerでやっている事
controllerの中には複数の関数名があり、routingからの指示を受けてその関数名を持つHTMLファイル(view)に飛ばす。またviewの中で使う変数を定義したりする。viewでやっている事
ここはHTMLファイルでブラウザでなにを見せるかを書いている。HTMLだけでは変数や構文を扱えないので、rubyやphpを組み込んでいる。主なコマンド
rails new アプリケーション名:アプリ作成
rails controller コントローラー名 view名: コントローラーとビュー作成それぞれについて認知しておきたいこと
rootingでの注意
railsでは、ルーティングの中で決めたpathを文字として扱う事ができる
例 /help→help_path他にも省略したり、特徴的な書き方をすることもある
例 @user→user_url(@user)→/user/:idまたroutingで書かれる移行の指示を一括で提供することができる。
config/routes.rbRails.application.routes.draw do root 'static_pages#home' . . . resources :users endこれはuserに関して、viewつなげるroot情報が網羅的に入っている。詳しくはRuby on Rails チュートリアル
controllerでの注意
・railsではcontrollerから別の場所に飛ばせる変数は頭に@がついた変数だけ。
・またUsersコントローラーのshowアクションのrootingはusers/:idとして定義されている。そのためshowアクションでURLにあるidを取り出して処理をする。app/controllers/users_controller.rbclass UsersController < ApplicationController def show @user = User.find(params[:id]) #rootingにあるidをprramsで取り出して使用して、userを探している。 end・form_tagやform_forで送られてきた値を取得するときは、params[送られてきた変数]をする。送られてきた変数の中身がからの時はparams[送られてきた変数]は空として扱う。
app/controllers/users_controller.rbclass UsersController < ApplicationController . . . def create @user = User.new(params[:user]) #form入力内容を示す:userを取り出している。 #厳密にはこれではダメ。ストロングパラメーターにしないといけない。 end end・controllerのアクション内でリダイレクトを指示することがある。(アクション名のつくHTMLファイルに飛ばずに、別のrootingに飛ばしてしまうこと)
viewでの注意
お作法としてapplication.htmlには統一レイアウトを置き
yeildという場所を書き、そこに全てのviewの内容が反映される。app/views/layouts/application.html.erb<html> <head> <title><%= full_title(yield(:title)) %></title> <%= csrf_meta_tags %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> <%= render 'layouts/shim' %> </head> <body> <%= render 'layouts/header' %> <div class="container"> <%= yield %> <%= render 'layouts/footer' %> </div> </body> </html>同様に全てのviewは、別のviewファイルから読みだして自身のviewに反映させてもいい
<%= render '反映させたいviewの場所' %>これをパーシャルを追加するという。
データベースの取り扱い
①まずデータベースを変更するためのマイグレーションファイルを作る。
rails g model モデル名 列名:種類モデル名は何用のデータなのかということ、単数形で書くこと。
例 User
列(カラム)はモデルの何のデータかを示す。
例 name
種類はカラムのデータをどんな種類で保存するか
例 string つまり文字列このコマンドで何が作成されるのか
・モデルのファイルができる。
そこでどんなデータなら保存するなどの制限を記述したりする。・モデル名(複数形)という名前のマイグレーションファイルができる。
dbを変更する命令が書かれている。
こいつをmigrateすることでdbに行列を作れるようになる。②rails db : migrate
マイグレーションファイルに書いてある指示を実行して行列(データ)をdbに作成できるなぜマイグレーションファイルがあるか。
ファイルならgitで管理できるから!データベースは人それぞれ違うので、管理できないから。
モデルファイルでは何をするのか
どんなデータなら保存するなどの制限を記述。
例 存在するか、文字数が多すぎないか、フォーマットがあっているか?
またモデルファイルの中で関数を定義して、データであるインスタンスの関数としてcontrollerで使用できる。app/models/user.rbclass User < ApplicationRecord validates :name, presence: true, length: { maximum: 50 } validates :email, presence: true, length: { maximum: 255 } def adult_check #Userモデルの関数 if self.age >= 20 return "お酒が飲めます" end end endデータ保存のイメージ
modelというクラスがありカラムという変数をたくさん持っている。
↓
そこからインスタンスを作り、そのインスタンスにあった値を各カラムに代入して保存する。モデルAにモデルBを従属させたい時(二つのモデルを繋げて)
以下のようなコードを書くと
モデルAインスタンスはたくさんのモデルBインスタンスを持つことができる。app/models/micropost.rbclass Micropost < ApplicationRecord belongs_to :user endapp/models/user.rbclass User < ApplicationRecord has_many :microposts endこの後に以下のように
A.Bの複数形.Bの関数or変数を使用することができる。def setup @user = users(:Tsuyoshi) @micropost = @user.microposts.build(content: "Hello") #これでTsuyoshiはHelloという投稿をする endログインはどうやる?
ログイン画面で入力されたメアドとパスワードを持つデータがあるか探す。
↓
あればログインできるようにする。
そのためにsession変数の中にuser.idの値を入れる!
session変数の値はブラウザ内でなら不変で存在できるので、画面遷移しても存在できるため、ログインしているユーザーのためのページが閲覧できる。ログアウトする時はsession変数の値を空にするか、ブラウザを閉じる。ログインに関する補足
*sessionとcookieの違いはsessionはブラウザを閉じれば値が破棄されるがcookieは破棄されない。
*ログインやログアウトを命ずる関数(あるいはその中で使うcookiesをいじる関数)はappのコントローラーhelperの中で定義したりする
*ログインしていないユーザーがいじってはいけないページを設定したければ、beforeactionで、権限を確認して、アクションまで到達させるかを見極める。
注意: beforeactionはcontroller内でのみ発動できる
全てのcontrollerのアクションで発動させたければ、controllerの親玉であるapplicationcontrollerで発動してやる*ログインテストなどでテスト環境のデータベースにデータを置きたい時はfixturesに記述する
*ログインする前にログインしないといじれないページにアクセスした時
ログインした後に直接ログイン前にアクセスしたページに飛ばす工夫
↓
アクセス失敗時に変数にそのurlを代入
↓
ログインしたらそこに飛ばせるようにする
↓
飛べば、変数の値を空にするその他、補足
ストロングパラメーター
セキュリティーのためにUserのインスタンスに発生させることが多い。インスタンス作成時にどんな引数も受けとってしまうことを防ぐ。これを行わないと、管理者権限があるかないかを示す変数の値を引数として渡し変更されてしまうので、どんなインスタンスでも管理者権限を持てるようになってしまう。
app/controllers/users_controller.rb@user = User.new(params[:user]) #form入力内容を示す:userを取り出している。↓
app/controllers/users_controller.rbclass UsersController < ApplicationController . . . def create @user = User.new(user_params) end private #外部アクセスを制限 #user_paramsとは:userの中身をpramsで紐解いているが、入力が許されているのはname,email,password,password_confirmationだけという意味 def user_params params.require(:user).permit(:name, :email, :password, :password_confirmation) end end
- 投稿日:2020-03-17T10:31:40+09:00
railsで学ぶサーバーサイド(rails チュートリアルで学んだことをまとめてみました)
この記事の説明
この記事ではrails チュートリアルで学んだことを私なりにまとめてみました。
理解の浅い部分がありますので、間違いがある場合はどうぞご教授ください。routingとcontrollerとview
rails newコマンドでアプリを作成するとroutingとcontrollerとviewが出来る。これらを使ってURLでデータを扱った処理ができる。
routingでやっている事
任意のURLに対してどのcontrollerのどの関数に飛ばすかを決める。controllerでやっている事
controllerの中には複数の関数名があり、routingからの指示を受けてその関数名を持つHTMLファイル(view)に飛ばす。またviewの中で使う変数を定義したりする。viewでやっている事
ここはHTMLファイルでブラウザでなにを見せるかを書いている。HTMLだけでは変数や構文を扱えないので、rubyやphpを組み込んでいる。主なコマンド
rails new アプリケーション名:アプリ作成
rails controller コントローラー名 view名: コントローラーとビュー作成rootingでの注意
railsでは、ルーティングの中で決めたpathを文字として扱う事ができる
例 /help→help_path他にも省略したり、特徴的な書き方をすることもある
例 @user→user_url(@user)→/user/:idまたroutingで書かれる移行の指示を一括で提供することができる。
config/routes.rbRails.application.routes.draw do root 'static_pages#home' . . . resources :users endこれはuserに関して、viewつなげるroot情報が網羅的に入っている。詳しくはRuby on Rails チュートリアル
controllerでの注意
・railsではcontrollerから別の場所に飛ばせる変数は頭に@がついた変数だけ。
・またUsersコントローラーのshowアクションのrootingはusers/:idとして定義されている。そのためshowアクションでURLにあるidを取り出して処理をする。app/controllers/users_controller.rbclass UsersController < ApplicationController def show @user = User.find(params[:id]) #rootingにあるidをprramsで取り出して使用して、userを探している。 end・form_tagやform_forで送られてきた値を取得するときは、params[送られてきた変数]をする。送られてきた変数の中身がからの時はparams[送られてきた変数]は空として扱う。
app/controllers/users_controller.rbclass UsersController < ApplicationController . . . def create @user = User.new(params[:user]) #form入力内容を示す:userを取り出している。 #厳密にはこれではダメ。ストロングパラメーターにしないといけない。 end end・controllerのアクション内でリダイレクトを指示することがある。(アクション名のつくHTMLファイルに飛ばずに、別のrootingに飛ばしてしまうこと)
viewでの注意
お作法としてapplication.htmlには統一レイアウトを置き
yeildという場所を書き、そこに全てのviewの内容が反映される。app/views/layouts/application.html.erb<html> <head> <title><%= full_title(yield(:title)) %></title> <%= csrf_meta_tags %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> <%= render 'layouts/shim' %> </head> <body> <%= render 'layouts/header' %> <div class="container"> <%= yield %> <%= render 'layouts/footer' %> </div> </body> </html>同様に全てのviewは、別のviewファイルから読みだして自身のviewに反映させてもいい
<%= render '反映させたいviewの場所' %>これをパーシャルを追加するという。
データベースの取り扱い
①まずデータベースを変更するためのマイグレーションファイルを作る。
rails g model モデル名 列名:種類モデル名は何用のデータなのかということ、単数形で書くこと。
例 User
列(カラム)はモデルの何のデータかを示す。
例 name
種類はカラムのデータをどんな種類で保存するか
例 string つまり文字列このコマンドで何が作成されるのか
・モデルのファイルができる。
そこでどんなデータなら保存するなどの制限を記述したりする。・モデル名(複数形)という名前のマイグレーションファイルができる。
dbを変更する命令が書かれている。
こいつをmigrateすることでdbに行列を作れるようになる。②rails db : migrate
マイグレーションファイルに書いてある指示を実行して行列(データ)をdbに作成できるなぜマイグレーションファイルがあるか。
ファイルならgitで管理できるから!データベースは人それぞれ違うので、管理できないから。
モデルファイルでは何をするのか
どんなデータなら保存するなどの制限を記述。
例 存在するか、文字数が多すぎないか、フォーマットがあっているか?
またモデルファイルの中で関数を定義して、データであるインスタンスの関数としてcontrollerで使用できる。app/models/user.rbclass User < ApplicationRecord validates :name, presence: true, length: { maximum: 50 } validates :email, presence: true, length: { maximum: 255 } def adult_check #Userモデルの関数 if self.age >= 20 return "お酒が飲めます" end end endデータ保存のイメージ
modelというクラスがありカラムという変数をたくさん持っている。
↓
そこからインスタンスを作り、そのインスタンスにあった値を各カラムに代入して保存する。カラムにインデックスをつけると
rails g migrationで任意のカラムにインデックスを加えるマイグレーションファイルを作る(emailカラムに使われる事が多い)
↓
rails db migrateでデータに反映
emailカラムにインデックスが付く→これによって検索が速くなる(インデックスのおかげでアルファベット順に並べ替えたりできるから)モデルAにモデルBを従属させたい時(Userがたくさん投稿できるようにしたい)
以下のようなコードを書くと
モデルAインスタンスはたくさんのモデルBインスタンスを持つことができる。app/models/micropost.rbclass Micropost < ApplicationRecord belongs_to :user endapp/models/user.rbclass User < ApplicationRecord has_many :microposts, dependent: :destroy #dependent: :destroyをつけると主のインスタンスが消されるとそれに従属した投稿も消されるのでuserのインスタンスが消えるとそこに従属していたmicropostも消える。 endこの後に以下のように
A.Bの複数形.Bの関数or変数を使用することができる。def setup @user = users(:Tsuyoshi) @micropost = @user.microposts.build(content: "Hello") #これでTsuyoshiはHelloという投稿をする endログインはどうやる?
ログイン画面で入力されたメアドとパスワードを持つデータがあるか探す。
↓
あればログインできるようにする。
そのためにsession変数の中にuser.idの値を入れる!
session変数の値はブラウザ内でなら不変で存在できるので、画面遷移しても存在できるため、ログインしているユーザーのためのページが閲覧できる。ログアウトする時はsession変数の値を空にするか、ブラウザを閉じる。cookiesとsession
sessionとcookieの違いはsessionはブラウザを閉じれば値が破棄されるがcookieは破棄されないこと。
cookies保存法
記憶トークンを作る
トークンとはPCがランダムに作ったパスワードみたいなもの(普通のパスワードは人間が考えて作るけど)
↓
記憶トークンを暗号化する(記憶トークンのハッシュ値をデータベースに保存するってこと)
↓
それをデータベースに保存する
↓
ブラウザのcookies(これはテキストファイル)の中に
signedで暗号化したユーザーIDと
記憶トークンのハッシュ値を有効期限付きで保存する再度ブラウザを開いた時に
cookiesに保存した暗号化したIDの暗号化を解く
↓
解いたIDであるユーザーをdbから探し、そこに保存されている記憶トークンのハッシュ値とcookiesが所有している
記憶トークンのハッシュ値が一致していればそのユーザーを変数userとして定義する
↓
ログインを許可する
ログイン処理の中には
session(:user_id) = user_idがあるので
sessionに値が入り、画面遷移してもログインしているアカウント用のページを返すようにするcookies導入した後にログアウトすると適切にログアウトする方法
cookiesの中身を空にする
sessionの中身を空にする
変数current userをnilにするログインに関する補足
*ログインやログアウトを命ずる関数(あるいはその中で使うcookiesをいじる関数)はappのコントローラーhelperの中で定義したりする
*ログインしていないユーザーがいじってはいけないページを設定したければ、beforeactionで、権限を確認して、アクションまで到達させるかを見極める。
注意: beforeactionはcontroller内でのみ発動できる。before_action :logged_in_user, only: [:edit, :update] #edit,updateアクション実行の前にlogged_in_userを発動。 . . . private # ログインされているかを確認 def logged_in_user unless logged_in? flash[:danger] = "Please log in." redirect_to login_url end end end全てのcontrollerのアクションで発動させたければ、controllerの親玉であるapplicationcontrollerでbefore_actionを発動してやる
*ログインテストなどでテスト環境のデータベースにデータを置きたい時はfixturesに記述する。
詳しくはRuby on Rails チュートリアル*ログインする前にログインしないといじれないページにアクセスした時
ログインした後に直接ログイン前にアクセスしたページに飛ばす工夫
↓
アクセス失敗時に変数にそのurlを代入
↓
ログインしたらそこに飛ばせるようにする
↓
飛べば、変数の値を空にするアカウントの有効化(新規登録などで行う)
まずUsersのtableデータに以下のカラムを追加する。
*有効化しているかいないか(初期状態は無効にしておく)
*有効化トークン暗号化版
*いつ有効化されたか↓
行のモデルファイルにbefore関数を使って、
ユーザのインスタンスが作られる前に、
有効化トークンをpcに作らせて暗号化し、それをユーザーのdbに保存する
↓
ユーザーにメールを送信する(appの中にあるmailerとそれに対応するアクションが送信をしてくれる。
rails g mailer メイラー名 アクション名で作れる)
↓
メールの中にはリンクがあり、そのリンクにはあらかじめ引数としてユーザーのメアド、有効化トークンが組み込まれている
↓
つまりリンクを押すだけでappにメアドと有効化トークンを送る、そしてdbに保存された有効化トークンと同じか比べる
↓
同じならば、有効化にしてログインさせる(新規登録完了)次回からのログインでは
emailとpasswordが認証され、有効化がtrueならばログイン状態にするメールの送り方
user_mailerの中で、誰にを引数に取り、誰々にメールを送る関数を作る
↓
ユーザーの行モデルの中で
user_mailerで定義したメール送信関数を使って
インスタンスユーザーが自身のメールアドレスにメールを送るという関数を作る
↓
その関数を必要に応じてコントローラーで使うrails g mailer メイラー名 アクション名 で何ができるのか
名前のついたメイラー(controller みたいなもの)
→別のコントローラーから指示があれば対応したメールを送る
この中にアクションがある
役割は上に書いてある通りアクション名のhtmlファイルとアクション名のtextファイル
→メールの内容が入っている。メイラーで定義された変数を読み出す上のアクション名のコントローラー
→メールアドレスのリンクが押された処理をするためのコントローラーtestの中にメイラー名のpreviewファイル
→中にアクション名の関数とそれに対応したリンクがある
→関数の中でユーザーをつくりメールを送信する
→対応したリンクにつなぐとメールが見れる
テストのために行うpreviewの使い方
まずブラウザでメール内容を見るために
config/environments/developmentでメールを送るための設定をする
↓
previewの中の関数で
メールで使う変数やメール送信の命令を記述する
↓
対応したurlにつなぐとみれるまたpreviewの実行をテストをする時は
テストのための設定もconfig/environments/testでやってやるtwitterの独特の構造
ここについては未完成
フォローとフォロワーの関係構築
フォロしているとフォロされているを有効にするには
そのユーザーとの関係性を保存するdbを作る。
このdbはuserの行モデルに従属する形にする。またこの時のhas_many: 〜 , class_name:子行モデル, foreign_key:A
にする事で
user.〜.何かという命令関数を作ることができる。
↓
引数を使ってAにキーを保存するように、フォローしたされたの関係を保存できたり。ユーザーがフォローしている人、フォロワーを把握するためにする従属
ユーザーモデルの中でhas_many A through B source C
↓
前提としてユーザーがBを従えている時
BはCを複数持つことができる。
そしてその複数形の事をuser.Aとする!フォローしている人の投稿だけ見るようにするには
has_many A through B source C
でできたfollowing(自分がフォローしている人の複数形)をmicropostsに保存して見せるようにするその他、補足
ストロングパラメーター
セキュリティーのためにUserのインスタンスに発生させることが多い。インスタンス作成時にどんな引数も受けとってしまうことを防ぐ。これを行わないと、管理者権限があるかないかを示す変数の値を引数として渡し変更されてしまうので、どんなインスタンスでも管理者権限を持てるようになってしまう。
app/controllers/users_controller.rb@user = User.new(params[:user]) #form入力内容を示す:userを取り出している。↓
app/controllers/users_controller.rbclass UsersController < ApplicationController . . . def create @user = User.new(user_params) end private #外部アクセスを制限 #user_paramsとは:userの中身をpramsで紐解いているが、入力が許されているのはname,email,password,password_confirmationだけという意味 def user_params params.require(:user).permit(:name, :email, :password, :password_confirmation) end endクエリとエスケープ
どちらもurlに関する事
クエリとは
urlの最後に?条件と書く事で
?以下の条件に正しく対応していればurlに繋ぐエスケープとは
クエリの条件で使われることが多く
urlには書き込めない文字を別の文字列で表現することex @ → %40
パスワード再設定のやり方
ユーザーがpassword再設定をリクエスト
↓
入力されたメールアドレスからユーザーを見つける
↓
再設定用トークンとそれに対応する暗号化された再設定用トークンを作る
↓
暗号化された再設定用トークンはdbに保存して
メルアドにメルアドと再設定トークンが組み込まれたリンクを送信する
↓
クリックされれば
リンクに組み込んだ再設定トークンとdbに保存した再設定トークンが同じか確認する
↓
okならばパスワード変更画面に誘導
↓
パスワード変更が完了すれば
ログインし、dbに保存された暗号化された再設定用トークンを空にする写真のアップロードの仕方
uploaderのgem をダウンロードする
↓
rails g uploader 〜でuploaderを作る
rails g migration ~でtableにに写真を保存する場所を示す
例 rails generate migration add_picture_to_microposts picture:string
↓
rails db:migrateで写真を保存したいモデルのなかで写真を保存するためのカラムを作る
↓
写真を保存したいモデルファイルで、保存したいカラムに対してuploaderが働きかけるようにする
詳しくはRuby on Rails チュートリアルuploaderファイルの中には
アップする写真がどんな種類か見分ける、などの指示が書かれている
↓
それを使ってviewのなかでoo種ならば写真を載せるとかにするAjaxとは
サーバーとの通信でデータを受け取り、ページを書き換える時に、
処理をするために別の場所に飛んで、処理後に再度今のページの中身を読み込んで戻ってくるのは処理が多くて遅くなる
↓
Ajaxを使えば今のページのままで処理が行える(今のページの再読み込みをせずに処理できる)Ajaxの例
.load→サーバーのHTMLを読み出す
.getや.post→送ったパラメータを使ってサーバーで処理をしてその結果を返してもらう。どちらも処理結果を得られるが、getの場合は処理結果を得るだけ、postは結果も得るがサーバー側のデータも書き換えも行う?
↓
.getや.postの関数の中では処理してもらうサーバーファイルと送るパラメータと結果取得後の何をするかを書くAjaxの注意
Ajaxは非同期である。つまりその処理が完了する前に次の処理移る。例
①Ajaxでサーバー側のAファイルを読み込む
②Aファイルの文字色を変える
単純にこの順番に命令を書くとファイルは読み込まれるが色は変わらない。
↓
Ajax命令の後に、その中身に対する命令をしたいならばコールバック関数を使ってやる。
- 投稿日:2020-03-17T10:30:45+09:00
FactoryBotでassociationを持つモデルをbuildするもinvalidになる
(Rails Tutorialなんかで出てくる)Relationshipモデルのrspecのテストではまった。いや、テスト以前に
FactoryBotで作ったRelationshipモデルを読み込むも、それがinvalid
だという問題から抜けきれなかった。以下順々に何が起こったのかを記録。今回のRelationshipモデル
カラムは
id
,follower_id
,followed_id
app/modles/relationship.rbclass Relationship < ApplicationRecord belongs_to :follower, class_name: 'User' belongs_to :followed, class_name: 'User' validates :follower_id, presence: true, uniqueness: { scope: [:followed_id] } validates :followed_id, presence: true endRspecでエラーが出るまで
Relationship has many Users
の関係があるため、Relationshipのテストには、以下の2つのFactoryBotを使う。
- UserモデルのFactoryBot
- RelationshipモデルのFactoryBot
spec/modles/user.rbFactoryBot.define do factory :user do email { 'test@test.com' } account_id { 'testtest' } name { 'tester' } password { 'password123' } end endこのFactoryから作られるUserモデルを用いてRealtionshipを作りだすFactoryを定義。
spec/factories/relationship.rbFactoryBot.define do factory :relationship do association :follower, factory: :user # email, account_idは重複しないようにoverwrite association :followed, factory: :user, email: 'another@test.com', account_id: 'another' end endこれをspecファイルから呼び出し、Realtionshipモデルを作る。まずは属性値のオーバーライトなしで作られるモデルがvalidであることの確認が必要。
spec/models/relationships_spec.rbrequire 'rails_helper' RSpec.describe Relationship, type: :model do it 'creates a valid relationship model' do r = build(:relationship) expect(r).to be_valid end endこれを
$ rspec
で実行してみると...実行結果Failures: 1) Relationship creates a valid relationship object Failure/Error: expect(r).to be_valid expected #<Relationship id: nil, follower_id: nil, followed_id: nil, created_at: nil, updated_at: nil> to be valid, but got errors: Follower can't be blank, Followed can't be blank # ./spec/models/relationship_spec.rb:6:in `block (2 levels) in <main>'打開策
テストファイルを以下のように
r = build(:relationship)
をr = create(:relationship)
に書き換えたところ、エラーは出なかった。これは、
rを永続化していればrはvalidになる
ということを意味している。spec/models/relationships_spec.rbrequire 'rails_helper' RSpec.describe Relationship, type: :model do it 'creates a valid relationship model' do r = create(:relationship) expect(r).to be_valid end end参考
StackOverflowによると、
In Rails 5, associations defined as belongs_to are required by default. So when you are checking expect(build(:relationship)).to be_valid, the valid? call is returning false because you don't have a user set.
(一部今回の状況に合うよう加筆)とのこと。
つまり今回の問題はモデルの永続化に関係がありそう。
おまけ
Rails Consoleで遊んでいると以下の現象に気が付いた。要約すると...
- 永続化されないUserモデルである u1, u2 を用いてRealtionshipモデル r を作ってもそれはsaveできない
- u1, u2を永続化したとしても、先程のrはsaveできない
- u1, u2の永続化の後、それらをrの属性に再代入することでrはsaveできるようになる
irb(main):077:0> u1 = User.new(email: 'test@test.com', account_id: 'testtest', name: 'user1', password: 'password') => #<User id: nil, email: "test@test.com", account_id: "testtest", name: "user1", is_male: nil, height: nil, weight: nil, comment: nil, created_at: nil, updated_at: nil> irb(main):078:0> u2 = User.new(email: 'test2@test.com', account_id: 'testtest2', name: 'user2', password: 'password') => #<User id: nil, email: "test2@test.com", account_id: "testtest2", name: "user2", is_male: nil, height: nil, weight: nil, comment: nil, created_at: nil, updated_at: nil> irb(main):079:0> r = Relationship.new(follower: u1, followed: u2) => #<Relationship id: nil, follower_id: nil, followed_id: nil, created_at: nil, updated_at: nil> irb(main):080:0> r.save => false irb(main):081:0> u1.save => true irb(main):082:0> u2.save => true irb(main):083:0> r.save => false irb(main):084:0> r = Relationship.new(follower: u1, followed: u2) => #<Relationship id: nil, follower_id: 1, followed_id: 2, created_at: nil, updated_at: nil> irb(main):085:0> r.save => true