画像投稿機能を追加するgem「CarrierWave」ruby on rails 写真アップロード機能

ここでは画像投稿機能を追加する方法について書いています。
Twitter風やInstagram風など、テキストだけではなく画像なども投稿する機能が欲しい場合は「**CarrierWave**」というgemを追加します。

**環境**
>Windows10
>VS code
>ruby 2.7
>Rails 6.1.4

**二つのgemを導入する**
ひな形の準備：scaffold
画像投稿機能：CarrierWave

#まずはscaffoldというgemでモデルやコントローラー、ビューを一括で作成

railsではモデルやビューやコントローラなどを作る必要があります。
いちから作っていると面倒なので「scaffold」というgemを使います。
railsアプリケーションの開発をする際には、モデルやコントローラー、ビュー、ルーティングを作成していく必要があります。

##modelsやviews、controllersの確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/1baa830b-aed6-2c92-07e3-c8e63727f468.png)
通常、rails newでフォルダを作ると、app直下にmodels、views、controllersなどのファイルが格納されるフォルダが出来上がります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/971e11fc-f95a-0bbc-af3c-d64d0a025396.png)
`app`にある`controllers`の中を見ると、`concerns`というフォルダと`application_controller.rb`というファイルがあるだけです。
ここへ新たにコントローラーファイルを作るというわけです。

###モデルやviewも確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/601b03cb-681e-012f-3d34-481432af8445.png)
modelフォルダにはapplication_record.rbなどがあり、
viewフォルダにはapplication.html.erbやmailer.html.erbなどがあります。
このようにファイルがありますが、ここへも新しくヴューやモデルファイルも追加します。

railsにはscaffoldというgemを使うことでひな形を一気に作成し、ここでの作業をまとめて行ってくれます。それがscaffoldです。


##scaffoldのインストール
###ターミナルでコマンド入力

```
rails generate scaffold user name:string age:integer
```

>意味
>`rails generate scaffold user name:string age:integer`
>`rails generate scaffold モデル名 カラム名:データ型 カラム名:データ型`

実行すると以下のような感じでできると思います。

```
PS C:\aaac> rails generate scaffold user name:string age:integer
      invoke  active_record
      create    db/migrate/20210817130706_create_users.rb
      create    app/models/user.rb
      invoke    test_unit
      create      test/models/user_test.rb
      create      test/fixtures/users.yml 
      invoke  resource_route
       route    resources :users
      invoke  scaffold_controller
      create    app/controllers/users_controller.rb
      invoke    erb
      create      app/views/users
      create      app/views/users/index.html.erb
      create      app/views/users/edit.html.erb
      create      app/views/users/show.html.erb
      create      app/views/users/new.html.erb
      create      app/views/users/_form.html.erb
      invoke    resource_route
      invoke    test_unit
      create      test/controllers/users_controller_test.rb
      create      test/system/users_test.rb
      invoke    helper
      create      app/helpers/users_helper.rb
      invoke      test_unit
      invoke    jbuilder
      create      app/views/users/index.json.jbuilder
      create      app/views/users/show.json.jbuilder
      create      app/views/users/_user.json.jbuilder
      invoke  assets
      invoke    scss
      create      app/assets/stylesheets/users.scss
      create      app/views/users/edit.html.erb
      create      app/views/users/show.html.erb
      create      app/views/users/new.html.erb
      create      app/views/users/_form.html.erb
      invoke    resource_route
      invoke    test_unit
      create      test/controllers/users_controller_test.rb
      create      test/system/users_test.rb
      invoke    helper
      create      app/helpers/users_helper.rb
      invoke      test_unit
      invoke    jbuilder
      create      app/views/users/index.json.jbuilder
      create      app/views/users/show.json.jbuilder
      create      app/views/users/_user.json.jbuilder
      invoke  assets
      invoke    scss
      create      app/assets/stylesheets/users.scss
      invoke  scss
      create    app/assets/stylesheets/scaffolds.scss
```

##マイグレーションファイルなどが生成
`db`フォルダの中に`migrate`というフォルダがあります。
この中に、作成した日付がかかれたファイルがあります。
これが先ほど、`rails generate scaffold user name:string age:integer`とコマンド入力したときに作られたデータベースの`カラム`となるファイルです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/7b4705ae-dec4-3101-238d-324fb9be7143.png)

###生成されたマイグレーションファイルの内容

    create_table :users do |t|
      t.string :name
      t.integer :age

これでマイグレーションファイルは出来上がりました。
けれどこれだけではデータベースが完成していません。

