Programming Journal

学習したことの整理用です。

【Rails】ユーザーの入力値を画像表示に反映させる

実装したいこと

記事投稿アプリで、記事のアイキャッチ画像を設定できます。

前提

記事投稿の機能は実装済です。
今回は画像の表示を変更する部分のみの実装です。
ファイルのアップデートはActive Storageを使用しています。

どう実装していけばいいか

どうやって実装するか全く思いつかず、数時間悩んでしまいました。。シンプルにデータの流れと入出力を順を追って考えたら何とか実装できました。

  1. ユーザーが入力フォームに値を入力する
  2. 入力値を受け取って、保存する。
  3. 画像を表示するときに、保存した値を反映させる。

実装の流れ

  1. ユーザーの入力値を保存するためのカラムを追加する。
  2. 入力フォームを追加する。
  3. 画像表示部分のclassを動的に変更する。

カラム追加

f:id:Study-Diary:20201016113033p:plain
カラム追加

ユーザーの入力した「画像幅」・「画像位置」を受け取るカラムをそれぞれ作成します。
それぞれ、eyecatch_widtheyecatch_positionとしました。

ターミナルで、rails db:migrateします。

enum設定

画像位置については、左寄せ・中央寄せ・右寄せの3択で設定できるようにします。

enum eyecatch_position: { left: 0, center: 1, right: 2 }

gem 'enum_help'を使用しているので、翻訳ファイルを設定しておきます。

ja:
  enums:
    article:
      eyecatch_position:
        left: '左寄せ'
        center: '中央寄せ'
        right: '右寄せ'

Validation設定

ユーザーの入力値は、100~700pxに限定します。
空欄を許可しておかないと、アイキャッチ画像を設定せずに更新したいときにもバリデーションエラーになるので必須の設定です。
私は最初2行で設定してしまったのですが、1行で設定できるんですね。スマート

# BAD
validates :eyecatch_width, allow_nil: true,
                             numericality: { greater_than_or_equal_to: 100, message: 'は100以上の値にしてください' }
validates :eyecatch_width, allow_nil: true,
                             numericality: { less_than_or_equal_to: 700, message: 'は700以下の値にしてください' }

# GOOD
validates :eyecatch_width, numericality: { less_than_or_equal_to: 700, greater_than_or_equal_to: 100 }, allow_blank: true

入力フォーム作成

画像幅を入力するフォームと、画像位置を選択するラジオボタンを設置していきます。

      = simple_form_for @article, url: article_path(@article) do |f|
        .box-body
          - if @article.eye_catch.attached?
            = image_tag @article.eye_catch_url(:thumb), class: 'img-thumbnail'
            br
            br
          = f.input :eyecatch_width
          = f.input_field :eyecatch_position, as: :radio_buttons
     
# 以下NG ラジオボタンが重なってしまった
          = f.input :eyecatch_width
          = f.input :eyecatch_position, as: :radio_buttons

f:id:Study-Diary:20201016115655p:plain
入力フォーム

gem 'simple_form'

以上のコードのように、簡単にフォームを作れるgemです。

GitHub - heartcombo/simple_form: Forms made easy for Rails! It's tied to a simple DSL, with no opinion on markup.

画像表示部分のclassを動的に変更する。

これが難しかったです。
Boot Strapを使用しているので、class名を変えれば、画像の位置を変えられそうです。

最初、article.eyecatch_positionの値をApplicationHelperで判定して、class="float-right" class="mx-auto d-block" class="float-left"を返す…と実装したのですが、それよりも、class="text-right" class="text-center" class="text-left"を使用すれば、enumの値をそのまま使用できます。

画像幅は、保存した値をarticle.eyecatch_widthでそのまま取ってこれます。

# BAD
  - if article.eye_catch.attached?
    section.eye_catch class="#{eyecatch_position_class(article)}" #eyecatch_position_classというApplicationHelperメソッドを呼んでいた
      = image_tag article.eye_catch_url(:lg), style: "width: #{article.eyecatch_width}px;"


# GOOD
  - if article.eye_catch.attached?
    section class="eye_catch text-#{eyecatch_position}"
      = image_tag article.eye_catch_url(:lg), class: 'img-fluid', width: article.eyecatch_width

Controller

Strong Parameterで入力できる値を追加します。

  def article_params
    params.require(:article).permit(:eye_catch, :eyecatch_width, :eyecatch_position)#ここ
  end

参考

『パーフェクト Ruby on Rails』P225
『現場Rails』P306