20200317のRailsに関する記事は30件です。

アプリ作成 アウトプット

ツイート機能実装アプリ開発

本日
1スケジュール作成していく中で何が実装に必要なのか、整理することが出来た。
2新規アプリの立ち上げrails new など 必要な作業が、何も見ずに作成していくのは難しい。

本日はここまで、データバースの設計等調べながら進めていく。

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

Capybaraでネスト有りのルーティングパスにvisitコマンドでアクセスする for Ruby on Rails

ネスト有りのルーティングでテストしようとした

specファイルを書いていたとき、ネスト有りのルーティングのテストでvisitコマンドのパスはどう書くんだと?疑問に思いました。
viewファイルと同じ感じでいけるのか?いう疑問で、試してみるといけました。

設定

routes.rb ではこのような設定があるとします。

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

Rspecでネスト有りのルーティングパスにvisitコマンドでアクセスする for Ruby on Rails

ネスト有りのルーティングでテストしようとした

specファイルを書いていたとき、ネスト有りのルーティングのテストでvisitコマンドのパスはどう書くんだと?疑問に思いました。
viewファイルと同じ感じでいけるのか?いう疑問で、試してみるといけました。

routes.rbの設定

routes.rb ではこのような設定があるとします。

routes.rb
  resources :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

visitの失敗例

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

【ruby】Docker開発環境へのGoogle Cloud Translation API (v2)導入手順

開発環境

ruby '2.6.3'
rails '6.0.2'

Google Cloud Translation APIとは

  • ウェブサイトやアプリを 100 以上の言語に瞬時に翻訳したい場合などに役立つのが Translation API です。
  • Translation API の料金

  • Translation API の料金

  • Google Cloud の無料枠
    私の場合は12 か月間の無料トライアル(Google Cloud サービスで使用できる $300 相当のクレジット付き)。なので無料です。

導入手順

Cloud Translate API の有効化

サービスアカウントキーの作成

サービスカウント: 「新しいサービスアカウント」を選択
サービスアカウント名: (任意)
役割: オーナー (Project > オーナー)
サービスアカウントID: (任意)
キーのタイプ: JSON

「作成」ボタンを押下すると、jsonファイルがダウンロードされます

サービスアカウントキーの適用,環境変数の設定

  • GOOGLE_APPLICATION_CREDENTIALSという名前の環境変数を作成し、先ほどダウンロードしたjsonファイルのパスを設定します。
ターミナル
vim .zshrc
.zshrc
export GOOGLE_APPLICATION_CREDENTIALS="ダウンロードしたファイルパス"
  • .zshrcの更新。
ターミナル
source ~/.zshrc

これでいつでもローカル環境では参照できるようになります。

保存されているか確認

ターミナル
printenv | grep GOOGLE
=> export GOOGLE_APPLICATION_CREDENTIALS="ダウンロードしたファイルパス"

docker上でGOOGLE_APPLICATION_CREDENTIALSを適応

  1. 開発中のディレクトリにjsonファイルをコピーする。(ファイル名は変更しても問題ありません、今回はkey.jsonという名前で行います。)
  2. .gitignoreに追記する
.gitignore
/key.json
  • DockerfileでDocker内にコピーする
Dockerfile
COPY key.json key.json
ENV GOOGLE_APPLICATION_CREDENTIALS key.json
  • docker-compose build # rails編
  1. gem導入
    gem 'google-cloud-translate'

  2. 私の場合は外部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ということをお忘れなく。
おしまい

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

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 RailsApi

RailsApiフォルダに移動。

[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のモデルを作成したためその複数形をパスに指定。)

すると以下の様な空のレスポンスが返ってきます。これはまだデータ投入していないからです。
スクリーンショット 2020-03-17 21.54.25.png

データ投入

ではデータ投入しましょう。
~/users/POSTリクエストを送ります。これは「bodyのjsonを元にデータを作成する」ことを意味します。その際に、リクエストのBodyを以下の様に指定しましょう。
Body content type : application/json
Body : {"user_id":"hoge","password":"fuga"}
スクリーンショット 2020-03-17 22.11.54.png

