Rails チュートリアル13章

今回は13章をやっていく中で必要だと思ったところをメモしていきます。

 

・複合キーインデックス

micropostのマイグレーションファイル

 
 
class CreateMicroposts < ActiveRecord::Migration[6.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_idに紐付けられたmicropostsを作成順(今回は作成の逆順にする)で取り出す
 
・default scope
 
 Micropostモデル
class Micropost < ApplicationRecord
  belongs_to :user
  default_scope -> { order(created_at: :desc) }
  validates :user_id, presence: true
  validates :content, presence: true, length: { maximum: 140 }
end
 
このようにして作成の逆順で取り出すよう設定している。
 
 
・time_ago_in_wordsメソッド
 
app/views/microposts/_micropost.html.erbapp/views/microposts/_micropost.html.erb
 
<li id="micropost-<%= micropost.id %>">
  <%= link_to gravatar_for(micropost.user, size: 50), micropost.user %>
  <span class="user"><%= link_to micropost.user.name, micropost.user %></span>
  <span class="content"><%= micropost.content %></span>
  <span class="timestamp">
    Posted <%= time_ago_in_words(micropost.created_at) %> ago.
  </span>
</li>
何分前とかって出るようにする。例えば3分前、3時間前、3日前。
 
 
マクロポストの作成(build)
 
root_pathのhomeでuserに紐ずくmicropostを作成する。
何かに紐付いたものを生成する場合、newではなくbuildになる。
作成はhomeで保存はmicropostのcreate
 
app/controllers/static_pages_controller.rb
class StaticPagesController < ApplicationController

  def home
    @micropost = current_user.microposts.build if logged_in?
buildになっている
end def help end def about end def contact end end
 
app/views/static_pages/home.html.erb
<% 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 %>
  <div class="center jumbotron">
    <h1>Welcome to the Sample App</h1>

    <h2>
      This is the home page for the
      <a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a>
      sample application.
    </h2>

    <%= link_to "Sign up now!", signup_path, class: "btn btn-lg btn-primary" %>
  </div>

  <%= link_to image_tag("rails.svg", alt: "Rails logo", width: "200px"),
              "https://rubyonrails.org/" %>
<% end %>
 
app/views/shared/_user_info.html.erb 
<%= link_to gravatar_for(current_user, size: 50), current_user %>
<h1><%= current_user.name %></h1>
<span><%= link_to "view my profile", current_user %></span>
<span><%= pluralize(current_user.microposts.count, "micropost") %></span>
 
app/views/shared/_micropost_form.html.erb
<%= form_with(model: @micropost, local: true) do |f| %>
  <%= 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 %>
 
app/controllers/microposts_controller.rb
 
class MicropostsController < ApplicationController
before_action :logged_in_user, only: [:create, :destroy]
before_action :correct_user, only: :destroy

def create
@micropost = current_user.microposts.build(micropost_params)
buildを使ってる
@micropost.image.attach(params[:micropost][:image])
if @micropost.save
flash[:success] = "Micropost created!"
redirect_to root_url
else
@feed_items = current_user.feed.paginate(page: params[:page])
render 'static_pages/home'
end
end
 
feed
 
class User < ApplicationRecord
  .
  .
  .
  # 試作feedの定義
  # 完全な実装は次章の「ユーザーをフォローする」を参照
  def feed
    Micropost.where("user_id = ?", id)
  end

    private
    .
    .
    .
end
 ?を使うことでidをエスケープしている
SQL文に変数を代入する場合は常にエスケープする必要がある。
 
app/controllers/static_pages_controller.rb
 
class StaticPagesController < ApplicationController

  def home
    if logged_in?
      @micropost  = current_user.microposts.build
このmicropostは先ほど書いたやつ(build)なので関係ない
@feed_items = current_user.feed.paginate(page: params[:page]) end end def help end def about end def contact end end
app/views/static_pages/home.html.erb
<% 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 class="col-md-8">
      <h3>Micropost Feed</h3>
      <%= render 'shared/feed' %>
    </div>
  </div>
<% else %>
  .
  .
  .
<% end %>

 

app/views/shared/_feed.html.erb

<% if @feed_items.any? %>
  <ol class="microposts">
    <%= render @feed_items %>
  </ol>
  <%= will_paginate @feed_items %>
<% end %>

 

<%= render @feed_items %>

@feed_itemsはMicropostsのクラスを持っているため、micropostsのパーシャルを呼び出すことができた。

app/views/microposts/_micropost.html.erbを呼び出してる

 

microposts作成失敗の場合に備えて

app/controllers/microposts_controller.rb

class MicropostsController < ApplicationController
  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
      @feed_items = current_user.feed.paginate(page: params[:page])
      render 'static_pages/home'
    end
  end

  def destroy
  end

  private

    def micropost_params
      params.require(:micropost).permit(:content)
    end
end

 

ページネートでエラーが出るので解決。

micropostsをcreateするcreateアクションがMicropostsコントローラーにあるので、Micropostsコントローラーでページネートしようとしている。

そこで、コントローラーとアクションを指定してあげることで解決する。

app/views/shared/_feed.html.erb

<% if @feed_items.any? %>
  <ol class="microposts">
    <%= render @feed_items %>
  </ol>
  <%= will_paginate @feed_items,
                    params: { controller: :static_pages, action: :home } %>
<% end %>