このあと、`rails db:migrateもしくはrake db:migrate`というコマンド入力をしてデータベースのテーブルを作成します。
※ railsとrakeの違い、rails5以降はrailsに統一されたのでどっちを使ってもよいと思います。

###rails db:migrateを実行
```
rails db:migrate
```
下記のように表示されたら完成です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/b37f76d7-2fd9-f893-a13a-6d3bbd87572d.png)

###「schema.rb」「development.sqlite3」ファイルの確認
「schema.rb」「development.sqlite3」というファイルが作成されておりますのでこちらも確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/fa0bbb01-e75e-12a1-13b5-ee37ed983446.png)

####「schema.rb」ファイルを確認
```rb
ActiveRecord::Schema.define(version: 2021_08_17_130706) do

  create_table "users", force: :cascade do |t|
    t.string "name"
    t.integer "age"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
  end

end
```



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/a9ab2de7-8e58-5d60-55e5-9b1c826e8aa2.png)



###users_controller.rb
ディレクトリを確認すると下記のようにusers_controller.rbというファイルができています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/48dc9d94-a82e-a0d2-c89f-fb768fcd5aab.png)

####modelにuser.rbファイルが作られます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/3470e659-6793-3be4-befe-e2d055955446.png)

####view>usersにもそれぞれのファイルが作られています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/c50b2e5f-aa52-010a-4e49-c13a032b3813.png)

##サーバーを起動させviewから確認
できあがったのでサーバーを立てるため下記コマンド入力

```
rails s
```
立ち上がったら下記URLへ
 [http://localhost:3000/users](http://localhost:3000/users "http://localhost:3000/users")

下記のように画面が出たら成功です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/07f1d935-a91a-8888-275f-4dee2effb2fc.png)

###ページが表示されない場合
http://localhost:3000/users 
が表示されない場合は、

下記URLにてTOPページを確認してください。
 [http://localhost:3000/](http://localhost:3000/ "http://localhost:3000/")
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/61aea514-1432-69dc-af33-b0b4dc20d37a.png)
TOPページが表示されていればサーバー自体は起動して表示することに関しては問題ありません。

##scaffoldインストール後の使い方
まず、下記のページが表示されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/23175d38-aa68-5705-403b-12ba009ca17b.png)

###scaffoldでフロントエンドからユーザのデータを作成
`New User`をクリックしてユーザーのデータを作ります。

下記ページが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/c893873c-e046-c308-7ea6-49ac98ab67ed.png)
NameとAgeにそれぞれ名前と年齢を入れます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/eefd54db-77b0-7ff4-6a19-ae05ef5b05a4.png)

あとは`Create User`をクリックします。
すると以下のように表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/bf90fcdd-cddd-34be-6881-307def03fbeb.png)

なおページURLは/user/1となっています。

`Edit | Back`とありますが、Edit は編集ページに移動します。Backを押すとユーザー一覧ページへ移動します。
同じようにユーザーを登録してみると出来上がりをイメージしやすいかもしれません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/65b8f337-a69d-b095-7f35-8cd4553c0bdb.png)
以上になります。

#【本題】CarrierWaveを導入する(scaffoldに画像投稿機能を追加する)
##gemfileに記述
CarrierWaveを導入するために、`gemfile`というファイルに下記コマンドを記述する。

```
gem 'carrierwave'
```

##carrierwave'を書き込むファイルの場所
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/6e1ac28c-d6c2-ef78-1f12-7a76f308ad13.png)



###`gemfile`を開き、一番下に上記のコードを追加します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/182d7fd3-e2a8-bad1-5407-e8688d8a22f0.png)

###CarrierWaveをインストールするために`bundle install`を実行
あとはCarrierWaveをインストールするために`bundle install`を実行します。

```
bundle install
```
インストールされているリストの中で、`using CarrierWave`があれば無事に完了しています。


#CarrierWaveを有効にするために再起動をします
再起動は`Ctrl＋C`で停止にして、`rails s`で起動させます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/9feb6d03-a049-40c0-676b-6c2453807518.png)

##アップローダークラスの作成

アップローダークラスのファイルを作成すると、アップロードするときの設定をつくれます。
ファイルのサイズ、拡張子、保存先などを指定する事が出来ます。

画像投稿用としてimgでコマンドを実行します。
`img` 以外の文字でも大丈夫です。


入力コード例

```
bundle rails g uploader img
```

ファイルは`app>uploader>img_uploader`にあります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/bc9425d2-a815-ae2d-f66c-3f093ac2a954.png)