すると以下の様なレスポンスが返ってきてユーザが作られたことが分かります。

スクリーンショット 2020-03-17 22.15.45.png

ついでにもう1つデータ投入しておきましょう。
スクリーンショット 2020-03-17 22.19.19.png

この状態で~/users/へGETリクエストを送ると、、、
スクリーンショット 2020-03-17 22.23.38.png

先ほど入れた2件のデータが両方取れます。

1件取得

次は、~/users/2GETリクエストを送ってみましょう。これは「idが2である人のデータを取得する」ことを意味しており、以下の様なレスポンスが返ってきます。
スクリーンショット 2020-03-17 22.26.31.png

削除

次は、~/users/2DELETEリクエストを送ってみましょう。これは「idが2である人のデータを削除する」ことを意味しており、以下の様なレスポンスが返ってきます。
スクリーンショット 2020-03-17 22.39.56.png

この状態で~/users/へGETリクエストを送ると、、、
スクリーンショット 2020-03-17 22.40.49.png

idが2のデータがなくなっていることがわかります。

更新

最後に、~/users/1PATCHリクエスト(PUTでも可)を送ってみましょう。これは「bodyのjsonを元にidが1であるデータを更新する」ことを意味します。その際に、リクエストのBodyを以下の様に指定しましょう。
スクリーンショット 2020-03-17 22.49.11.png

すると以下の様なレスポンスが返ってきます。
スクリーンショット 2020-03-17 22.49.34.png

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

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

【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 RailsApi

RailsApiフォルダに移動。

[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のモデルを作成したためその複数形をパスに指定。)

すると以下の様な空のレスポンスが返ってきます。これはまだデータ投入していないからです。
スクリーンショット 2020-03-17 21.54.25.png

データ投入

ではデータ投入しましょう。
~/users/POSTリクエストを送ります。これは「bodyのjsonを元にデータを作成する」ことを意味します。その際に、リクエストのBodyを以下の様に指定しましょう。
Body content type : application/json
Body : {"user_id":"hoge","password":"fuga"}
スクリーンショット 2020-03-17 22.11.54.png

すると以下の様なレスポンスが返ってきてユーザが作られたことが分かります。

スクリーンショット 2020-03-17 22.15.45.png

ついでにもう1つデータ投入しておきましょう。
スクリーンショット 2020-03-17 22.19.19.png

この状態で~/users/へGETリクエストを送ると、、、
スクリーンショット 2020-03-17 22.23.38.png

先ほど入れた2件のデータが両方取れます。

1件取得

次は、~/users/2GETリクエストを送ってみましょう。これは「idが2である人のデータを取得する」ことを意味しており、以下の様なレスポンスが返ってきます。
スクリーンショット 2020-03-17 22.26.31.png

削除

次は、~/users/2DELETEリクエストを送ってみましょう。これは「idが2である人のデータを削除する」ことを意味しており、以下の様なレスポンスが返ってきます。
スクリーンショット 2020-03-17 22.39.56.png

この状態で~/users/へGETリクエストを送ると、、、
スクリーンショット 2020-03-17 22.40.49.png

idが2のデータがなくなっていることがわかります。

更新

最後に、~/users/1PATCHリクエスト(PUTでも可)を送ってみましょう。これは「bodyのjsonを元にidが1であるデータを更新する」ことを意味します。その際に、リクエストのBodyを以下の様に指定しましょう。
スクリーンショット 2020-03-17 22.49.11.png

すると以下の様なレスポンスが返ってきます。
スクリーンショット 2020-03-17 22.49.34.png

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

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

【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 RailsApi

RailsApiフォルダに移動。

[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のモデルを作成したためその複数形をパスに指定。)

すると以下の様な空のレスポンスが返ってきます。これはまだデータ投入していないからです。
スクリーンショット 2020-03-17 21.54.25.png

データ投入

