ActionMailerのプレビュー

[ActionMailerのプレビュー]について

[ActionMailer]のプレビュー機能が便利だった為、こちらにまとめます
[ActionMailer]のプレビュー機能を使えば、実際にメールが送信されることはないので、何度もメールのレイアウトを確認することができる

プレビュー機能の手順を以下に示します

下記コマンドで、[ActionMailer]を生成する

$ rails generate mailer (メーラー名)


上記で[ActionMailer]を生成した際に、[spec/mailers/previews/]のフォルダ以下にpreviewのファイルが生成されているので、こちらに記載する。
Railsガイドには、[test/mailers/previews/]フォルダ以下にpreviewファイルを配置するとなっており、文章のまま[test/mailers/previews/]を作ってしまったので注意が必要!!
以下に例を示します

[app/mailers/article_mailer.rb]

class ArticleMailer < ApplicationMailer
  def report_summary
    mail(to: 'admin@example.com', subject: '公開済記事の集計結果')
  end
end
[app/mailers/previews/article_mailer_preview.rb]

class ArticleMailerPreview < ActionMailer::Preview
  def report_summary                     # メーラーと同じメソッド名で定義する
    ArticleMailer.report_summary   #送信したいメーラーを呼び出す[(メーラー名).(メーラーのメソッド)]
  end
end


サーバーを起動して以下のURLにアクセスすると、メールのプレビューが確認できる

http://localhost:3000/rails/mailers/(メーラー名)/(メソッド名)
   ① 以下が例
http://localhost:3000/rails/mailers/user_mailer/welcome_email


http://localhost:3000/rails/mailersで、使用できるメーラーが以下のように表示される

Image from Gyazo


メソッド名をクリックすると以下のようにメールがプレビューで表示される(このURLが①になる)
このメソッド名のリンク(report_summary)は、previewクラスに作成したreport_summaryメソッドに対応して表示される

Image from Gyazo

※ポイント
[ActionMailer]のプレビュー機能では、メールが送信されているわけではないのでプレビューで表示されるからメールの送信機能も動いていると勘違いしないようにする

参考記事

【Rails入門】Action Mailerのメール送信を初心者向けに基礎から解説 | 侍エンジニアブログ

オブジェクト指向とgetterとsetterとカプセル化

[オブジェクト指向とgetterとsetterとカプセル化]

[オブジェクト指向],[getter],[setter],[カプセル化]という言葉を見かけることが多いが、それらの意味をあまり理解していなかったのでこちらにまとめます

[オブジェクト指向]
○○指向というのは、〇〇を重視しているというような意味になる
例えば、恋人を選ぶ際にルックス指向や性格指向といった感じ
オブジェクト指向プログラミングというのは、オブジェクトをたくさん作ってアプリケーションを作るという事
Twitterで例えたら、ユーザーのアカウントというオブジェクトやTweetというオブジェクト、フォローというオブジェクトなどが集まってTwitterが出来上がるということ

[getter]と[setter]
[getter]というのは、クラスの外からオブジェクトの属性の値を参照できるようにするメソッドのこと
[setter]というのは、クラスの外からオブジェクトの属性の値を変えることができるようにするメソッドのこと
今回のように、オブジェクトの属性値を変更できるオブジェクトの事をミュータブルなオブジェクトという
以下に例を示します

class Food
  def name=(text)   # setter: クラスの外からname属性に値をセットしたり変更したりできる
    @name = text
  end

  def name      # getter: クラスの外からname属性の値を参照できる
    @name
  end
end

food = Food.new        
food.name = "寿司"
p food.name    => "寿司"

[カプセル化]
[カプセル化]というのは、クラスの外からオブジェクトの属性の値を参照出来ないようにしたり、値を更新できないようにすること
基本的には、オブジェクトの属性値は外部から値が更新されないようにカプセル化した方が良いことがほとんど
今回のように、オブジェクトの属性値が変更できないオブジェクトの事をイミュータブルなオブジェクトという
以下に例を示します

class Food

private
  def name=(text)
    @name = text
  end

  def name
    @name
  end
end

food = Food.new
food.name = "寿司"     => エラーになる     # クラスの中に[getter]と[setter]を記述しているが、privateにする事でクラスの外から[getter]と[setter]を呼び出せないようにして、クラスの外から値を参照したり、値を更新できないようにしている<br>
p food.name                 => エラーになる

参考記事

www.youtube.com

www.youtube.com

複数ファイルのアップロード

複数ファイルのアップロード

複数ファイルをアップロードしたい時は、以下のように記述する(simple_formの場合)

[app/views ファイル]

= f.input :main_images, as: :file, input_html: { multiple: true }    # input_html: { multiple: true } というオプションを付ける
[app/controllers ファイル]

  def site_params
    params.require(:site).permit(:name, :subtitle, :description, :favicon, :og_image, main_images: [])
  end

上記のようにコントローラでストロングパラメータで複数ファイルをアップロードしたものを受け取る際は、配列になるのでmain_images: []のように記述する

