2022/02/20(日) ゼロからわかるRuby超入門Chapter4
配列
- 配列は、要素と呼ばれる複数のオブジェクトをまとめるための部品
- 配列自身もArrayクラスのオブジェクト
- 配列に入る個々のオブジェクトを要素と呼ぶ
- 配列に新たに要素を追加したり、既に入っている要素を削除したり出来る
- 配列では、種類の異なるオブジェクトを1つの配列にまとめることが出来る
- 配列名は慣習的に複数形の単語にする(複数のオブジェクトが要素として格納されるため)
# 配列名は複数形 sugers = ["白砂糖", "黒糖", "角砂糖"] coffee_beans = ["Brazil", "Kenya", "Nicarragua"] even_numbers = [2, 4, 6] # 種類の異なるオブジェクト(型の異なるオブジェクト)を1つの配列にまとめる somethings = ["カフェラテ", 400, false] => ["カフェラテ", 400, false] # 配列に入っている要素は、それぞれ異なる型のオブジェクト somethings[0].class => String somethings[1].class => Integer somethings[2].class => FalseClass # 配列はArrayオブジェクト somethings.class => Array ["カフェラテ", 400, false].class => Array
配列に入っている要素を取得する
- 配列の特定の要素を取得する際は、インデックス番号を指定する
- インデックス番号とは、配列の複数ある要素から1つを特定することが出来るように、0から1,2と順に要素に割り当てられた番号のこと。
- 1番後ろの要素を取得する場合は、「-1」を後ろから2番目の要素を取得する場合は「-2」をインデックス番号として指定する
- インデックス番号で指定する以外にもlastメソッドで配列の先頭の要素を、firstメソッドで配列の末尾の要素を取得できる。
drinks = ["コーヒー", "カフェラテ", "紅茶", "カルピス", "オレンジジュース"] => ["コーヒー", "カフェラテ", "紅茶", "カルピス", "オレンジジュース"] # インデックス番号を指定して、特定の要素を取得する drinks[0] => "コーヒー" drinks[1] => "カフェラテ" drinks[2] => "紅茶" drinks[3] => "カルピス" drinks[4] => "オレンジジュース" # 取得した要素オブジェクトのクラス drinks[4].class => String # 配列の末尾の要素を取得 drinks[-1] => "オレンジジュース" drinks.last => "オレンジジュース" # 配列の先頭の要素を取得 drinks.first => "コーヒー"
# drinks配列は要素を5つ持つので、インデックス番号は4まの要素しか存在しない=>nilオブジェクトが返る drinks[5] => nil
配列に要素を追加・削除する
- 要素を追加するメソッド
- pushメソッドは、配列の末尾に要素を追加する
- unshiftメソッドは、配列の先頭へ要素を追加する
>>
は、配列の末尾に要素を追加する
# 配列の先頭に要素を追加 drinks.unshift("キャラメル・マキアート") => ["キャラメル・マキアート", "コーヒー", "カフェラテ", "紅茶", "カルピス", "オレンジジュース"] # 配列の末尾に要素を追加 drinks.push("マンゴー パッション ティー フラペチーノ") => ["キャラメル・マキアート", "コーヒー", "カフェラテ", "紅茶", "カルピス", "オレンジジュース", "マンゴー パッション ティー フラペチーノ"]
- 要素を削除するメソッド
- popメソッドは、配列の末尾から要素を1つ削除する
- shiftメソッドは、配列の先頭から要素を1つ削除する
# 配列の末尾から要素を1つ削除 drinks.pop => "マンゴー パッション ティー フラペチーノ"#=> 削除した要素を戻り値を返す drinks => ["キャラメル・マキアート", "コーヒー", "カフェラテ", "紅茶", "カルピス", "オレンジジュース"] # 配列の先頭から要素を1つ削除 drinks.shift => "キャラメル・マキアート"#=> 削除した要素を戻り値を返す drinks => ["コーヒー", "カフェラテ", "紅茶", "カルピス", "オレンジジュース"]
配列の足し算・引き算
- 配列の足し算は、2つの配列をつなげた新しい配列を作成します
- 配列の引き算は、元の要素から引く配列の要素を取り除いた新しい配列を作成します。
# 配列の足し算 a1 = [1, 2, 3] a2 = [4, 5] a1 + a2 #=> [1, 2, 3, 4, 5] # 配列b1にしかない要素を取得する(引き算で) b1 = [1, 2, 3] b2 = [1, 3, 5] b1 - b2 #=> [2]
配列の全要素に繰り返し処理を行う
drinks => ["コーヒー", "カフェラテ", "紅茶", "カルピス", "オレンジジュース"] # 配列の要素に繰り返し処理 # 配列オブジェクトdrinksの全要素を表示する irb(main):033:0> drinks.each do |drink| irb(main):034:1* puts drink irb(main):035:1> end コーヒー カフェラテ 紅茶 カルピス オレンジジュース => ["コーヒー", "カフェラテ", "紅茶", "カルピス", "オレンジジュース"]
- eachメソッドは、配列の全要素を繰り返し処理するメソッド
- 配列の各要素はインデックス番号0番から順にdrinkという変数に格納され、puts処理が行われます。それが要素数分、繰り返される。
- 配列の要素数がいくつであっても、eachメソッドを使えば全要素を繰り返し処理を実行できる(要素数によってプログラムを書き換える必要がない)
- breakを使って、繰り返し処理を途中で終わらせることができる。ある条件に達すると、繰り返しを終了するなどして使用する。
- nextは、ある特定の回の時に繰り返し処理を中断して、次の繰り返しに処理を移す
- 繰り返す範囲を指定する場合は、Rangeオブジェクトを指定します。
# 繰り返し処理を途中で終わらせる [1, 2, 3].each do |x| break if x == 2 # xの値が2である時、繰り返し処理を終わらせる(処理終了) puts x end #=> 1 # xが2の時だけ繰り返し処理を中断する [1, 2, 3].each do |x| next if x == 2 # xの値が2である時、繰り返し処理を終わらせる(処理終了) puts x end #=> 1 #=> 3 # 3~5の数値を繰り返し処理する (3..5).each do |x| puts x end #=> 3 #=> 4 #=> 5
参考
ゼロからわかるRuby超入門 chapter4
2022/02/19(土) ゼロからわかるRuby超入門Chapter3
比較メソッド(<
や>
または、<=
、>=
)
比較メソッドは、<
や>
または、<=
、>=
のことです。
具体的に言うと、左右の数値や文字列の大小を比較して、条件を満たす場合にtrueを、満たさない場合にfalseを戻り値として返すメソッドです。下記の例からも分かるように大小を比較するメソッドですが、比較結果は数値ではなく、trueとfalseでのみ出力される部分に注意が必要です。👈🏻
irb(main):002:0> 1 < 2 => true #=> 実行結果としてtrueオブジェクトで置き換えられる irb(main):003:0> 1 > 2 => false
また、変数に入った数値を比較することも出来ます。この比較メソッドは、if文の条件式などで使われます。
irb(main):004:0> wallet = 500 => 500 irb(main):005:0> wallet >= 500 => true irb(main):006:0> wallet = 300 => 300 irb(main):007:0> wallet >= 500 => false
文字列の文字数を比較することも出来ます。
irb(main):008:0> 'ruby' >= 'put' => true irb(main):009:0> 'ruby'.length >= 'put'.length => true irb(main):010:0> 'ruby' < 'put' => false
等しい、等しくないを判断できる比較メソッド(==
、!=
)
比較メソッドには、<
や>
または、<=
、>=
の他にも==
や!=
があります。==
は、等しいかどうかを判断して等しい時にtrueを返す比較メソッドです。対して、!=
は、等しくない時にtrueを返す比較メソッドです。つまり、==
を使った時にfalseになる条件の時!=
を代わりに使用するとtrueが返るということです。使いたい条件によって、使い分けましょう。
== | != | |
---|---|---|
等しい時 | true | false |
等しくない時 | false | true |
📌 <
や>
または、<=
、>=
の比較メソッドは、特に大小を比較します。そのため、文字列の文字数の大小を比較できます。
==
や!=
の比較メソッドは、数値オブジェクトだけでなく文字列オブジェクトの等しい、等しくないを比較できます。つまり、文字列そのものが等しいかを比較できるのです。
# 文字列同士が等しいのかを調べることも可能。 irb(main):011:0> 'ruby' == 'ruby' => true irb(main):012:0> 'ruby' != 'ruby' => false irb(main):013:0> 'ruby' != 'ruby ' => true # 空白を入れると同じ文字列として見なされない。 irb(main):014:0> 'ruby' == 'ruby ' => false # 空白を入れると同じ文字数の文字列として見なされない。 irb(main):016:0> 'ruby'.length == 'ruby '.length => false # 文字数は同じでも異なる文字列は、falseと判断できる irb(main):017:0> 'ruby' == 'konn' => false
末尾に?が付くメソッド
末尾に?
が付くメソッドは、trueかfalseの真偽値を返します。
?
を含めてのメソッド名なので、?を省略すると、エラーとなってしまいます。
メソッド | 意味 |
---|---|
include? | 含むかどうか(部分一致)。配列であれば、等しい要素を持つ時に、文字列であれば、文字列中に部分文字列が含まれていればtrueを返す。 |
empty? | 入れ物が空かどうか(String, Array, Hash, Set)。文字列が空 (つまり長さ 0) の時、配列であれば、自身の要素の数が 0 の時にtrueを返す。 |
nil? | nilかどうか |
if文を使った条件式
- if文は条件を満たした(true)時に処理を実行し、条件を満たさない(falseとnil)時は処理を実行しません 【Ruby】 論理演算子(!, &&, ||, not, and, or)をまるごと学ぼう!
- インデント(スペース2つ分)を用いるとプログラムを読みやすく、見やすく書くことができます
- unlessはifと反対の動きをします。条件が満たされない(false)の時に処理し、条件を満たす(true)の時は処理を実行しません。
- if文の条件式に数値オブジェクトや文字列オブジェクトを指定した場合は、条件式が常にtrueの状態になります。
後置if(if修飾子)
- ifを使って、複数行で書いたプログラムを1行で簡潔に書くことができるものです。
- 条件を満たした時の処理が1行で収まるときに使います。他にも、以下のような時に使います。
- 後置ifを使っても横に長くならない
- 自然な英語っぽく読める(「do A if B = BならAせよ」の形式で読める)
- 【Ruby】乱用厳禁!?後置ifで書くとかえって読みづらくなるケースより
# 後置ifの使い方 条件式がtrueの場合に実行したい処理 if 条件式 # 後置unlessの使い方 条件式がfalseの場合に実行したい処理 unless 条件式
条件式で条件を満たさない時にも処理を実行する(処理を分岐)
- 条件を満たさない時の処理を記述するのにelse節を使う
if 条件 # 条件を満たした時の処理 else # 条件を満たさない時の処理 end
- ifで分岐する処理を3つ以上にする場合、elsifとelseの両方を用います。
- elsifはif以外の別の条件を書くことができます。
if 条件① # 条件①を満たした時の処理 elsif 条件② # 条件①を満たさないけれど、条件②を満たした時の処理 else # 条件①②の両方とも満たさない時の処理 end
論理演算子を用いて複数の条件を実現する
論理演算子とは?
論理演算子とは、「真」と「偽」の2つの値だけで行う計算(論理演算)を表す記号のことです。Rubyの論理演算子には、「!, &&, ||, not, and, or」が用意されています。 論理演算子を使用すると、複数の条件式を組み合わせて判定することができます。
A || Bは、左辺(A)を評価して真ならその値を返し、偽なら右辺(B)の値を返す
A && Bは、左辺(A)を評価して偽ならその値を返し、真なら右辺(B)の値を返す
【Ruby】 論理演算子(!, &&, ||, not, and, or)をまるごと学ぼう!
条件によって、複数の選択肢から1つを選んで分岐する方法(case)
order = 'パフェ' # 条件の候補に合致する処理を実行させる(case) case order when 'カフェラテ' # 変数orderの値がカフェラテの時(候補①) puts 'カフェラテ' when 'モカ' # 変数orderの値がモカの時(候補②) puts 'モカ' else # どの選択肢(カフェラテでもモカ)でもない時(候補①②以外) puts '取り扱っていません' end
決まった回数だけ繰り返す(timesメソッド)
# 3回繰り返す処理(繰り返す処理が複数行ある時) 3.times do puts 'モカ' puts 'ください' end # 3回繰り返す処理(繰り返す処理が1行のみの時) # ブロックをdo ~ endではなく、{}で記述できます 3.times { puts 'カフェラテください'}
条件を満たしている間ずっと繰り返す(whileメソッド)
biscuit = 0 # ビスケットが5つになるまでずっと繰り返す(繰り返しの条件) while biscuit < 5 biscuit += 1 # 変数biscuitの値に1を加えて再度代入する puts "ポケット叩くとビスケットが#{biscuit}つ" # 式展開を使っているので、""を使う end #=>ポケット叩くとビスケットが1つ #=>ポケット叩くとビスケットが2つ #=>ポケット叩くとビスケットが3つ #=>ポケット叩くとビスケットが4つ #=>ポケット叩くとビスケットが5つ
参考
ゼロからわかるRuby超入門 chapter3
Bootstrap
Bootstrapとは?
Bootstrapとは、レスポンシブなモバイルファーストなウェブサイトを構築するためのオープンソースの
CSSフレームワーク
です。
「ボタンにはこのCSSが良いだろう」「フォームはこれが良いだろう」といったCSS/JSを集めて、一つのパッケージとして提供してくれています。
Bootstrapとレスポンシブデザイン
Bootstrapはブレークポイント
とグリッドシステム
によって画面サイズに合わせてレイアウトを変更し、コンテンツを配置することでレスポンシブデザイン
に対応しています。
ブレークポイント
ブレークポイントとは、「レイアウトをユーザーの使用端末や閲覧画面のサイズに合わせてレスポンシブに変化させるための基準」のことです。
このように、「何をいくつ分のブロック(グリッド)で表示するか」をコントロールすることで、デザイン性・自由度共に高いコンテンツを作成することができるのです。そしてbootstrapでは、グリッドシステム
を上手く使うことで簡単にレスポンシブデザイン
を実現することができます。
ヘッダー
では、Navbar (ナビゲーションバー)を使用することで、簡単にレスポンシブデザインを適用できます。また、body部分
では.containerを用いることで、レスポンシブデザインを適用できます。
.container は段階的コンテナを生成します。ウィンドウの横幅に応じて段階的に横幅が変動します。xs(~575px)の時は 100%、sm(576~767px)の時は 540px、md(768~991px)の時は 720px、lg(992~1199px)の時は 960px、xl(1200px~)の時は 1140px 固定となります。コンテナはセンタリングされます。
とほほのBootstrap 4入門 - コンテナ - とほほのWWW入門
bootstrap導入後の例
<button class='btn btn-primary'>テスト</button>
と記述した場合、bootstrapを導入していると
このようにある程度見栄えが整ったボタンが出来上がるのです。この「class='btn btn-primary'」の部分がbootstrap
に認識され、それに適合したレイアウトを適応させてくれています。
bootstrap
はその他にも、画面を12分割して配置を指定できるグリッドシステム
や、レスポンシブデザイン
など始めとする、多くの便利な機能を提供しています。
Bootstrapのver4系をインストールする
↑WebpackerがインストールされてないRails5以前のアプリを対象にしたBootstrap4を導入する手順
Railsアプリで Bootstrap 4 を利用する - Qiita
GitHub - twbs/bootstrap-rubygem: Bootstrap 4 rubygem for Rails / Sprockets / Hanami / etc
導入手順
Gemfile
Gemfileでbootstrap
を指定してインストールする。
Bootstrapは※jQuery
に依存するため、(デフォルトでjQueryがインストールされない)Rails5.1以上ではjquery-railsもGemfileに追記する。
gem 'bootstrap', '~> 4.1.1' gem 'jquery-rails'
# Gemfileに追記したgemをbundleでインストール # bundleでインストールすることにより、gemのバージョン管理がしやすくなる $ bundle install
※注意点
sprockets-rails
がv2.3.2.以上である必要がある。
# sprockets-railsのバージョン確認方法 $ bundle show |fgrep sprockets-rails * sprockets-rails (3.2.1)
※jQuery
Rails5.1以降のバージョンではRailsインストール時にjQuery
が自動でインストールされなくなりました。他のライブラリの導入に影響が出る弊害を無くすためです。
しかし、別途jquery-rails
gemをインストールすることで、jQueryを使用することが出来ます。
BootstrapJavaScriptはオプションでjQueryを使用できます。Rails 5.1以降を使用している場合は、jquery-railsgemをGemfileに追加できます。
# gemfileに追加することで、jQueryを使用できる gem 'jquery-rails'
# bundleコマンドでインストール
$ bundle install
さらに、マニフェストファイル
上で、jQueryをrequire
することによりjQueryを使用できるようになります。
//= require jquery3
application.scss(マニフェストファイル)
アセットパイプライン
を介してファイルを利用できるように設定します。Railsアプリの作成時に生成されるapplication.css
をapplication.scss
にリネームするなどして、.scss
(Sass構文の場合は.sass)ファイルを用意する。
# .cssファイルを.scssファイルにリネームする(拡張子の変更)
$ mv app/assets/stylesheets/application.css app/assets/stylesheets/application.scss
app/assets/stylesheets/application.scss
(どのファイルからも読み込まれるstylesheetsファイル)でbootstrapファイルが読み込まれるようにimport
させます。
つまり、わざわざCSSの記述を個別に書くのではなく、bootstrapをimportして全てのファイルで読み込まれるapplication.scssファイルで読み込むことで、全てのページでbootstrapが適応されることになります。
//カスタムブートストラップ変数は、ブートストラップの前に設定またはインポートする必要があります。 // Custom bootstrap variables must be set or imported *before* bootstrap. @import "bootstrap" ;
※注意点
- Sassファイルでは
*= require
、*= require_tree
を削除する - Sassファイルではインポートに
@import
を利用する - Sassファイルで
*= require
を利用すると他のスタイルシートではBootstrapのmixinや変数を利用できなくなる
application.js(マニフェストファイル)
Bootstrapと依存関係をapplication.jsに追記します。
# どのアセットファイルを読み込むかを記述する //= require jquery3 //= require popper //= require bootstrap-sprockets
- Bootstrapのtooltipsやpopoverは配置を
popper.js
に依存しているので、importする必要があります。 - bootstrapの依存gemに
popper_js
が指定されているため新たにインストールは不要です。(自動でインストール済み) Bootstrap gemはpopper_jsに依存してます。 コンパイルを高速化したい場合は
bootstrap-sprockets
の代わりにbootstrap
を指定します。popover(ポップオーバー)
とは? 対象の要素をクリックしたときに小さな領域を表示するJavascriptです。対象の要素をもう一度クリックすると表示が消えます。tooltips(ツールチップス)
とは? ツールチップは、ユーザーがオブジェクトの上にカーソルを置くと自動的に表示され、クリックしたりカーソルを移動したり、ある程度時間が経過したら画面から消えます。 補足的な説明など、さらに情報を加えたほうがわかりやすいときに使われます。
参照
GitHub - twbs/bootstrap-rubygem: Bootstrap 4 rubygem for Rails / Sprockets / Hanami / etc
Railsアプリで Bootstrap 4 を利用する - Qiita
Bootstrapのレスポンシブとは何か?使い方の流れもあわせて紹介 | #site_titleBootstrapのレスポンシブとは何か?使い方の流れもあわせて紹介
font-awesomeとは?Railsアプリケーションで、font-awesome-sassというgemライブラリをアプリケーションにインストールする
font-awesomeとは?
Font Awesomeとは、Viewファイルで特定の文字列を指定して、ライブラリで用意されている
アイコン
(webアイコンフォト
)を表示することを可能にしたツールです。
例えば、
コード内に、
<i class='fa fa-check'></i>
という文字(=コード)を記述することで、「✔️」というアイコンを表示させることができるようになるのです。
Webアイコンフォントとは?
ウェブページ上で文字と同じように表示できるアイコンのことで、Font Awesomeで用意されています。通常のアイコンは画像なので拡大するとぼやけてしまいますが、画像でアイコンを貼るのと違い、拡大してもぼやけませんし、cssを使って色もサイズも簡単に変えることができます。
font-awesome-sassとは?
font-awesome-sassとは、無料で使えるwebフォントアイコンであるFont Awesomeを簡単にrailsで使えることができるようになるgemです。
font-awesomeの導入からwebアイコンを表示させるまで
手順
手順1. font-awesome-sassgemライブラリをインストール
① Gemfileに追記する
gem 'font-awesome-sass', '~> 5.12.0'
gem 'font-awesome-rails'
では、font-awesome5系に対応していないので gem 'font-awesome-sass'
を使用する必要があります。
$ bundle insall
② マニフェストファイルでfont-awesomeを読み込ませる(import)
font-awesomeをマニフェストファイルであるapp/assets/stylesheets/application.scss
に読みこませる。
@import "font-awesome-sprockets"; @import "font-awesome";
font-awesome-sprocketsファイル
には、フォントファイルへのパスを見つける機能が入っています。ですので、importする必要があります。つまり、これをimportしてしまえば、自動でフォントファイルを探してくれるので、一つ一つフォントファイルをimportする必要がなくなり便利です。- scssファイルには
*= require
などのSprocketsディレクティブの記載が残っていると、@import
で定義した内容がうまく読み込めずbootstrapが反映されないので注意してください。
//= requireと@importの違い
どちらもマニフェストファイル
で、アセットファイルを読み込み結合するために記述します。
//= とは?
JSのマニュフェストファイル
では//=
で始まる行をアセットパイプラインに指示を与えるための特別な行として扱っています。
//= requireとは?
指定したJSファイル
の内容を記述した位置に取り込みます。(拡張子は省略できます。)
//=require_treeとは?
JSファイル
で指定されたディレクトリ配下の前ファイルの内容を結合し、記述した位置に取り込みます。「.」
と記述すると指定されたディレクトリ配下のの全ファイルの内容を結合します。
※この記述は一番下に記述することが大切です。
ディレクティブは記載した順に実行されますが、require_treeでインクルードされるファイルの読み込み順序は指定できません。従って、特定の読み込み順に依存しないようにする必要があります。もしどうしても特定のJavaScriptファイルを他のJavaScriptファイルよりも結合順を先にしたい場合、そのファイルへのrequireディレクティブをマニフェストの最初に置きます。requireおよび類似のディレクティブは、出力時に同じファイルを2回以上インクルードしないようになっています。[Railsガイドより]
例えば、以下の場合
//= require jquery3 //= require popper //= require bootstrap-sprockets
//= require jquery3
よりも前に//= require_tree .
を記載した場合、//= require_tree .
で読み込んだファイルでjqueryのコードを参照しているとjquery3が読み込まれる前に評価されるためメソッドが未定義となりエラーになるケースが発生します。
そのため、//= require_tree .
は一番下の行に記載している必要があります。
@importとは?
SCSSのマニフェストファイルで読み込むアセットファイルを指定する場合に使用します。
//= requireと@importまとめ
- //= require →
JSマニフェストファイル
で使用 - @import →
SCSSマニフェストファイル
で使用
手順2. Font Awesomeを使って、Webアイコンの表示させる
Font Awesomeの使い方
Font Awesomeのアイコンはビューファイルで下記のように記述すると表示させることができます。
<i class="接頭辞名 fa-アイコン名"></i>
接頭辞名はversion5から5種類になり、アイコンごとに異なります。
① 使いたいアイコンフォントを探す
アイコン一覧から使いたいアイコンを選びます。アイコンが決まったら、使いたいアイコンをクリックします。
② アイコンフォントのコードをコピー
アイコンの詳細ページが開きます。下にスクロールして、というコードをまるっとコピーします。
③ アイコンを表示させたい位置に貼付け
コピーしたコードをHTML内のアイコンを表示させたい位置に貼り付けます。これだけで以下のようにアイコンフォントを使うことができます。
<p><i class="fab fa-twitter"></i>ここにアイコンを表示</p>
これで、ツイッターのアイコンが表示されるようになります。
その他の操作
アイコンの大きさを変える
<i class="fas fa-tasks fa-lg"></i>
FontAwesomeでは、アイコンの大きさを簡単に変えることができます。以下のコードを
i class="〜"
内に書くことでサイズを大きくすることができます。
- fa-lg (1.333…倍)
- fa-2x (2倍)
- fa-3x (3倍)
- fa-4x (4倍)
- fa-5x (5倍)
<p><i class="fas fa-bomb fa-lg"></i></p> <p><i class="fas fa-bomb fa-2x"></i></p> <p><i class="fas fa-bomb fa-3x"></i></p> <p><i class="fas fa-bomb fa-4x"></i></p> <p><i class="fas fa-bomb fa-5x"></i></p>
ヘルパーメソッドicon
アイコンの表示の記述を簡単に書くことができるヘルパーメソッドです。
icon('接頭辞名', 'アイコン名') # 例 <%= icon('far', 'clock') %>
上のコードは下記のコードにコンパイルされます。
<i class="far fa-clock"></i>
詳しい使い方は、以下参照↓
参考
GitHub - FortAwesome/font-awesome-sass: Font-Awesome Sass gem for use in Ruby/Rails projects
Ruby on Rails のgemとは?
gemとは?
Railsの開発では、利用したいgem
ライブラリをGemfile
という定義ファイルに記載して、$bundle install
コマンドでgemfileに記載したgemライブラリのソースコードを取得(インストール)します。
Gemfileに記載したライブラリ(gemライブラリ)をbundler
と言うパッケージ管理ツールでインストールすることで、様々なライブラリのバージョンや依存関係を管理して、扱いやすくしてくれます。
もしこのbundler
が無ければ、都度gem install ライブラリ名でバージョンを指定して、ライブラリ同士のエラーが出ないようにライブラリのバージョンを手動で管理しなければなりません。
Gemをインストールする際に、Gemのバージョンを確認する方法
RubyGems.org | your community gem host
↑公式のGemを検索するrubygems
セッション / クッキー
認証機能とは?
認証機能とは、ユーザの情報を検証して、システムへのログインやユーザの有効性確認を行うための機能です。
そしてこの認証機能の中でも、特に使用頻度が高いのが、ログイン機能でしょう。 では、ユーザーがログインしている / していないを、システム的にはどのように判定しているのでしょうか。 これには、セッションと呼ばれる仕組みを利用しています。
セッションとは?
セッションとは、Webサイトにアクセスして行う一連の行動のことを指し、ページを跨いで情報を保持したい場合に利用される機能です。
webページ閲覧時に用いられるプロトコルをHTTPプロトコルと呼ぶのですが、このHTTPプロトコルは、以前の通信を記憶しておく術を持ち合わせていません。(これを、ステートレスなプロトコル と呼んだりします。) つまり、ログイン後、次のページを見たいという通信を行う際には、このHTTPプロトコルは、ユーザーがログインしていることを忘れてしまっているのです。
そこで、セッションの出番です。 セッションは、ページを遷移しても変わらず情報を保持することができるため、このセッションにログイン中のユーザーの情報を格納しておくことによって、ページを遷移しても、変わらずログイン状態を維持し続けることができるのです。
※プロトコルとは、コンピューター同士が通信をする際の手順や規約などの約束事のことを指します。
webアプリケーションでは、アプリケーションサーバー側にセッションという仕組みを用意しており、1つのブラウザから連続して送られる一連のリクエスト間で状態を共有できます。セッションの情報はRails標準では、ブラウザ側のクッキーに保存されます。また、sessionは明示的に削除する(又は有効期限切れになる)まで消えません。
Railsアプリケーションにはユーザーごとにセッションが設定されます。前のリクエストの情報を次のリクエストでも利用するためにセッションに少量のデータが保存されます。あらゆるセッションは、暗号化されたセッション固有のID(セッションID)をcookieに保存します。Railsでセキュリティ上の理由からセッションIDをURLで渡すことは許可されていません。そのため、セッションIDは必ずcookieで渡すようにしているのです。
Action Controller の概要 - Railsガイド
cookieとは?
ブラウザとwebサーバー間でやりとりされる時に使われる仕組みです。cookieでは、webサーバーからブラウザへHTTPレスポンスを返す際に、何らかのcookie情報を含めて送ります。cookie情報はキーと値(value)のペアの集合です。ブラウザはこのcookieの情報をサーバーのドメインなどの情報に紐付けて保存し、次回以降、同じドメインのサーバーへのHTTPリクエスト時に、ブラウザで保管しておいたcookie情報をリクエストに添えて送ります。 そうすることにより、webサーバーはどのブラウザからのリクエストかを識別することが出来るのです。つまり、cookieは複数のリクエストの間で共有したい状態をブラウザ側に保存する仕組みです。
クッキーは平文
セッションIDは暗号化されたもの
Railsの場合、config/initializer/session_store.rb
にて、セッション情報をどこに保存するのかが指定されています。デフォルトでは、
# セッション情報をどこに保存するのかを設定 # _○○_sessionというkeyで、cookieを用いてセッション情報を管理する Rails.application.config.session_store :cookie_store, key: '_○○_session'
という設定がなされています。
cookieとは、webブラウザが保持する情報のことです。webでは毎回ページを読み込む度にブラウザとサーバーとの間で通信がなされており、このcookieもリクエスト、レスポンスの度に毎回やりとりがなされます。
つまり、セッション情報の保存先をcookieにするということは、
- ログイン時に、ユニークなセッション情報を発行
- それをサーバ : ブラウザ間の通信の度に、cookie内でやりとり
- cookieを受け取ったサーバは、cookie内のセッション情報を元に今リクエストを送ってきているユーザがログイン中か否かを判定
という流れを経ているのです。 但し、cookieに全てのセッション情報が載ってしまうということは、比較的簡単にセッション情報を確認できてしまうことも意味します。
↓Railsのセッション管理方法について
Rails4系からはcookieに載るセッション情報が暗号化されたとは言え、秘密鍵を知っていれば誰でもログイン情報を復元できてしまう恐れがあるのです。ですので、よりセキュリティを強固にしたい場合、このセッションの管理先をredisなどのKVSデータベースに指定したりなどの方法を取る場合もあります。
今回はsorceryは上記で説明した、ログインに必要なことをほぼ自動的にやってくれます。
↓sessionの保存先をcookieからKVSに変更する理由
セッションを保存するとき、なぜ、Cookieではなくmemcachedやredisを使用するのでしょうか?
※KVSとは、キーバリューストア(Kye-Value Store)の略で、保存項目がkeyとvalueのみのDBのことを指します。
参照
sorceryって何??sorceryを使った、ユーザー登録、ログイン&ログアウト機能の実装からsorceryとはなんぞやを調べてみた。
sorceryとは?
sorceryとは、ユーザ認証機能を簡単に実装できるライブラリ(gem)です。同じように認証機能を提供してくれているものとしてdeviseなどが挙げられますが、sorceryの方がよりシンプルで、カスタマイズ性に富んでいるという特徴を持ちます。
ユーザの認証の基本的な機能であるパスワード認証
を始め、
- User Activation
- Reset Password
- Remember Me
- Session Timeout
- Brute Force Protection
- Basic HTTP Authentication
- Activity Logging
といった機能が揃っていて、必要な機能を選んで使うことができます。
間違えやすい点としては、Sorceryはログイン認証機能を実装する為のGemであり、ログイン認証機能自体はSorceryが提供するメソッドによって実現されます。 まとめると、SorceryというGemをRailsにインストールすると、Sorceryが提供する様々なログインに関するメソッドを使えるようになるということです。
[引用:【Rails】駆け出しVimmerがSorceryをざっくり説明してみた]
Sorceryをインストールして、ユーザー登録機能を実装する
1 RailsアプリケーションのGemfileにsorceryを追加します。
gem 'sorcery'
2 コマンドラインで、bundle installしコマンドを実行し、Gemfileに記載したSorceryGemをインストールします。
$ bundle install
3 **Sorceryによって追加されたジェネレーターを実行して、Sorcery Gemを使ったアプリの構築を開始します。
まず、Sorceryが提供するジェネレータbundle exec rails g sorcery:install
を実行し、Userモデルとmigrationファイルを生成します。**
$ bundle exec rails g sorcery:install
上記のコマンド実行後、次のファイルが作成されます。↓
- app/models/user.rb(userモデル)
- config/initializers/sorcery.rb(initializersファイル)
- db/migrate/yyyymmddhhmmss_sorcery_core.rb(migrationファイル)
4 rake rails db:migrateを実行して、usersテーブルを生成します。
$ rake db:migrate
5 以下のコマンドをターミナル上で実行して、Userモデルに対応したビューとコントローラを作成します。
同時に、userテーブルにstring型のemailカラムとstring型のcrypted_password(暗号化されたパスワード)カラムとstring型の※saltカラムを作成します。
$ rails g scaffold_controller user email:string crypted_password:string salt:string
仮想属性とは? 例えば今回のように、databaseのusersテーブルがあるとします。ユーザー情報を登録するusersテーブルにはpasswordというカラムはなく、password〇〇や、〇〇password といった暗号化されたパスワードを入れるようになっています。今回はcrypted_passwordカラムに暗号化されたパスワードが入るようになっています。 そして、crypted_passwordカラムにパスワードを暗号化して入れるためにpassword属性とpassword_confirmation属性という仮想属性を作っているのです。仮想属性にパスワードを入れてsaveすると、暗号化されたものが実際にcrypted_passwordカラムに入ります。 つまり、DBのテーブルにパスワードを保存するために仮想属性が必要になるということです。 実際には、DBに存在しない属性(カラム)であることから、仮想属性と呼ばれます。 params.permit(:password) するときに、password= というsetter methodがないとエラーになりますので atter_accessorを使って、getter、setterの仮属性定義が必要です。
※password_confirmation(パスワードコンファーメイション)とは、データベースに保存されない仮想の属性で、パスワードの入力確認に使われます。
この属性を使用するとpasswordとpassword_confirmationの双方が一致しているかのバリデーションが自動で追加されます。
現在パスワードの保管方法は、単にパスワードをハッシュ化して、暗号化したものを保管するのではなく、元のパスワードの文字列に別の文字列(ソルト)を付け加えることで文字列全体を長くしてから、繋げた文字列をまとめてハッシュ化したものをDBに格納しています。そうすることで、よりセキュリティを高めることができるのです。DBにはソルトとハッシュ値を保存しています。ハッシュ化(パスワード文字列+ソルト)=ハッシュ値
6 暗号化されたパスワードやソルトをユーザーに編集/閲覧させることはセキュリティ上、望ましくないため、ビューでこれらの属性を表示させないようにします。
ビューであるapp / views / users /のすべてのテンプレートからこれらの属性を削除します。
7 UsersControllerでStrong parameterを定義してフォームの特定の属性の値を取得できるように設定します。
class UsersController < ApplicationController # ... private def user_params # paramsオプジェクトとして受け取れる値は、userテーブルのemail属性、password属性、password_confirmation属性の値のみと設定。 # ここで、password属性、password_confirmation属性の2つの属性は仮想属性であり、実際にはDBに存在しない属性です。passwordとpassword_confirmationの双方の値が一致しているか確認した後、暗号化されたものがDBに保存されます。 params.require(:user).permit(:email, :password, :password_confirmation) end end
8 暗号化されたパスワードがDBに保存される前に、ユーザーが入力したパスワードをフォームで受け取るために仮想フィールドをビュー(今回はビューテンプレート)に追加する必要があります。
# app/views/users/_form.html.erb <div class="field"> <%= form.label :password %><br /> <%= form.password_field :password %> </div> <div class="field"> <%= form.label :password_confirmation %><br /> <%= form.password_field :password_confirmation %> </div>
9 Userモデルに以下の記載をします。validates :password, confirmation: trueをUserモデルに設定することで、Userモデルにpassword属性とpassword_confirmation属性が定義されます。
(この2つはuserテーブルのcrypted_passwordカラムに紐づくUserモデルの仮想属性です。) この2つの仮想属性は暗号化されてから、userテーブルでcrypted_passwordカラムに変更されるようになっています。
# app/models/user.rb class User < ActiveRecord::Base authenticates_with_sorcery! validates :password, length: { minimum: 3 }, if: -> { new_record? || changes[:crypted_password] } validates :password, confirmation: true, if: -> { new_record? || changes[:crypted_password] } validates :password_confirmation, presence: true, if: -> { new_record? || changes[:crypted_password] } validates :email, uniqueness: true end
10 最後に、ルーティングを定義します。
# config/routes.rb root :to => 'users#index' resources :users
アプリを実行し、http://localhost:3000/usersにアクセスすると、ユーザー新規登録ページに遷移し、そこで新しいユーザーを作成できます。Soceryを使用しているため、パスワードは自動的に暗号化され、ソルトも自動作成されます。
Sorceryを使って、ログイン・ログアウト機能を実装する
1 . ユーザーのログイン状態を維持し続けるために、以下のコマンドをターミナル上で実行します。このコマンドを実行することで、ユーザーのログインとログアウトに対応したコントローラとビューが作成されます。ログインとログアウト機能で、セッションを使用するので、コントローラー名をUserSessionsと設定しています。
$ rails g controller UserSessions new create destroy
2 . 上記で作成したコントローラーにログインとログアウト処理をメソッドとして記載します。
# app/controllers/user_sessions_controller.rb class UserSessionsController < ApplicationController # ログイン処理 def create # loginメソッドを使って、paramsで取得したemailによるUser検索、パスワードの検証を行い、正常に処理できるとセッションデータにUserレコードのid値を@userに格納する @user = login(params[:email], params[:password]) if @user # @userがnullではない時、ログインできている時 # ログインが成功すると、ログイン成功のフラッシュメッセージを表示するとともに、ユーザーが要求したページにリダイレクトする。 redirect_back_or_to(:users, notice: 'Login successful') else # @userがnullの時、ログインできていない時 # ログインに失敗すると、ログイン失敗フラッシュメッセージを表示して、新規登録ページに遷移する。 flash.now[:alert] = 'Login failed' render action: 'new' end end # ログアウト処理 def destroy # logoutメソッドでセッションをリセットする logout redirect_to(:users, notice: 'Logged out!') end end
loginメソッドで、認証処理が行われる。 @user = login(params[:email], params[:password])でemailによるUser検索、パスワードの検証を行い、正常に処理できるとセッションデータにUserレコードのid値を格納する、という処理が行われている。
logoutメソッドで、セッションをリセットする。
redirect_back_or_toメソッド・・・保存されたURLがある場合そのURLに、ない場合は指定されたURLにリダイレクトします。ユーザーがリクエストしたURLがあるときはそのURLにリクエストを、リクエストURLがない場合は、指定されたURLにリダイレクトします。 例えば、掲示板ページにアクセスしようとしたユーザにログインを要求する場合、require_loginメソッドでユーザをログインページに誘導し、ログインが成功したら、最初に訪れようとしていた掲示板ページにリダイレクトさせるということが可能になる。
3 . ログインフォームを作成する
# app/views/user_sessions/new.html.erb <h1>Login</h1> <%= render 'form' %> <%= link_to 'Back', users_path %>
# app/views/user_sessions/_form.html.erb <%= form_with url: login_path, method: :post do |f| %> <div class="field"> <%= f.label :email %><br /> <%= f.text_field :email %> </div> <div class="field"> <%= f.label :password %><br /> <%= f.password_field :password %> </div> <div class="actions"> <%= f.submit "Login" %> </div> <% end %>
4 . ルーティングを定義する
# config/routes.rb root :to => 'users#index' resources :users get 'login' => 'user_sessions#new', :as => :login post 'login' => "user_sessions#create" post 'logout' => 'user_sessions#destroy', :as => :logout
5. 現在は、ログアウトしているユーザーでもログインしているユーザーと同じような操作が出来てしまうので、操作の前にログイン認証
を行うようにします。ただし、ログアウト時でもできる操作に関しては、Skip処理
をすることで、ログイン認証を行わず、操作ができるように設定します。
# app/controllers/application_controller.rb # 全てのアクション実行前にログイン認証を必須とする。 before_action :require_login
# app/controllers/users_controller.rb # index, new, createアクション実行時のみ、ログイン認証処理を必須としない。 skip_before_action :require_login, only: [:index, :new, :create]
# app/controllers/user_sessions_controller.rb # new, createアクション実行時のみ、ログイン認証を必須としない skip_before_action :require_login, only: [:new, :create]
6 . ログインしていないユーザーがログインユーザー専用のページにアクセスするのを防ぐため、以下のコードをapplication_controller.rbに記載します。そうすることで、もしログインしていないユーザーがログインユーザー専用のページにアクセスした際、ログインページに遷移します。
# app/controllers/application_controller.rb private def not_authenticated redirect_to login_path, alert: "Please login first" end
sorceryを使うと使用できるようになるメソッド
require_login
ログインをしていないユーザーをアクション単位で弾く。アクセスしようとしたURLをセッションに格納し、
not_authenticated
を実行するメソッド。以下のようにbefore_action
で指定する。アクションごとに変える場合は、only: :action
を付ける。アクション内の分岐など、もっと細かい単位で弾きたい場合は後述のlogged_in?
を使う。
sorceryのモジュール内に定義されているメソッドで、sorcery gemをインストールすることによって、使えるメソッドになる。ApplicationController内に定義することで、全てのアクション実行前に使えるようになる。
before_action :require_login
not_authenticated
先ほどの
require_login
内で、このメソッドも実行される。デフォルトではredirect_to root_path(自動的にルートに飛ばされる)と定義されているが、カスタマイズしたい場合はapplication_controller
で上書きをする。
class ApplicationController < ActionController::Base protected def not_authenticated redirect_to login_url, alert: 'ログインしてください' end end
current_user
現在ログイン中のuserを返す。コントローラ、ビューで使える。
logged_in?
現在ログイン中かどうか、true or falseで返す。コントローラ、ビューで使える。ログインしているかどうかによって場合分けをしたいときに使うことが多い。
今回は、ヘッダーの表示をログインしているか、ログインしていないかで場合分けするために、logged_in?メソッドを使い、実装しました。
<% if logged_in? %> <%= link_to 'プロフィール', user_url(current_user) %> <% else %> <%= link_to 'ログイン', login_url %> <% end %>
sorceryを使わないで、ログインの有無による、表示分けを行う時は、以下を参照
【Sorcery】Sorceryで使えるようになるメソッドとその活用例 - Qiita
参考
Simple Password Authentication · Sorcery/sorcery Wiki
GitHub - Sorcery/sorcery: Magical Authentication
GitHub - heartcombo/devise: Flexible authentication solution for Rails with Warden.
【Rails】駆け出しVimmerがSorceryをざっくり説明してみた
第16回 データベースからパスワードが盗まれても問題がなくなる方法