ではデータ投入しましょう。
~/users/POSTリクエストを送ります。これは「bodyのjsonを元にデータを作成する」ことを意味します。その際に、リクエストのBodyを以下の様に指定しましょう。
Body content type : application/json
Body : {"user_id":"hoge","password":"fuga"}
スクリーンショット 2020-03-17 22.11.54.png

すると以下の様なレスポンスが返ってきてユーザが作られたことが分かります。

スクリーンショット 2020-03-17 22.15.45.png

ついでにもう1つデータ投入しておきましょう。
スクリーンショット 2020-03-17 22.19.19.png

この状態で~/users/へGETリクエストを送ると、、、
スクリーンショット 2020-03-17 22.23.38.png

先ほど入れた2件のデータが両方取れます。

1件取得

次は、~/users/2GETリクエストを送ってみましょう。これは「idが2である人のデータを取得する」ことを意味しており、以下の様なレスポンスが返ってきます。
スクリーンショット 2020-03-17 22.26.31.png

削除

次は、~/users/2DELETEリクエストを送ってみましょう。これは「idが2である人のデータを削除する」ことを意味しており、以下の様なレスポンスが返ってきます。
スクリーンショット 2020-03-17 22.39.56.png

この状態で~/users/へGETリクエストを送ると、、、
スクリーンショット 2020-03-17 22.40.49.png

idが2のデータがなくなっていることがわかります。

更新

最後に、~/users/1PATCHリクエスト(PUTでも可)を送ってみましょう。これは「bodyのjsonを元にidが1であるデータを更新する」ことを意味します。その際に、リクエストのBodyを以下の様に指定しましょう。
スクリーンショット 2020-03-17 22.49.11.png

すると以下の様なレスポンスが返ってきます。
スクリーンショット 2020-03-17 22.49.34.png

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

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

Rails アプリにGoogleMap APIを導入する

はじめに

投稿画面で、ユーザから入力された地名を、GoogleMap上に反映させるための機能実装をまとめます。

実装方法

1.ライブラリをインストール。

以下のライブラリをGemfileに追記します。

Gemfile
gem 'gmaps4rails'
gem 'geocoder'

そして、installします。

terminal
$ bundle install

2.カラムの追加

次に、すでに存在しているpostsテーブルにカラムを追加していきます。

20200223012643_add_address_to_posts.rb
class AddAddressToPosts < ActiveRecord::Migration[5.2]
  def change
    add_column :posts, :address, :string
    add_column :posts, :latitude, :float
    add_column :posts, :longitude, :float
  end
end

address(住所), latitude(緯度), longitude(経度)カラムを追加します。
先ほど、インストールしたライブラリが、このaddressに格納された情報から緯度、経度を自動で計算をし、それぞれのカラムに格納してくれます。

マイグレーションファイルをDBに反映させるのを忘れずに

terminal
$ rails db:migrate

3.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. 最後に表示を確認

4a3d19bbbaebdc01e1341f01d67ab5bb.png

このように、投稿フォームで入力された場所をマップが表示していれば成功です。

おわりに

自分のアプリケーションにGoogleMapを搭載するのに、色々と試行錯誤しましたが、意外とシンプルなコードで実装することができました。
GoogleMapを使った機能を実装する際には、GoogleのAPIキーを取得する必要があるのですが、その辺りの詳細はまたの機会にまとめます。

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

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

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

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

active_job/lib/active_job/railtie.rb
      ActiveSupport.on_load(:action_dispatch_integration_test) do
        include ActiveJob::TestHelper
      end

ここでincludeされているActiveJob::TestHelperが原因です。

https://github.com/rails/rails/blob/76bafb0b2ff5d4a7afc373191963eb2a243c75d4/activejob/lib/active_job/test_helper.rb#L36-L46

ActiveJob::TestHelperのbefore_setupで queue_adapter_for_testにハードコードされている ActiveJob::QueueAdapters::TestAdapter というadapterに上書きされてしまっていることで発生していました。

activejob/lib/active_job/test_helper.rb
    def 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.rb
RSpec.configure do |config|
  config.before(:each) do
    (ActiveJob::Base.descendants << ActiveJob::Base).each(&:disable_test_adapter)
  end