参考記事

【Rails 5.2】 Active Storageの使い方 - Qiita

Swiper

Swiper

Swiperは、画像などを動的にスライドできるjQueryプラグイン

導入手順は、以下のようになる

$ yarn add swiper


[node_modules]にswiperがインストールされる
swiperの公式にあるように[swiper-bundle.css]と[swiper-bundle.js]を読み込むようにしなければいけない

Image from Gyazo

今回は、swiperを使用するlayoutファイルに[application.js]と[application.css.scss]を使用していると仮定しています

[app/assets/javascripts/application.js]

//= require swiper/swiper-bundle.js
[app/assets/stylesheets/application.css.scss]

@import 'swiper/swiper-bundle';

上記のassetに記述したファイルのパスを以下に記述することで、絶対パスで記述しなくても読み込める

[config/initializers/assets.rb]

Rails.application.config.assets.paths << Rails.root.join('node_modules')
[app/views/layouts/_header.html.slim]

header
  .swiper-container
    .swiper-wrapper   # スライドさせたい部分にクラスを付ける①
      - if current_site.main_images.present?
        - current_site.main_images.each do |main_image|
          = image_tag url_for(main_image), class: 'swiper-slide'    #  スライドさせる対象にswiper-slideというクラスを付ける
      - else
        = image_tag '/images/cover.jpg', class: 'swiper-slide'
  .container.blog-title
    h1 = link_to current_site.name, root_path
    p.lead = current_site.subtitle

javascript:
  $(document).ready(function() {
    new Swiper('.swiper-container', {       #   ①のクラス名を利用
      loop: true,
      autoplay: {
        delay: 3000,
      },
    })
  })

※ポイント

$(document).ready(function() {
  # 指定した処理
});

上記の記述は、DOMの読み込みが終わったらfunction()の中の処理を実行するという意味
JavaScriptは、HTMLが全て読み込まれてから出ないと正しく動作しない為、これを記述する
非同期通信(remote: true)で何かをクリックした時とかに[js.erb]ファイルをレスポンスする時は、ブラウザ上で画面が既に表示されているので、DOMの読み込みが終わっているが、今回のようにブラウザに画面が表示されるのと同時にJavaScriptを使う場合とかだと画面上のDOMが読み込まれているか分からないので、 [$(document).ready(function() { });] を記述する

参考記事

jQueryの基本 - $(document).ready - Qiita

JavaScriptの$(document).readyの使い方を現役エンジニアが解説【初心者向け】 | TechAcademyマガジン

jQuery入門講座 使い方-jQueryの省略構文

swiperをyarnで導入して、画像をスライダー形式にする! - Qiita

Swiperの導入 - manabuのまなび

【2021年版 RailsアプリにSwiper.jsでカルーセルを実装】 - Qiita

RailsでSwiperを導入する方法(Swiperは2020年7月にバージョンアップし、従来と設定方法が変わりました!) - Qiita

RailsでSwiperを導入する方法(Swiperは2020年7月にバージョンアップし、従来と設定方法が変わりました!) - Qiita

カスタムバリデーター

[カスタムバリデーター]とは?

モデルに記載するのとは別で、自分でバリデーションメソッドを作成することができる
[app/validators]を作成することで自動で読み込んでくれる

EachValidatorメソッド

[EachValidator]メソッドは、1つの属性に対しての検証を定義できる
[EachValidator]メソッドは、以下の3つを引数として受け取れる
・record: モデルのインスタンス
・attribute: 属性名
value: 属性値
クラス名は、[検証名]Validatorの形式にする必要がある

以下に使用例を記述します

[app/models/site.rb]

class Site < ApplicationRecord
  validates :og_image, attachment: { purge: true, content_type: %r{\Aimage/(png|jpeg)\Z}, maximum: 524_288_000 }  #  [app/validators/attachment_validator.rb]に定義したattachment
  validates :favicon, attachment: { purge: true, content_type: %r{\Aimage/png\Z}, maximum: 524_288_000 }
  validates :main_images, attachment: { purge: true, content_type: %r{\Aimage/(png|jpeg)\Z}, maximum: 524_288_000 }
end
[app/validators/attachment_validator.rb]

class AttachmentValidator < ActiveModel::EachValidator
  include ActiveSupport::NumberHelper

  def validate_each(record, attribute, value)
    return if value.blank? || !value.attached?

    has_error = false

    if options[:maximum]
      if value.is_a?(ActiveStorage::Attached::Many)
        # 画像が複数枚投稿された場合
        value.each do |v|
          unless validate_maximum(record, attribute, v)
            has_error = true
            break
          end
        end
      else
        # 画像が1枚投稿された場合
        has_error = true unless validate_maximum(record, attribute, value)
      end
    end

    if options[:content_type]
      if value.is_a?(ActiveStorage::Attached::Many)
        # 画像が複数枚投稿された場合
        value.each do |v|
          unless validate_content_type(record, attribute, v)
            has_error = true
            break
          end
        end
      else
        # 画像が1枚投稿された場合
        has_error = true unless validate_content_type(record, attribute, value)
      end
    end

    record.send(attribute).purge if options[:purge] && has_error
  end

  private

  def validate_maximum(record, attribute, value)
    if value.byte_size > options[:maximum]
      record.errors[attribute] << (options[:message] || "は#{number_to_human_size(options[:maximum])}以下にしてください")
      false
    else
      true
    end
  end

  def validate_content_type(record, attribute, value)
    if value.content_type.match?(options[:content_type])
      true
    else
      record.errors[attribute] << (options[:message] || 'は対応できないファイル形式です')
      false
    end
  end
