assetsフォルダの画像とpublicフォルダの画像とセレクタの部分一致

assetsフォルダの画像とpublicフォルダの画像とセレクタの部分一致

rspecを記述している時に、画像の表示をテストする際にsrc属性の値をチェックする際に少しハマった事があったので、こちらにまとめます。

・[public]フォルダに画像を保存した時
[public]フォルダに画像を保存すると、通常は以下のようなHTMLになる。
[public/default.jpg]に画像を保存した場合

[htmlファイル]

<img src="/default.jpg"> ①

※ポイント

viewファイルに記載する時のパスは、以下のようになる。

[viewファイル]

= image_tag '/default.jpg'

ファイルのパスは、/から記載する。

ブラウザに表示されるhtmlのsrc属性は、①のようにファイル名がそのまま表示される。

・[assets/images]フォルダに画像を保存した時 [assets/images]フォルダに画像を保存すると、通常は以下のようなHTMLになる。
[assets/images]に画像を保存した場合

[htmlファイル]

<img src="/assets/cooking_memory/default-c11415b5b99233bc64bbedd7a2d6870611196c7bcd9b5a4bfe8dcd5ece0ade65.jpg"> ②

※ポイント

viewファイルに記載する時のパスは、以下のようになる。

[viewファイル]

= image_tag 'default.png'

/から記載せずにそのままパスを記載する。

ブラウザに表示されるhtmlのsrc属性は、②のようにファイル名がハッシュになっている。

RSpecのテスト時
RSpecで画像の表示をテストする場合は、以下のようになる。

・[public]フォルダに画像が保存されている時

[specファイル]

expect(page).to have_selector("img[src$='default.jpg']")

$を記載する事で、属性の値がdefault.jpgで終わるものになる

・[assets/images]フォルダに画像が保存されている時

[specファイル]

expect(page).to have_selector("img[src*='default.jpg']")

*を記載する事で、属性の値にdefault.jpgを含むもの

※ポイント
セレクタの部分一致

前方一致 E[foo^="bar"] foo属性の値がbarで始まるE要素

後方一致 E[foo$="bar"] foo属性の値がbarで終わるE要素

部分一致 E[foo*="bar"] foo属性の値にbarを含むE要素

アプリが元々保持する画像は、[app/assets/images]フォルダに保存するのが推奨!!

参考記事

セレクタの部分一致について - Qiita

モデルのrspec

モデルのrspecテスト

モデルのrspecのテストは、以下の3種類をテストするのが一般的です。
・バリデーションのテスト ・モデルのインスタンスメソッドのテスト ・モデルのクラスメソッドのテスト

参考記事

【Ruby on Rails】RSpecのModel(モデル)テスト書き方サンプル - にょけんのボックス

ビューファイルでの日時のフォーマット

ビューファイルでの日時のフォーマット

ビューファイルでの日時のフォーマット形式について、備忘録としてこちらにまとめます。

下記のようになっています。

[db/schema.rb]

  create_table "cooking_memories", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t|
    t.string "cooking_name", null: false
    t.string "fish_name", null: false
    t.date "cooking_date"
    t.text "memo"
    t.bigint "user_id", null: false
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.index ["user_id"], name: "index_cooking_memories_on_user_id"
  end
[1] pry(main)> cooking_memory = CookingMemory.last
  CookingMemory Load (2.2ms)  SELECT `cooking_memories`.* FROM `cooking_memories` ORDER BY `cooking_memories`.`id` DESC LIMIT 1
=> #<CookingMemory:0x00007fefe7b7e060
 id: 25,
 cooking_name: "アジフライ",
 fish_name: "アジ",
 cooking_date: Fri, 06 May 2022,
 memo: "アジフライを作りました。",
 user_id: 1,
 created_at: Fri, 06 May 2022 01:19:57 JST +09:00,
 updated_at: Fri, 06 May 2022 01:19:57 JST +09:00>
[2] pry(main)> cooking_memory.cooking_date
=> Fri, 06 May 2022
[ビューファイル]

= l cooking_memory.cooking_date
[config/locales/activerecord/ja.yml]

ja:
  activerecord:
    models:
      cooking: '料理'
      fish: '魚'
      handle: '捌き方'
      user: '会員者'
    attributes:
      cooking:
        name: '料理'
      fish:
        kind: '魚の種類'
      handle:
        pattern: '捌き方'
      user:
        name: 'ニックネーム'
        email: 'Eメール'
        password: 'パスワード'
        password_confirmation: 'パスワード再確認'
      cooking_memory:
        cooking_name: '料理名'
        fish_name: '魚の種類'
        cooking_date: '調理をした日'
        cooking_memory_image: '料理の画像'
        memo: 'メモ欄'
  time:
    formats:
      default: '%Y年%m月%d日'