end

これでRSpec & Sidekiqの環境でもTestAdapterの上書きをキャンセルできます。

issue

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

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
・MySQL

4.手順

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の中身は以下のようになります。

Dockerfile
FROM 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 . /myapp
docker-compose.yml
version: '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の設定(初心者向け)

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

Rails + GitHub の導入

概要

Ruby on Rails 作成したアプリケーションを GitHub に登録して管理するまでの流れになります。

目次

  1. Rails アプリケーションのローカルリポジトリを作成
  2. GitHub にリモートリポジトリを作成
  3. ローカルリポジトリとリモートリポジトリを結びつける
  4. ローカルリポジトリをリモートリポジトリに反映

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 」をクリックします。
image

リモートレポジトリ名を入力し、「 Create repository 」ボタンをクリックしてリポジトリを作成します。
image

以下の様な画面になれば、リモートリポジトリの作成は完了です。
image

3. ローカルリポジトリとリモートリポジトリを結びつける

まずURLをコピーします。
image

次にコマンドで操作します。

ターミナル
$ 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)に反映させる操作ができます。

最後にブラウザで確認してみましょう。先程のリモートリポジトリ作成後のページをリロードしてください。
image
上記のような表示なっていれば正しく反映できています。

以上で Rails + GitHub の導入は完了です。

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

画像アップロードとリサイズ

Carrierwaveとminimagick

画像アップロードするにはCarrierwaveを使います。
画像ファイルをリサイズするにはminimagickを使います。
ターミナル

$ brew install imagemagick

Gemfileの一番下に

     〜省略〜
gem 'carrierwave'
gem 'mini_magick'

ターミナル

$ bundle install

ターミナル

$ rails g uploader image

【例】モデル名をMessageとします

app/models/message.rb
class Message < ApplicationRecord

       〜省略〜

  mount_uploader :image, ImageUploader
end
app/uploaders/image_uploader.rb
class 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以内にリサイズするという意味です。

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

一時フォルダ内だからといってファイルを閉じ忘れてはいけない

結論

一時フォルダを消してもそのファイルが完全に消えずハードディスクを圧迫して困ります、ちゃんと閉じましょう

紹介: 一時フォルダ

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

参考

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

エラーメッセージ

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メソッドによってエラーメッセージ全件の内容を取得しています。

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

【第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がいっぱい入っているので、暇なときに見てみよう。


スクリーンショット 2020-03-16 21.26.51.png
ジャスティンビーバーの曲くらいダウンロードされている人気者。

2.アプリケーションの作成

まず、environmentディレクトリに移動する。

$ cd ~/environment

補足情報:コマンドラインでは現在自分がどの位置にいるかが$の左側で示されている。
ec2-user:~/environment $

下のコマンドを実行し、アプリケーションを作成。

rails _5.1.6_ new hello_app

これで大量のディレクトリ、ファイルが生成された。

Bundlerのインストール

Bundlerとは?
gemの互換性やバージョン管理をしてくれるgem。

Gemfileを指定の内容に変更する。

注意点
ファイルの内容を変更した後、必ずCtrl + sで変更内容をセーブしよう。
セーブが行われていない場合、ファイルのタイトルバーの右側に●マークがある
スクリーンショット 2020-03-17 13.50.19.png

gemのバージョンを固定することで、チュートリアルを同じ挙動で進めることができる。
その後、Bundle installを実行。

$ bundle install

※カレントディレクトリがhello_appであることを確認してから実行しよう。
※上記のコマンドを実行して、「bundle updateを実行してください」というエラーメッセージが出たら、先にBundle updateを実行しよう。

railsサーバーの実行

これまでの準備で、サーバーを起動する準備が整った。
以下のコマンドで、実際にサーバーを立ち上げよう。

$ cd ~/environment/hello_app/
$ rails server

※今までのターミナルではなく、新しいターミナルで実行しよう。
※サーバーを終了するときはCtrl + C。

