エラー体験記 Active Storageを用いた画像の複数枚投稿機能

前置き

この記事は、私がプログラミングの学習において遭遇したエラーについて残しておくものになります。

このジャンルについては「# エラー」をつけてシリーズ化していく予定なので、よろしくお願いします。

 

お断り

今回の記事は、少し前に遭遇したエラーについて思い出しながら書いているものになります。

そのため、エラーメッセージについては実際のものと多少異なる可能性があります。

また、コードについては一部簡略化している部分もあります。

あらかじめご了承ください。

 

以下、エラー発生時の状況

 

作成中のアプリ

  • 言語:Ruby, Ruby on Rails
  • アプリ概要:メッセージ投稿アプリ
  • テーブル設計:以下詳細

 

テーブル設計(今回のエラーと関係のないものは省略)

## messagesテーブル

| Column | Type  | Options.   |

| -------- | ----- | ---------- |

| title        | string | null: false | 

| text        | text    | null: false |

 

### Associations
なし
* モデル内で、 has_one_attached :imageを定義。

* 画像の添付にはActive Storageを使用。

 

エラー発生時に行った作業

画像の複数枚投稿機能を実装。

コードの変更点は以下。

 

  • モデル

    # associationを1対1から多対多に修正。

    has_one_attached: image

    has_many :images

  • ビュー(フォーム部分)

    # 選択した複数の画像を配列の形で受け取れるように修正。

    <%= f.image_file :image %>

    <%= f.image_file :images, name: "message[images]" %>

  • コントローラ(ストロングパラメータ受け取り部分)

    # フォームのname属性の変更に合わせてpermitメソッドの引数を修正。

    def message_params

        params.require(:message).permit(:name, :title, :image)

    end

    def message_params

        params.require(:message).permit(:name, :title, images: )

    end

  • ビュー(message一覧ページ)

    # 画像が複数枚ある内の1枚目だけをプレビュー表示されるように変更。

    <%= image_tag @message.image if @message.image.attached? %>

    <% if @message.images.any? %>

        <%= image_tag @message.images[0] %>

    <% end %>

     

発生したエラー

原文は覚えていませんが、「imagesに対してというメソッドは使えないよ」みたいな意味合いだったのは覚えています。

自分の中での分析

というメソッドが使えないということは、原因として考えられるのは

  1. nilclassに対してメソッドを用いてしまっている。
  2. imagesが配列(Array class)以外のクラスを持っている。

のどちらか。

前者に関しては、if @message.images.any?nilの場合を除外している上に、Sequel Proでも画像がattachされていることは確認済み。

よって、原因として考えられるのは後者に絞られる。

結論

「コードの変更前に保存されていたレコードが邪魔をしていた。」
これが原因でした。

 

上記の通りにコードを変更したことによって、そのあとで@messageにattachされたimagesに関しては、要素の数がいくつであろうと配列の形式をとります。

# imageがattachされていない場合
@message.images =
# imageが1枚だけattachされている場合
@message.images = [ image1 ]
# images が複数attachされている場合
@message.images = [ image1, image2, .... ]

 

要素が一つであろうと配列は配列なので、メソッドが問題なく使えるというわけですね。

 

しかし、コード変更前に保存されたレコードについては、imageは配列の形になっていません。

# コード変更前のレコード
@message.images = image

ビューやカラムなどをいじっても、すでに保存されているレコードの方がそれに合わせて自動で変わってくれるわけではないんですね。

なので、コード変更前にmessagesテーブルに保存されていたレコードに対して
<%= @message.images[0] %>
が呼び出された際に、「配列ではないものにメソッドは使えないよ」と怒られてしまったということです。

 

最終的には、テーブルのレコードを全て削除することで解決しました。

今後もカラムの仕様を変更した場合には同様のことが起こり得るので、気をつけたいですね。