subtitle

RaiseTechの各種コースをはじめとしたイロイロな学習の記録

Railsでツイート機能を実装してみる

先日から作成しているサンプルプロジェクトの続き。

deviseというgemを使って、ログイン認証機能を付けたアプリに対して、ツイート機能を実装してみる。


データベースの基本構成は、下記の通り。

user

  • id
  • email
  • encrypted_password

tweet

  • id
  • body
  • user_id


ターミナルから下記コマンドを打ち、usersというコントローラを作成し、indexとshowアクションを生成しておく。

deviseでusers用のモデルは生成済のため、usersに関しては、ここではコントローラだけ作成すればOK。

rails g controller users index show

ルーティングも自動でindexとshowが追加されているが、あとで編集するのでそのままにしておく。


tweet用のコントローラとモデルを作成する。(マイグレーションも忘れずに実施する)

rails g model Tweet body:text user_id:integer
rails g controller tweets new index show create
rails db:migrate

いろいろとわさわさできた。



ここから手動でコードをカサカサ変えていく

config/routes.rb

ルーティングは、もともと作ってあったサンプル画面のhello_catsをコメントアウトして、先ほど作成したtweetsに変更。

Rails.application.routes.draw do
  root 'tweets#index'
  devise_for :users
  resources :tweets
  resources :users
#  get 'hello_cats/index', to: 'hello_cats#index'
#  root 'hello_cats#index'
end


app/controllers/users_controller.erb

usersコントローラでは、indexアクションでUserデータ全取得、showアクションで該当IDのデータを取得。

before_actionの使い方については、こちらの記事を参照。(ログイン前のユーザーに対してはログインページにリダイレクトさせる。)

class UsersController < ApplicationController
  before_action :authenticate_user!
  def index
    @users = User.all
  end

  def show
    @users = User.find(params[:id])
  end
end


app/controllers/tweets_controller.erb

index画面以外は、ログイン前のユーザーはログイン画面にリダイレクト。

class TweetsController < ApplicationController
  before_action :authenticate_user!, exept: [:index]
  def new
    @tweets = Tweet.new
  end

  def index
    @tweets = Tweet.all
  end

  def show
    @tweets = Tweet.find(params[:id])
  end

  def create
  end
end


app/views/layouts/application.html.erb

ツイート機能に関するページへのリンクを追加

<body>
  <header>
    <nav>
      <% if user_signed_in? %>
        <%= link_to '新規投稿', new_tweet_path %>    #追加
        <%= link_to 'マイページ', user_path(current_user.id) %>    #追加
        <%= link_to '登録内容変更', edit_user_registration_path %>
        <%= link_to 'ログアウト', destroy_user_session_path, method: :delete %>
      <% else %>
        <%= link_to '新規登録', new_user_registration_path %>
        <%= link_to 'ログイン', new_user_session_path %>
      <% end %>
        <%= link_to 'ツイート一覧', tweets_path %>    #追加
        <%= link_to 'ユーザー一覧', users_path %>     #追加
    </nav>
  </header>
  <p class="notice"><%= notice %></p>
  <p class="alert"><%= alert %></p>
  <%= yield %>
</body>


app/views/tweets/index.html.erb

<h1>Tweets#index</h1>
<p>Find me in app/views/tweets/index.html.erb</p>

<% @tweets.each do |tweet| %>
  <hr size="5">
  <p><span>ツイート内容:</span><%= link_to tweet.body, tweet_path(tweet.id) %></p>
<% end %>


app/views/tweets/new.html.erb

<h1>Tweets#new</h1>
<p>Find me in app/views/tweets/new.html.erb</p>

<%= form_for @tweets do |f| %>
  <p>
    <%= f.label :body, "ツイート" %>
    <%= f.text_field :body %>
  </p>
  <%= f.submit %>
<% end %>


app/views/tweets/show.html.erb

<h1>Tweets#show</h1>
<p>Find me in app/views/tweets/show.html.erb</p>
<hr size="5">
<p><span>ツイート内容:</span><%= @tweet.body %></p>


app/views/users/index.html.erb

<h1>Users#index</h1>
<p>Find me in app/views/users/index.html.erb</p>

<% @users.each do |user| %>
  <hr size="5">
  <p><span>email: </span><%= link_to user.email, user_path(user.id) %></p>
<% end %>


app/views/users/show.html.erb

<h1>Users#show</h1>
<p>Find me in app/views/users/show.html.erb</p>

<hr size="5">
<p><span>email: <.span><%= @users.email %></p>


app/models/user.erb

1ユーザーにつき、たくさんのtweetが紐づくので、userモデルに「has_many :tweets」を追加する。

class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable
  has_many :tweets      #追加
end


app/models/tweet.erb

今度は逆に、tweetは必ずユーザーが一意に決まるので、tweetモデルに「belongs_to :user」を追加する。

class Tweet < ApplicationRecord
  belongs_to :user      #追加
end


app/controllers/tweets_controller.erb

再度tweets_controller.erbに戻り、createアクションを追加する。

  def create
    @tweets = Tweet.new(tweet_params)
    @tweets.user_id = current_user.id
    @tweets.save
    redirect_to tweets_path
  end
  private
    def tweet_params
      params.require(:tweet).permit(:body)
    end


それっぽいのができた。