これによりブラウザで表示できるようになったので確認してみよう。
スクリーンショット 2020-03-17 14.07.18.png

参考

Bundlerとは:https://pikawaka.com/rails/bundler

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

【解決】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

以上です!

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

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

【Rails】devise gemありきで、ユーザー情報を更新する方法

今回こまったこと

devise gemをbundle installして、アカウントを登録。
作ったアカウントを編集する画面を作ったものの、内容が反映されない・・・どうすれば!?

と、言う事でググったら解決できたのでまとめます。

事前準備

devise用のuserテーブルには、カラムを追加してます。
name ユーザー名
text プロフィールコメント
prof_image プロフィール画像

↓こんな感じ
スクリーンショット 2020-03-17 13.24.28.png

↓コントローラーにお決まりの一文
スクリーンショット 2020-03-17 13.27.21.png
このif: :devise_controller?は、どうやら、deviseコントローラーで処理をしているかどうか。を判断するヘルパーメソッドみたいです。
ので、before_actionに記述して、ApplicationControllerの処理の前に、判別しているっぽいです。

↓protected配下にこれまたお決まりの一文。
スクリーンショット 2020-03-17 13.27.02.png
deviseにもともと用意されていない「:name,:prof_image,:text」の3つのテーブルへ書き込みを許可するぜ。って書いてあげてます。
これについては、sing_upの処理で許可するよ。って書かれてます。※今回はここの理解が甘かった。

編集したプロフィールが反映されない問題

プロフィール詳細画面を作成して、ここから編集画面へ遷移するような導線を用意しました。で、以下がプロフィール編集画面です。ここの「更新」ボタンを押しても反映されない・・・!なぜ?

↓プロフィール編集画面(つっこみどころ満載ですが、ゆるしてください。レイアウトも作成中です(汗))
スクリーンショット 2020-03-17 13.37.37.png

なぜ?仮定

エラーは出ないし、きっとコントローラーに記載されている処理が何か足りていない。と仮定。
それならばと思い、コントローラーの記載を確認。むむむ・・・今の自分の知識じゃ訳がわからない・・・。
ということで、ぐぐる。
どうやら、「devise_parameter_sanitizerメソッド」の理解が足りていなかったようだ!

少しでもいいから、devise_parameter_sanitizerメソッドのこと思い出してください

この一文は僕が昔大好きだったゲームの一文のパロです。
はい、どうでもいいです。ごめんなさい。

調べていったら、「devise_parameter_sanitizerメソッド」の引数部分の指定不足が原因だと言う事がわかりました。

そもそもdevise_parameter_sanitizerメソッドとは

deviseではサインアップ時に既存で用意されているカラムemailpasswordのみを受け取るようにストロングパラメーターで設定してあります。
なので、独自で追加したカラムへのアクセス許可をしてあげる必要があります。
そこで登場するのが、このdevise_parameter_sanitizerメソッドです。

このdevise_parameter_sanitizerメソッドには、第一引数でどのアクションの時に許可する?が指定できるみたいです。

第一引数書く値 意味
:sign_in ログイン時
:sing_up 新規登録時
:account_update レコード更新時

原因と解決

つまるところ、現状の実装だとApplicationControllerにはsing_upの処理が走ったタイミングでしか追加したカラムの書き込みを許可していないって事になりますね。
なので実装を修正。

▼Before
スクリーンショット 2020-03-17 13.27.02.png

▼After
スクリーンショット 2020-03-17 13.53.53.png

はい。これで無事更新ができるようになりました!!

おわり

初の個人アプリ開発もエラー→ググる→トライ→エラー→ググる・・・・・解決!が定着化してきました。
色々な記事を投稿してくださっている先輩方には感謝しかありません!
僕も先輩方と同じように後からエンジニアを目指す人たちの助け舟を出せるような人に育っていきたいです。

あと、補足や認識齟齬があればどうぞご指摘いただけますと幸いです!
自分の知識を正しいものにしていきたいので、是非ともよろしくお願いいたします。

ではでは、ありがとうございました!

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

