こんにちは、Nanayakuです。
今回は、画像投稿機能の追加について解説していきます。
目次
画像の保存方法
画像はデータベースに直接保存しません。
画像はデータの容量が多いため、データベースの容量を圧迫し、データ形式の変換など扱いが難しいからです。
そのため、画像は違うところに保存し、画像の保存場所(パスやURL)の文字列をデータベースに保存します。
Topicモデルについて
これは上記でも説明した通り、写真のリストのデータベースを作成するモデルです。
モデルの概要は以下の通りです。
カラム | 型 |
user_id(ユーザーのid ) | integer |
description(画像の概要/説明 ) | string |
image(画像のパス/名前) | string |
ここで、UserテーブルとTopicテーブルを関連づけるため、外部キーが必要になります。
今回は「user_id」が外部キーになります。
外部キーとは、「他のテーブルの主キーを保存するためのカラム」の事です。
これにより、自分が投稿した写真を編集したり、自分が投稿した写真の一覧を見るなどの操作が簡単に出来ます。
Topicモデルの作成
以下のコマンドで、上記の概要通りのテーブルが出来ます。
rails g model Topic user_id:integer description:string image:string
rails db:migrateのコマンドで、データベースに適用させます。
空欄で投稿できないようにバリデーションを各カラムに追加します。
参考
関連付け(アソシエーション)
Userから見たTopicの関係とTopicから見たUserの関係を明示的に表現することで、全削除などの操作の設定が簡単になります。
「それぞれのtopicは1つのuserを持つ」と言うTopicから見たUserの関連付けは「belongs_to」で出来ます。
「1つのuserは複数のtopicを持つ」と言うUserから見たTopicの関連付けは「has_many」で出来ます。
このように関連付けをすることで、Railsは参照先をデータを簡単に取得・編集・削除できるメソッドを追加してくれます。
画像投稿機能の作成
Railsには、「CarrierWave」と言うgemがあります。
このgemは、画像のアップロード機能を簡単に追加・実装できます。
Gemfileに「gem "carrierwave"」を追記し、bundle installでインストールします。
画像アップロードファイルの作成
「rails g uploader image」コマンドでアップロードファイルを作成します。
アップロードファイルとモデルを紐づけるため、以下のコードを「app/models/topic.rb」に書きます。
mount_uploader :carrierwave用に作ったカラム名, carrierwaveの設定ファイルのクラス名
mount_uploader :image, ImagesUploader
railsでcarrierwaveを使って画像をアップロード、表示
エラーが出ないように「config/application.rb」へ以下のコードを追記します。
config.autoload_paths += Dir[Rails.root.join('app', 'uploaders')]
ルーターの設定
resources :topicsでまとめて設定します。
Controller・Viewの作成
コントローラーの設定と同じように、paramsで投稿画像のみを生成し、保存ができた時と出来なかった時のフィードバックを表示します。
「topics/new.html.erb」でHTMLを書いていきます。
投稿一覧表示
コントローラーの「topics_controller.rb」ファイルに、indexアクションを作ります。
後は、View(index.html.erb)を作成すれば、投稿一覧を表示できます。
投稿写真の制限
今のままでは、投稿できる写真のファイル形式やデータサイズがバラバラです。
そこで、「uploaders/image_uploader.rb」にバリデーションを設定します。
例)
投稿できるファイル形式がjpg、jpeg、pngのみに制限する
def extension_white_list
%w(jpg jpeg png)
end
投稿できるサイズを10M以下に制限する
def size_range
1..10.megabytes
end
投稿ページへのアクセス
今の設定では、直接「topic/new」とURLを打つと、ログインしていない状態でも移動出来てしまいます。
そこで、「topics_controller.rb」で、ログイン状態でのみnewアクションにアクセス出来るように条件分岐するひち用があります。
def new
if logged_in?
@topic = Topic.new
else
redirect_to login_path, info: 'ログインして下さい'
end
end
最後に
備忘録がわりに作ったので、間違っている所とかあったら、コメントくれると嬉しいです。