ブラウザには、以下のように表示されています。

Image from Gyazo

指定しているフォーマットとは、別なフォーマットで表示されてしまいます。。。

ビューファイルをstrftimeメソッドを使って以下のようにすると指定した通りのフォーマットで表示されます。

[ビューファイル]

= cooking_memory.cooking_date.strftime("%Y年%m月%d日")

Image from Gyazo

下記のように翻訳ファイルを書き換えたところ、ビューファイルでlメソッドを使っても指定した通りの日時のフォーマットになりました。

[config/locales/activerecord/ja.yml]

ja:
  activerecord:
    models:
      cooking: '料理'
      fish: '魚'
      handle: '捌き方'
      user: '会員者'
    attributes:
      cooking:
        name: '料理'
      fish:
        kind: '魚の種類'
      handle:
        pattern: '捌き方'
      user:
        name: 'ニックネーム'
        email: 'Eメール'
        password: 'パスワード'
        password_confirmation: 'パスワード再確認'
      cooking_memory:
        cooking_name: '料理名'
        fish_name: '魚の種類'
        cooking_date: '調理をした日'
        cooking_memory_image: '料理の画像'
        memo: 'メモ欄'
  date:
    formats:
      default: '%Y年%m月%d日'

Image from Gyazo

※ポイント
そもそもlメソッドと翻訳ファイルの記述の仕方の認識が曖昧だったため、こちらにまとめます。

lメソッドは、localizeメソッドの略で、DateオブジェクトやTimeオブジェクトをconfig/locales/以下の翻訳ファイルに設定した日時のフォーマットに変換することができる。

翻訳ファイルは、記述の仕方が決まっていて日時の場合は、以下のようになる。

ja:
  date:
    formats:
      default: "%Y/%m/%d"
      long: "%Y年%m月%d日"
      short: "%m/%d"
  time:
    formats:
      default: "%y/%m/%d %H:%M"

翻訳ファイルのdate以下は、Dateオブジェクトの時に読み込まれる。
翻訳ファイルのtime以下は、Timeオブジェクトの時に読み込まれる。
lメソッドを使う際に第二引数を指定しないとdefault部分が読み込まれる。
lメソッドを使う際に第二引数を指定すると、default以外の部分が使える。(以下が使い方の例)

[1] pry(main)> I18n.l(Date.today, format: :long)
=> "2022年05月06日"

参考記事

Rails で date型カラムの view 表記を l メソッドのオプションで変更する - Just do IT

【Rails】 I18n入門書~日本語化対応の手順と応用的な使い方 | Pikawaka

simple_formatの使い方

simple_formatの使い方

simple_formatの使い方について調べたので、こちらにまとめます。

ブラウザで下記のように登録する
Image from Gyazo

DBには、下記のように保存されている。

memo: "アジフライ美味しい\r\nアジフライ美味しい\r\n<h1>アジフライ美味しい</h1>\r\n<h2>アジフライ美味しい</h2>\r\n\r\nアジフライ美味しい\r\n<script>alert(‘XSSできます’)</script>"

以下にビューファイルで記述したパターンと、それでブラウザに表示されるパターンとエスケープ処理された記述(ページのソースの表示)とHTMLの表示を書きます。

[simple_format]を使った場合

[ビューファイル]

= simple_format(cooking_memory.memo)

ブラウザで以下のように表示される(登録時のHTMLタグがHTMLのタグとして機能している)
Image from Gyazo

下記のように読み込まれている(ページのソースの表示)

<p>アジフライ美味しい
<br />アジフライ美味しい
<br /><h1>アジフライ美味しい</h1>
<br /><h2>アジフライ美味しい</h2></p>

<p>アジフライ美味しい
<br />alert(‘XSSできます’)</p>

ブラウザでは、下記のようなHTMLになっている

<p>
  “アジフライ美味しい”
  <br>
  “アジフライ美味しい”
  <br>
</p>
<h1>アジフライ美味しい</h1>
<br>
<h2>アジフライ美味しい</h2>
<p></p>
<p>
  “アジフライ美味しい”
  <br>
  “alert(‘XSSできます’)”
</p>

XSSなどの恐れのある<script>タグを除去して、登録時に改行などした部分がDB上では\r\nなどのようになっているからこれを<p>タグや<br>タグなどにして、実際に登録した時と同じような改行をしてブラウザに表示してくれる。

そのまま記述した場合

[ビューファイル]

= cooking_memory.memo

ブラウザでは、以下のように表示される
Image from Gyazo

下記のように読み込まれている(ページのソースの表示)

アジフライ美味しい
アジフライ美味しい
&lt;h1&gt;アジフライ美味しい&lt;/h1&gt;
&lt;h2&gt;アジフライ美味しい&lt;/h2&gt;