ひとまずアップロードができればよいので、ここで細かい設定などの説明は割愛します。

##投稿画像が保存される場所　画像のアップロード先
img_uploaderには下記のように書かれています。


```
  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end
```
したがって、uploadsのフォルダ内となります。

##投稿する画像の情報をカラムを追加

さきほど、`scaffold`でカラムを作りました。
カラムの確認方法は、dbフォルダ内の`schema.rb`です。
現在は下記のようになっています。※SQLITEの場合

```
ActiveRecord::Schema.define(version: 2021_08_17_130706) do

  create_table "users", force: :cascade do |t|
    t.string "name"
    t.integer "age"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
  end

end
```
###ここへ画像を保存するカラムを追加します。

```
rails g migration add_img_to_users img:string
```

※`rails g migration Addカラム名Toテーブル名 カラム名:データ型`カラム名になる部分は任意。

実行すると、マイグレーションファイルとして追加されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/1db319e7-997c-5304-c7b9-a37f06cd9b0d.png)

ファイルの中身はこのようになっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/0085de0b-a899-ae72-a875-3d4dd6972fe6.png)


###マイグレーションを実行してデータベースのテーブルへ追加

```
rails db:migrate
```
追加後、dbフォルダにある`schema`ファイルを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/9a76ec99-21b8-f6b6-4f20-3b3bfa62ec9e.png)
`t.string "img"`が追加されています。



##controllerにimgカラムを追加
データベースに保存するために`controller`フォルダにある`users_controller`ファイルにカラムを追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/8044a753-7300-329a-eace-5dfc3fb5c247.png)

ファイルの中に下記の記述があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/81150e3e-8d6a-609c-0064-aba4623c7022.png)

ageのあとに`, :img`を追加します。

```
def user_params
  params.require(:user).permit(:name, :age, :img) 
end
```

##投稿画像の設定をするアップローダークラスとカラム名imgを紐付ける
`models`フォルダに`user.rb`というファイルがあるのでそこを開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/7e8a64aa-878b-af40-6e7e-97d28ab861d8.png)

ファイル内は何も記述されていません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/1d81bbb8-9ffa-203f-c6d4-9aec844044ec.png)

ここへ下記コードを書き込みます。

```
class User < ActiveRecord
  mount_uploader :img, ImgUploader
end
```
画像投稿時に、アップローダークラスに書かれている設定が反映されます。つまり画像のサイズや画像の投稿フォルダや拡張子などです。

##注意 user.rbファイル class User < ActiveRecord 
`class User < ActiveRecord`の部分で下記のようにするとエラーになります。

```
class User < ActiveRecord::Base
```
Baseを記述したららNameerrorが表示されました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/5220ec7f-10b7-823c-2cbf-95c595aca226.png)


#viewsの設定 投稿フォームに画像が投稿できるようにする
次はフロントエンド側の設定です。
下記のように、まだ画像を投稿するフォームがありません。
画像を投稿するようにします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/d289f0cd-2699-671a-6892-757f9ace51b9.png)

http://localhost:3000/users

まず`users`フォルダへ移動して`_form.html.erb`を開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/3b1b1878-c4ad-2be0-0393-73fb3f4d57bb.png)

名前や年齢の下に入れたいので下記コードを貼ります。

```erb
<div class="field">
  <%= form.label :img %>
  <%= form.file_field :img %>
</div>
```

ページ内の下記へ貼ります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/6edd5ec4-0934-d5ed-48bc-4b5f64a48aa7.png)


localhost:3000/users/newを表示
ファイルが投稿できるようになっています
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/cd9df4d3-70ca-34cf-bd25-eec411c3d8e9.png)

###表示させる部分show.html.erbにコード追記
下記のコードをusers>show.html.erbのファイルのageの下に貼り付けます。
```
<% if @user.img? %>  
  <p>
    <strong>post img:</strong>
    <%= image_tag @user.img.url %>
  </p>
<% end %>
```

貼り付ける場所
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/3e98e599-7657-37f0-5699-a19137a42352.png)


##動作確認のためユーザ登録を表示させる

適当に名前や年齢をいれ、画像も入れます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/dfb607a7-9b44-ba5d-5110-cbcbc544dd27.png)

このように画像が投稿されます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/af45f1c3-c00c-dd0b-909a-8c20352cdf0f.png)

ユーザー一覧ではこのように表示されます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/77dbd432-ae99-381d-7f29-94ce25a1b96a.png)

以上になります。