Rails Tutorial 第13章を見ていきます。
この章で学ぶこと
- 投稿フォームの作成
概念
組立方
- Micropostデータモデル作成
- Userモデルと関連づけ
- 関連付けに伴う細かなこと
- 投稿内容の一覧表示
- 投稿フォームのview作成
- 画像の投稿
- 画像のバリデーション
1. Micropostデータモデル作成
rails generate model Micropost content:text user:references
これによって、Micropostと紐づける必要のあるuserに関する項目が色々追加されます。
class Micropost < ApplicationRecord
belongs_to :user
end
=> MicropostがUserと1対1の関係であることを示すコード
class CreateMicroposts < ActiveRecord::Migration[5.0]
def change
create_table :microposts do |t|
t.text :content
t.references :user, foreign_key: true
t.timestamps
end
add_index :microposts, [:user_id, :created_at] #この行は追加してください
end
end
=> UserとMicropostを関連づける下準備が完了
indexをuser_idとcreated_atにつけているのは、
micropostsをuser_idに紐づくcreated_atの降順で取得することを前提にしているからです。
なお、このindexが配列になっているのは両方を使って検索することを前提としているからです。
user_idとcreated_atがセットで検索されることが前提の場合はできるだけまとめてあげたほうが高速化するようです。
2. Userモデルと関連づけ
1.でMicropostモデルを作成するのと合わせてUserモデルとの関連づける下準備をしたので、
ここではもっとその関連を強めてアクセスしやすくします。
具体的には下記のようにしたい。
必要なのはuser.rbとmicropost.rbにhas_many
とbelongs_to
を追加してあげること。
class User < ApplicationRecord
has_many :microposts
...
end
3. 関連付けに伴う細かなこと
▼ user.micropostsでcreated_atの降順に取り出すようにしたい
...
default_scope -> { order(created_at: :desc) }
#SQL得意な人は下記のような書き方も可能
#default_scope -> { order('created_at DESC') }
...
矢印みたいなのはラムダ式という文法らしく、深い内容を探りすぎると時間かかりすぎそうなので、
ここでは「ブロックを引数に取り、Procオブジェクトというものを生成している」と理解しておきます。
ちなみに、callメソッドでProcオブジェクトの中身は見れるようです。
▼ userが削除されたらuser.micropostsも削除する
class User < ApplicationRecord
has_many :microposts, dependent: :destory
...
end
has_manyのオプションに加えてあげるだけで終わりです。
4. 投稿内容の一覧表示
今回は、 users#show
のページにmicropostsを表示するということをします。
大枠としては下記のような感じです。
-
users_controller.rb
のshow
メソッドが呼び出される。 -
users_controller.rb
の中で@microposts = user.microposts
のインスタンスを作成する。- 3までで既にuserとmicropostを関連づけてるので実現できる。
-
users/show.html.erb
内で@microposts
をレンダリングする。- そうすると、
microposts/_micropost.html.erb
が呼び出されて描画される。
- そうすると、
- paginationを入れる。
ポイントはMicropostのデータをUsers_controllerで表示するということです。
▼ 投稿一覧を表示
def show
@user = User.find(params[:id])
@microposts = @user.microposts
end
=> ユーザーに紐づく投稿を全て取得
<%= render @microposts %>
=> _micropost.html.erbを投稿の数だけ呼び出して描画
=> その時に @microposts.each { |micropost| render micropost }
が内部ではおきている。
<li id="micropost-<%= micropost.id %>">
<%= link_to gravatar_for(micropost.user, size:50), user_path(micropost.user) %>
<span class="user"><%= link_to micropost.user.name, user_path(micropost.user) %></span>
<span class="content"><%= micropost.content %></span>
<span class="timestamp">
Posted <%= time_ago_in_words(micropost.created_at) %> ago.
</span>
</li>
=> あくまでshow.html.erb
のパーシャルなので、変数はそのまま利用できる。
▼ ページング
まずは必要なGemを追加。
gem 'will_paginate'
gem 'bootstrap-will_paginate'
あとは、ページングしたいページで表示件数を制御し、ページングのビューを出してあげる。
@microposts = @user.microposts.paginate(page: params[:page])
=> params[:page]でページを取得している。一律30件で制御されている。
<%= will_paginate @microposts %>
=> will_paginate
だけではusers
の一覧だと思ってしまうので引数で明示してあげる。
5. 投稿フォームのview作成
-
routes.rb
の設定 - ログイン状態の確認
- createアクションの作成
- フォームの作成
resources(:microposts, only:[:create, :destroy])
=> Micropostではviewを持たないのでcreateとdestroyだけに制御する
def logged_in_user
unless logged_in?
flash[:danger] = "Please Login"
redirect_to login_url
end
end
=> まずはログイン状態を確かめるメソッドをどこからでもアクセス可能なように作成する
before_action(:logged_in_user, only: [:create, :destroy])
=> 投稿に関するコントーラーが動き出すタイミングでログイン状態をチェックする
def create
@micropost = current_user.microposts.build(micropost_params)
if @micropost.save
flash[:success] = "Micropost created"
redirect_to root_url
else
render 'static_pages/home'
end
end
private
def micropost_params
params.require(:micropost).permit(:content)
end
=> Strong Parametersで投稿のオブジェクトを作成し、DBに保存できるのかどうかで投稿が成功したかどうかを判別
<%= form_for(@micropost) do |f| %>
<div class="field">
<%= f.text_area :content, placeholder: "Compose new micropost..." %>
</div>
<%= f.submit "Post", class: "btn btn-primary" %>
<% end %>
=> テキストを入力するtext_areaと投稿するsubmitボタンをform_forで作成
6. 画像の投稿
- 必要なGemのインストール
- 画像アップローダーの生成
- Micropostにカラムを生成
- CarrierWaveに画像と関連づけたモデルを伝える
- ファイルアップロードボタンの作成
...
gem 'carrierwave'
gem 'mini_magick'
...
group :production do
...
gem 'fog'
end
...
=> 画像アップローダーと、画像圧縮と本番にあげるように必要なgemのインストール
rails generate uploader Picture
=> carrierwaveによってuploaderが使えるようになります。
rails generate migration add_picture_to_microposts picture:string
rails db:migrate
=> DBにカラムの追加
...
mount_uploader :picture, PictureUploader
...
=> アップローダーの設定をモデルのカラムと紐づける
@micropost = current_user.microposts.build(micropost_params)
private
def micropost_params
params.require(:micropost).permit(:content, :picture)
end
=> 画像がアップロードされるときに :picture も許可する
<span class="picture">
<%= f.file_field :picture %>
</span>
=> 画像をアップロードするボタンを設置
<%= image_tag micropost.picture.url if micropost.picture? %>
=> 画像を表示する領域