アジフライ美味しい
&lt;script&gt;alert(‘XSSできます’)&lt;/script&gt;

上記のように<h1>タグや<h2>タグ、<script>タグがエスケープされて違う文字に置き換えられているのが分かる。

ブラウザでは、下記のようなHTMLになっている

"アジフライ美味しい
アジフライ美味しい
<h1>アジフライ美味しい</h1>
<h2>アジフライ美味しい</h2>

アジフライ美味しい
<script>alert(`XSSできます`)</script>"

XSSなどの恐れのある<script>タグやHTMLタグをエスケープ処理して、それらのタグがブラウザ上には文字として認識されてそのタグが文字として表示されている。
登録時に改行などした部分がDB上では\r\nなどのようになっているがブラウザ上には、改行されずそのまま表示される。
Railsでは、<%= =>を使って出力する場合は、自動的にエスケープ処理してくれる。

[html_safe]を使った場合

[ビューファイル]

= cooking_memory.memo.html_safe

ブラウザでは、以下のように表示される
Image from Gyazo

下記のように読み込まれている(ページのソースの表示)

アジフライ美味しい
アジフライ美味しい
<h1>アジフライ美味しい</h1>
<h2>アジフライ美味しい</h2>

アジフライ美味しい
<script>alert(`XSSできます`)</script>

上記のように<h1>タグや<h2>タグ、<script>タグがエスケープされずにそのままタグとして読み込まれている

ブラウザでは、下記のようなHTMLになっている

"アジフライ美味しい アジフライ美味しい"
<h1>アジフライ美味しい</h1>
<h2>アジフライ美味しい</h2>
"アジフライ美味しい"
<script>alert(`XSSできます`)</script>

<script>タグやHTMLタグをエスケープ処理せずにそのままタグとして読み込んでいる。 改行した際にDBには、\r\nとなるがこれは改行などをしてくれるタグには変換してくれないので、ブラウザ上には改行されないまま表示される。

[h]メソッドを使った場合

[ビューファイル]

= h(cooking_memory.memo)

ブラウザでは、以下のように表示される
Image from Gyazo

下記のように読み込まれている(ページのソースの表示)

アジフライ美味しい
アジフライ美味しい
&lt;h1&gt;アジフライ美味しい&lt;/h1&gt;
&lt;h2&gt;アジフライ美味しい&lt;/h2&gt;

アジフライ美味しい
&lt;script&gt;alert(`XSSできます`)&lt;/script&gt;

上記のように<h1>タグや<h2>タグ、<script>タグがエスケープされている

ブラウザでは、下記のようなHTMLになっている

"アジフライ美味しい
アジフライ美味しい
<h1>アジフライ美味しい</h1>
<h2>アジフライ美味しい</h2>

アジフライ美味しい
<script>alert(`XSSできます`)</script>"

<script>タグやHTMLタグをエスケープ処理している。
改行した際にDBには、\r\nとなるがこれは改行などをしてくれるタグには変換してくれないので、ブラウザ上には改行されないまま表示される。
[h]メソッドの代わりに以下のように記述しても同じ効果になる。

= html_escape(cooking_memory.memo)

※ポイント

以下のように記述すれば、サニタイズもしてくれて改行で登録した文章を表示させる際も改行してくれる。

[ビューファイル]

= simple_format(h(cooking_memory.memo))

ブラウザでは、以下のように表示される
Image from Gyazo

下記のように読み込まれている(ページのソースの表示)

<p>アジフライ美味しい
<br />アジフライ美味しい
<br />&lt;h1&gt;アジフライ美味しい&lt;/h1&gt;
<br />&lt;h2&gt;アジフライ美味しい&lt;/h2&gt;</p>

<p>アジフライ美味しい
<br />&lt;script&gt;alert(`XSSできます`)&lt;/script&gt;</p>

上記のように<h1>タグや<h2>タグ、<script>タグがエスケープされている
改行部分などに<p>タグや<br>タグなどが入っている。

ブラウザでは、下記のようなHTMLになっている

<p>
  “アジフライ美味しい”
  <br>
  “アジフライ美味しい”
  <br>
  “<h1>アジフライ美味しい</h1>;
  <br>
  “<h2>アジフライ美味しい</h2>”
</p>
<p>
  “アジフライ美味しい”
  <br>
  “<script>alert(`XSSできます`)</script>
</p>

<script>タグやHTMLタグをエスケープ処理している。
改行した際にDBには、\r\nとなるがこれを<p>タグや<br>タグなどにしてくれている。

参考記事

HTML特殊文字のエスケープ - Ruby on Rails入門

Ruby On Rails ピチカート街道 - h( ... ) でHTMLエンコード -

[Rails5]simple_format, h, html_safeを色々試してみた | ゆるりテックブログ

