2020/12/19 railsチュートリアル13章
マイクロポストモデルを作る
micropostモデルを作る
contentカラムはtext型にする→DB上ではstringでもtextでもパフォーマンスはほとんど変わらない、将来の変更に柔軟性が高い(データ上限が多いので)
has_many --再登場、userとmicropostを関連付けする
rails generate model Micropost content:text user:references #user_id:integerの省略形 => 自動的にbelongs_to :userを入れてくれる t.references :user, null: false, foreign_key: true => 他のモデルのIDを参照するときはnullチェックした方がいい => 外部キー(foreign_key)を参照するためだよということをDBに伝える
複合キーインデックス、よく引くテーブルの高速化をする。
=>micropostの投稿とuser_idのセット
最初のテスト
test "user id should be present" do @micropost.user_id = nil assert_not @micropost.valid? end
migrationのときにnull: falseとしているので、特にvalidationをかいていなくても勝手に弾かれる(assert_notがtrue)
関連付け(Association)
関連付けすると生成されるメソッドがある
user.microposts => Micropost.find_by(user_id: user.id)
user.microposts.create => Micropost.create(user_id: user.id)
user.microposts.build => Micropost.new(user_id: user.id)
user.microposts.find_by(content: ..) => Micropost.find_by(user_id: user.id, content: ...) etc..
関連付けした場合は慣習的にこちらのメソッドを使う(user_idで検索する時の間違いとかが起きないなど、色々メリットがある、current_userが投稿するときにmicropostsへのuser_idの紐付けを間違えたりとか)
@micropost = Micropost.new(content: "Lorem ipsum", user_id: @user.id) ↓ @micropost = @user.microposts.build(content: "Lorem ipsum")
ここのbuildメソッドはnewメソッドと同義、関連付けしたものということがわかりやすいようにこちらを使う
micropost.user Micropostに紐付いたUserオブジェクトを返す user.microposts Userのマイクロポストの集合をかえす user.microposts.create(arg) userに紐付いたマイクロポストを作成する user.microposts.create!(arg) userに紐付いたマイクロポストを作成する(失敗時に例外を発生) user.microposts.build(arg) userに紐付いた新しいMicropostオブジェクトを返す user.microposts.find_by(id: 1) userに紐付いていて、idが1であるマイクロポストを検索する
マイクロポストの順序付け
default_scope -> { order(created_at: :desc) }
->{...} はRubyのProcオブジェクト
ブロックを変数に渡すことができる
irb(main):001:0> a = -> { puts "Hi" } => #<Proc:0x00007fac3e82f248@(irb):1 (lambda)> irb(main):002:0> a => #<Proc:0x00007fac3e82f248@(irb):1 (lambda)> irb(main):003:0> a.call #callしたときにメソッドを実行する Hi => nil
userの依存
Userが破棄されたらMicropostも破棄する
has_many :microposts, dependent: :destroy
User.rbのテストなので、userのテストに書こう
Micropostを表示する
userのshowテンプレートに表示しよう
コントローラ生成
表示には使わないが、micropostの投稿とか編集とか削除には使うので作ろう
表示用パーシャル
<ol class="microposts"> <%= render @microposts %> </ol>
前回やったやつ、renderの引数に一覧データを渡して_micropost.html.erbを呼び出す
<li id="micropost-<%= micropost.id %>">
CSSidを別々に割り振っていくことで、javascriptなど使うときとかに有効活用できるらしい
showアクションで投稿を表示
def show @user = User.find(params[:id]) @microposts = @user.microposts.paginate(page: params[:page]) end
showアクションに@micropostのインスタンス変数を追加して表示できるようにする
サンプルデータ作成
# ユーザーの一部を対象にマイクロポストを生成する users = User.order(:created_at).take(6) #まずユーザーを抽出 50.times do content = Faker::Lorem.sentence(word_count: 5) #5文字程度のデータをcontentにいれる users.each { |user| user.microposts.create!(content: content) } #micropostを作る end
micropostを操作する
def create @micropost = current_user.microposts.build(micropost_params) #関連付けが終わっているので、user_idはデフォルトで入っているので、contentだけparamsから持ってくればいい if @micropost.save flash[:success] = "Micropost created!" redirect_to root_url else render 'static_pages/home' end end def micropost_params params.require(:micropost).permit(:content) #contentだけ持って来れればいい end
どこから投稿できるようにするか→今回はhomeからやる(homeにフォームを置き、ログインしてたらフォームが出るように切り替える )
<% if logged_in? %> <div class="row"> <aside class="col-md-4"> <section class="user_info"> <%= render 'shared/user_info' %> #ユーザー情報 </section> <section class="micropost_form"> <%= render 'shared/micropost_form' %> #投稿フォーム </section> </aside> </div> <% else %>
投稿フォーム
<%= form_with(model: @micropost, local: true) do |f| %> #micropostモデルのオブジェクトを置くことでフォームの送信先を指定、あるかないかでリクエストは勝手に選ばれる <%= render 'shared/error_messages', object: f.object %> #エラーメッセージ用。 <div class="field"> <%= f.text_area :content, placeholder: "Compose new micropost..." %> </div> <%= f.submit "Post", class: "btn btn-primary" %> <% end %>
error_messagesのパーシャルは、@user用に作っているので@micropostには使えない。
パーシャルのobjectが自動で変わればいいのに・・・
f.object => フォーム作るときに参照(モデルとか)したオブジェクト
object = f.objectとすることでパーシャルの中身を動的に変更できるように修正する
投稿の表示
def feed Micropost.where("user_id = ?", id) end
where("user_id = ?", id) Micropost tableの中から、次の条件に一致したデータを探す。"user_id = ?"は文字列だがSQL文。
"?"に次の引数"(self.)id"がはいる。
フィードの中身
<% if @feed_items.any? %> <ol class="microposts"> <%= render @feed_items %> # each文で表示 </ol> <%= will_paginate @feed_items %> <% end %>
投稿した時に表示エラー
createアクションで失敗に分岐した時は@feed_itemがないのでエラーになる。
@feed_itemをその分岐の中でも作ってあげると解決