フラッシュメッセージ

フラッシュメッセージとは

ユーザーが、「サインアップ」「ログイン」「ログアウト」を行った直後にメッセージを出すことです。

flashオブジェクト

deviseを使用すると、ログイン時などに表示させるメッセージが「flashオブジェクト」に自動で格納されます。
flashオブジェクト内には、複数のメッセージがハッシュのように「キー」「バリュー」形式で保存されています。
【例】ファイルを_notificationsとします

app/views/layouts/__notifications.html.haml
.notification
  - flash.each do |key, value|
    = content_tag :div, value, class: key

each文を使うと、これらを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.rb
module ChatSpace
  class Application < Rails::Application
    (中身)
    config.i18n.default_locale = :ja
  end
end

これで日本語でフラッシュメッセージの表示がされます。

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

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
end

HTML形式でのレポート出力を行う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)

以上で今回の説明を終了します。

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

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_sandbox

app の下にファイルを作成する

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)

試したソース

参考情報

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

@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つにまとめて圧縮したファイルを読み込んでいるという違いがあることが分かりました。

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

プログラミング王に、、俺はなる!!!

前回までのあらすじ

謎の赤髪の男から「この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チュートリアルと実際に簡単なアプリ作成を同時進行みたいな感じで進めていきたいと思います。
今回はここまで!!!

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

プログラミング王に、、俺はなる!!!(環境構築編)

前回までのあらすじ

謎の赤髪の男から「この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チュートリアルと実際に簡単なアプリ作成を同時進行みたいな感じで進めていきたいと思います。
今回はここまで!!!

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

プログラミング王に、、俺はなる!!!(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チュートリアルと実際に簡単なアプリ作成を同時進行みたいな感じで進めていきたいと思います。
今回はここまで!!!

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

migrationファイルのnull: falseって?

migrationファイルのnull: falseって?

→指定したカラムが(データベースに)カラの状態で保存されることを防ぐ

rb
class 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側の設定。
結論:目的の場所が異なるので両方設定しておくことが良いですね。

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

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.rb
Rails.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.rb
class UsersController < ApplicationController

  def show
    @user = User.find(params[:id]) #rootingにあるidをprramsで取り出して使用して、userを探している。
  end

・form_tagやform_forで送られてきた値を取得するときは、params[送られてきた変数]をする。送られてきた変数の中身がからの時はparams[送られてきた変数]は空として扱う。

app/controllers/users_controller.rb
class 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.rb
class 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.rb
class Micropost < ApplicationRecord
  belongs_to :user
end
app/models/user.rb
class 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.rb
class 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
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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.rb
Rails.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.rb
class UsersController < ApplicationController

  def show
    @user = User.find(params[:id]) #rootingにあるidをprramsで取り出して使用して、userを探している。
  end

・form_tagやform_forで送られてきた値を取得するときは、params[送られてきた変数]をする。送られてきた変数の中身がからの時はparams[送られてきた変数]は空として扱う。

app/controllers/users_controller.rb
class 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.rb
class 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.rb
class Micropost < ApplicationRecord
  belongs_to :user
end
app/models/user.rb
class 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.rb
class 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命令の後に、その中身に対する命令をしたいならばコールバック関数を使ってやる。

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

FactoryBotでassociationを持つモデルをbuildするもinvalidになる

(Rails Tutorialなんかで出てくる)Relationshipモデルのrspecのテストではまった。いや、テスト以前にFactoryBotで作ったRelationshipモデルを読み込むも、それがinvalidだという問題から抜けきれなかった。以下順々に何が起こったのかを記録。

今回のRelationshipモデル

カラムはid, follower_id, followed_id

app/modles/relationship.rb
class 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
end

Rspecでエラーが出るまで

Relationship has many Usersの関係があるため、Relationshipのテストには、以下の2つのFactoryBotを使う。

  • UserモデルのFactoryBot
  • RelationshipモデルのFactoryBot
spec/modles/user.rb
FactoryBot.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.rb
FactoryBot.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.rb
require '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.rb
require '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
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む