ActiveStorageの画像の保存先

ActiveStorageの画像の保存先

ActiveStorageの画像の保存先が分からず調べたので、備忘録としてこちらにまとめます。

[carrierwave]Gemを使って画像をアップロードした時は、下記のようにpublic/uploadsフォルダ以下に画像が保存されます。
Image from Gyazo

しかしActiveStorageを使ってファイルをローカルに保存する設定をした時に、アップロードしたファイルがディレクトリのどこにも見つからない。。。
調べると、blob型として画像をテーブルに保存しているようだ。

blob型とは?
blob型:データベースで用いられるデータ型の1つで、テキストや整数のように既存のデータ型としては用意されていない任意のバイナリデータを格納できる。(あらゆるデータを入れることができる。)
blob型には、グラフィックイメージ、サテライトイメージ、ビデオクリップが対象のデータとなる。

バイナリデータとは?
バイナリデータは、テキストデータ以外のデータです。(一般的には、この意味で使われる。)
厳密には、コンピュータで扱えるデータは、全てバイナリデータになります。(テキストでーたもバイナリデータ)
テキストデータ:人間が見て読めるデータのこと。
バイナリデータ:人間が見ても意味が分からないデータのこと。
※分かりやすい見分け方は、[メモ帳]で開いて中身が理解できるかどうか
テキストデータは、中身が文字だけのデータです。

バイナリデータとテキストデータの特徴は、以下になります。

文字だけ 文字以外も含む(画像データや動画データetc)
データ テキストデータ バイナリデータ
ファイル テキストファイル バイナリファイル
編集ソフト テキストエディタ バイナリエディタ
メモ帳でファイルを開いた時 文章が読める 読めない

参考記事

【Rails】ActiveStorageのvariantを使いこなす!便利な画像変換のメソッドやオプションを実例で解説(!, >, <, ^とは何か?)

BLOB 型

過去のコミットを編集したい

過去のコミットを編集したい
過去にコミットしたものの内容を変更したい場合の方法を備忘録としてこちらに残します。

過去にコミットしたFix CookingMemoryのカラム名の変更というコミットの内容を変更したい場合
Image from Gyazo

修正したいコミットはHEADから1つ前なので、+1して以下のように実行
git rebase -i HEAD~[戻したいコミット数+1]

$ higmonta@higuchimiyukiyuunoMacBook-Pro fishing_cooking % git rebase -i HEAD~2
Stopped at 2815474...  Fix CookingMemoryのカラム名の変更
You can amend the commit now, with

  git commit --amend 

Once you are satisfied with your changes, run

  git rebase --continue

下記のようになるので、編集したいコミットのpickeditに変えて、保存する。

pick e2f81c9 Fix CookingMemoryのカラム名の変更
pick a86abca Fix フォーム画面の記述のリファクタリング

# Rebase 238f49c..a86abca onto 238f49c (2 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
"~/workspace/fishing_cooking/.git/rebase-merge/git-rebase-todo" 27L, 1219B

編集したいファイルを編集する。
ちなみに編集後は、以下のようになります、

Image from Gyazo

下記のようにgit addを実行

$ higmonta@higuchimiyukiyuunoMacBook-Pro fishing_cooking % git add .

下記のようにgit commit --amendを実行

$ higmonta@higuchimiyukiyuunoMacBook-Pro fishing_cooking % git commit --amend
[detached HEAD e2f81c9] Fix CookingMemoryのカラム名の変更
 Date: Sun Apr 17 03:01:57 2022 +0900
 5 files changed, 12 insertions(+), 7 deletions(-)
 create mode 100644 db/migrate/20220416175212_change_cooking_memory_fish_column_to_fish_name.rb

ちなみに、この段階で以下のようになっています。

Image from Gyazo

下記のようにgit rebase --continueを実行
ちなみに、この段階で以下のようになっています。

Image from Gyazo

参考記事

[git]特定のコミットの内容を修正する - dackdive's blog

ビルトインコマンドと外部コマンド

ビルトインコマンドと外部コマンド

ビルトインコマンドと外部コマンドの違いが分からなかったので、こちらにまとめます。

ビルトインコマンド:ファイルとしての実体は無く、シェルに組み込まれている
外部コマンド:PATHに記述されたディレクトリに実行ファイルを置く

以下が実行例です。

higmonta@higuchimiyukiyuunoMacBook-Pro fishing_cooking % type cd
cd is a shell builtin ①
higmonta@higuchimiyukiyuunoMacBook-Pro fishing_cooking % type cat
cat is /bin/cat ②

①は、ビルトインコマンドとなっている
②は、外部コマンドとなっている
※[type]コマンドでビルトインコマンド or 外部コマンドを調べることができる(外部コマンドの場合は、その場所も調べてくれる)