うめぼしジョイスティック - ivoice

CakePHP、JavaScript、jQuery等のプログラミングについて書いていきます 思考は、うめぼしのように硬く、そして柔らかく。

Railsのあれこれ その5

既存のモデル(テーブル)にカラムを追加する

既存のテーブルに追加でカラムを追加します。 結構複雑です。

まず、ターミナルで

rails g migration add_image_name

このように、カラムを追加するためのマイグレーションファイルを追加します。 「add_image_name」というのがマイグレーションファイルの名前になります。 ここは任意でOK。

アプリ名>db>migrate の中に、

日付け_add_image_name

というファイルが追加されているはずなので、そこを編集します。

class Change < ActiveRecord::Migration[5.0]
  def change
    add_column :users, :image_name, :string
  end
end

この場合は usersテーブルにimage_nameという文字列のカラムを追加します。

マイグレーションファイルのchangeメソッドの中に

def change
  add_column :テーブル名, :カラム名, :データ型
end

このように記述します。テーブル名はモデル名の複数形になるので注意しましょう。(例:Userモデルの場合、users)

そうしたら、 ターミナルで

rails db:migrate

と打ちます。 これで、さきほどマイグレーションファイルに書いた変更がデータベースに反映されます。 確認してみましょう。

image_name

という文字列のカラムが追加されているはずです。


画像を参照するときの書き方

これが結構地味に頭がこんがらがります。

<img src="<%= "/user_images/#{画像名}" %>">

このようにします。

画像名の変数が image_name だとすると

<img src="<%= "/user_images/#{image_name}" %>">

こうなる訳ですね。 外側の""ダブルクオーテーション2つは、ただのマークアップのための表示、 そして内側のダブルクオーテーション2つはrubyの変数を式として評価するためのものです。

<%= "#{image_name}" %>

このようになっていた場合、rubyでは image_nameを変数として出力する訳です。 今回は

<img src="<%= "/user_images/#{image_name}" %>">

となっているので、

<%= "/user_images/#{image_name}" %>

までがrubyの式として表示させたい部分ですね。 いちばん外側にあるダブルクオーテーションは「マークアップのためのダブルクオーテーションマーク」ということです。 いや~ややこしい。

この「rubyの式の展開」についてはよく覚えて、慣れておきましょう。

画像を登録する

画像です。画像の登録。

コントローラーのcreateでは、

  def create
    @user = User.new(name: params[:name], 
                    email: params[:email],
                    image_name: "default_user.jpg")
    
    if @user.save
      flash[:notice] = "ユーザー登録が完了しました"
      redirect_to("/users/#{@user.id}")
    else
      render("users/new")
    end
  end

のようにして、まずUser.newをするときに、画像にデフォルトの画像ファイルを設定します。

その次に、画像を編集する場合です。

edit.html.erbに

<p>画像</p>
          <input name="image" type="file">

を追加します。

input属性のnameはimageという名前にしましょう。 そして、ポイントはファイルタイプを「file」とすることです。 これで画像ファイルが取得できます。

ただし、送信フォームに

<%= form_tag("/users/#{@user.id}/update", {multipart: true}) do %>

のようにして、フォームに

{multipart: true}

をつけます。これをすることにより、ファイルが送信出来るようになります。

そして、コントローラーのupdateアクションでは「画像がある場合に登録する」 という処理を記載します。

ファイルがあるときのみ実行するif文を書きます。

  def update
    @user = User.find_by(id: params[:id])
    @user.name = params[:name]
    @user.email = params[:email]

    if params[:image]
      @user.image_name = "#{@user.id}.jpg"
      image = params[:image]
      File.binwrite("public/user_images/#{@user.image_name}", image.read)
    end

    if @user.save
      flash[:notice] = "ユーザー情報を編集しました"
      redirect_to("/users/#{@user.id}")
    else
      render("users/edit")
    end
  end

このようになります。

if params[:image]

の部分で、「画像がもしある場合」 として処理を実行しています。

ファイルを保存するには

File.binwrite("public/user_images/#{画像名}", 画像データ.read)

というようにして画像ファイルを入れる場所と、画像データを指定します。

上記では

 @user.image_name = "#{@user.id}.jpg"
 image = params[:image]
 File.binwrite("public/user_images/#{@user.image_name}", image.read)

の部分です。 public/user_images/ というフォルダに、画像を書き込んでいることが分かります。 この場合のファイル名はユーザーIDを使っています。

かなりややこしいですね。 binwriteメソッドとreadメソッドについても調べておきましょう。