end

上記でoptions[:maximum]は、バリデーションに定義したmaximumの値を参照できる(デバッグで確認した以下を参照)

[1] pry(#<AttachmentValidator>)> options[:maximum]
=> 524288000
[2] pry(#<AttachmentValidator>)> options[:content_type]
=> /\Aimage\/(png|jpeg)\Z/
[3] pry(#<AttachmentValidator>)> options[:purge]
=> true

参考記事

Rails カスタムバリデーション(validator, EachValidator) - Qiita

Visual Studio Codeの便利ツール

Visual Studio Codeの便利ツール

Visual Studio Codeの便利ツールがありましたので、こちらにまとめさせていただきます

[code]

下記のようにして[code]という拡張機能をインストールする

Image from Gyazo

codeという拡張機能を入れると、下記のようにターミナルから[code ディレクトリ名]でVSコードで指定したディレクトリを開くことができる。

Image from Gyazo

Node.jsとnodenvとyarn

Node.jsとnodenvとyarn

今までフロント部分について曖昧な事が多かったため、こちらにまとめさせていただきます。

Node.jsとは?
Node.jsは、JavaScriptがサーバー側で動くようにするものだが、今までJavaScriptのサーバー側バージョンの言語?と思っていたが、実は違った
Node.jsは、JavaScriptがサーバー側で動くようにするためのプラットフォームである。
そもそもRubyJavaScriptなどのプログラミング言語が使えるようになるのは、プログラミング言語を理解できるプラットフォームがあるからである
Rubyの場合は、サーバー側にRuby言語が理解できるプラットフォームがあるからサーバー側でRubyが動く
JavaScriptの場合は、ブラウザ側にJavaScript言語が理解できるプラットフォームがあるからブラウザ側でugoku
Node.jsは、通常はブラウザ側にしかJavaScriptのプラットフォームが無いが、サーバー側でもJavaScriptを理解できるようにするためのプラットフォームである。

nodenvとは?
nodenvは、Node.jsのバージョン管理ツールである

yarnとは?
JavaScriptのライブラリを管理するパッケージマネージャ

[node_modules]フォルダとは?
yarnでインストールしたライブラリがインストールされる場所(Rubyだとvendorフォルダになる)

[package.json]ファイルとは?
yarnでインストールしたいライブラリ名とバージョンを記載したファイル(RubyだとGemfileになる)

[yarn.lock]ファイルとは?
yarnでインストールしたライブラリと、それの依存関係にあるライブラリと、それぞれのバージョンを記録しておくファイル(RubyだとGemfile.lockファイルになる)

Rubyに例えると以下のようなイメージ

Ruby Node.js
バージョン管理ツール rbenv nodenv
パッケージマネージャ bundler yarn
インストールしたいライブラリを記載するファイル Gemfile package.json
インストールしたライブラリが保存される場所 vendor node_modules
インストールしたライブラリとそれの依存関係にあるライブラリと、それらのバージョンを保存しておくファイル Gemfile.lock yarn.lock
Gemfile.lockやyarn.lockに記載されているライブラリをインストール+Gemfile.lock(yarn.lock)とGemfile(package.json)を比較してGemfile.lock(yarn.lock)に記載が無く、Gemfile(package.json)に記載があるライブラリがある場合は、そのライブラリに依存しているライブラリも含めてインストール bundle install yarn install
Gemfile.lock(yarn.lock)に記載されているバージョンを参照せずにGemfile(package.json)に記載されている内容の範囲内で最新のライブラリをインストールし直す(ライブラリのバージョンが変わり今まで動いていたアプリケーションが動かなくなる可能性があるので、基本的にはやらない方が良い) bundle update yarn upgrade
Gemfileやpackage.jsonに記載せずに、指定したライブラリをインストールする gem install (ライブラリ名) yarn add (ライブラリ名)

以下のファイルの位置でもRubyとの対応関係がイメージがつくと思います。

higmonta@higuchimiyukiyuunoMacBook-Pro 2563_higmonta_runteq_curriculum_advanced % which yarn
/Users/higmonta/.nodenv/shims/yarn
higmonta@higuchimiyukiyuunoMacBook-Pro 2563_higmonta_runteq_curriculum_advanced % which bundler
/Users/higmonta/.rbenv/shims/bundler

参考記事

swiperをyarnで導入して、画像をスライダー形式にする! - Qiita