50
58

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ツイッター風Railsアプリ最短復習(忙しい人の流し読みで開発シリーズ)

Last updated at Posted at 2020-03-17

はじめに

こんにch… え?忙しい?? んじゃぁスタート!!!

具体的な手順

完成品GitHub

①アプリ立ち上げ

Terminal
$ cd Desktop
$ rails _5.2.4.1_ new cheaptweet -d mysql
$ cd cheaptweet
$ rails db:create
$ rails s
webBrowser
localhost:3000
rails.png

②テーブル作成

cheaptweet.jpeg

Gemfile
# 省略
gem 'devise'
Terminal
$ bundle install
$ rails g devise:install

control + c
$ rails s

$ rails g devise user
db/migrate/2020xxxxxxxxx_devise_create_users.rb
# 省略
 t.string :nickname,           null: false
# 省略
Terminal
$ rails db:migrate
aa.png
Terminal
$ rails g model tweet
db/migrate/2020xxxxxxxxxxxx_create_tweets.rb
# 省略
 t.string :text, null: false
 t.references :user, foreign_key: true, null: false
# 省略
Terminal
$ rails db:migrate
text.png
app/models/user.rb
#省略
 validates :nickname ,presence: true
 has_many :tweets
#省略
app/models/tweet.rb
#省略
 validates :text ,presence: true
 belongs_to :user
#省略

③会員登録・ログイン・ログアウトのみの基本循環構築

app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_action :configure_permitted_parameters, if: :devise_controller?

  protected
  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:nickname])
  end
end
Terminal
$ rails g devise:views
app/views/devise/registrations/new.html.erb
<!--省略-->
<div class="field">
  <%= f.label :nickname %><br />
  <%= f.text_field :nickname, autofocus: true %>
</div>
<!--省略-->
<!--  他の autofocus: true を削除 -->
Terminal
$ rails g controller tweets index
config/routes.rb
# get 'tweets/index'

#    |
#    v

resources :tweets, only: [:index]
root 'tweets#index'
#省略
app/views/layouts/application.html.erb
<!--省略-->
<body>
<!--↓追記↓----------------------------------------------->
  <header style="height: 50px; background-color: grey;">
    <% if user_signed_in? %>
      <%= current_user.nickname %>
      <%= link_to "ログアウト", destroy_user_session_path, method: :delete %>
    <% else %>
      <%= link_to "ログイン", new_user_session_path %>
      <%= link_to "会員登録", new_user_registration_path %>
    <% end %>
    <%= link_to "トップへ", root_path, style:"float: right;" %>
  </header>
<!--↑追記↑---------------------------------------------->
  <%= yield %>
</body>
<!--省略-->
app/views/tweets/index.html.erb
<div>※確認用</div>

main1.png main2.png
sign_up.png
login.png

④投稿(new→create)

config/routes.rb
# resources :tweets, only: [:index]

#    |
#    V

resources :tweets, only: [:index, :new, :create]
#省略
app/controllers/tweets_controller.rb
class TweetsController < ApplicationController
  def index
  end
####↓追記↓################################################
  def new
    @tweet = Tweet.new
  end
  def create
    @tweet = Tweet.new(tweet_params)
    if @tweet.save
      redirect_to root_path
    else
      render action: :new
    end
  end
  private
  def tweet_params
    params.require(:tweet).permit(:text).merge(user_id: current_user.id)
  end
####↑追記↑#################################################
end
new.html.erb
<%= form_with(model: @tweet, local:true) do |f| %>
  <%= f.text_area :text %>
  <%= f.submit '投稿' %>
<% end %>
app/views/layouts/application.html.erb
<!--省略-->
<body>
  <header style="height: 50px; background-color: grey;">
    <% if user_signed_in? %>
      <%= current_user.nickname %>
<!--↓追記↓----------------------------------->
      <%= link_to "投稿", new_tweet_path %>
<!--↑追記↑----------------------------------->
      <%= link_to "ログアウト", destroy_user_session_path, method: :delete %>
    <% else %>
      <%= link_to "ログイン", new_user_session_path %>
      <%= link_to "会員登録", new_user_registration_path %>
    <% end %>
  </header>
  <%= yield %>
</body>
<!--省略-->
hellob.png hello.png

⑤一覧(index)

app/controllers/tweets_controller.rb
#省略
def index
####↓追記↓#####################################################
  @tweets = Tweet.all.includes(:user).order("created_at DESC")
####↑追記↑#####################################################
end
#省略
app/views/tweets/index.html.erb
× <div>※確認用</div>

<!--     |     -->
<!--     V     -->

<% @tweets.each do |t| %>
  <div><span style="color: red;"><%= t.user.nickname %></span><%= t.text %></div>
<% end %>
index.png includesなし              includesあり back1.png back2.png ## ⑥詳細(show)・編集(edit→update)・削除(destroy) ```ruby:config/routes.rb # resources :tweets, only: [:index, :new, :create]

|

V

resources :tweets
#省略


```ruby:app/controllers/tweets_controller.rb
#省略
def show
  @tweet = Tweet.find(params[:id])
end
#省略
app/views/tweets/index.html.erb
×  <div><span style="color: red;"><%= t.user.nickname %></span><%= t.text %></div>

<!--    |    -->
<!--    V    -->

<div><%= link_to tweet_path(t.id) do %><span style="color: red;"><%= t.user.nickname %></span><%= t.text %><% end %></div>
app/views/tweets/show.html.erb
<div><span style="color: red;"><%= @tweet.user.nickname %></span><%= @tweet.text %></div>
<%= link_to "編集",  edit_tweet_path(@tweet.id) %><%= link_to "削除",  tweet_path(@tweet.id),method: :delete  %>
app/controllers/tweets_controller.rb
#省略
def edit
  @tweet = Tweet.find(params[:id])
end
def update
  @tweet = Tweet.find(params[:id])
  if @tweet.update(tweet_params)
    redirect_to tweet_path(params[:id])
  else
    render action: :edit
  end
end
def destroy
  @tweet = Tweet.find(params[:id])
  @tweet.delete
  redirect_to root_path
end
#省略
app/views/tweets/edit.html.erb
<%= form_with(model: @tweet, local:true) do |f| %>
  <%= f.text_area :text %>
  <%= f.submit '投稿' %>
<% end %>

削除後確認画面が欲しければ、

app/controllers/tweets_controller.rb
#省略
def destroy
  @tweet = Tweet.find(params[:id])
  @tweet.delete
#  redirect_to root_path
end
#省略
app/views/tweets/destroy.html.erb
<div>削除しました</div>
<%= link_to "トップに戻る", root_path %>

⑦編集・削除の権限設定

app/views/tweets/show.html.erb
× <%= link_to "編集",  edit_tweet_path(@tweet.id) %><%= link_to "削除",  tweet_path(@tweet.id),method: :delete %>

<!--    |    -->
<!--    V    -->

<% if user_signed_in? && current_user.id == @tweet.user_id %>
  <%= link_to "編集",  edit_tweet_path(@tweet.id) %><%= link_to "削除",  tweet_path(@tweet.id),method: :delete %>
<% end %>
app/controllers/tweets_controller.rb
class TweetsController < ApplicationController
####↓追記↓###############################################
  before_action :unless_signin, only: [:new, :create,]
  before_action :unless_mytweet, only: [:edit, :update, :destroy]
####↑追記↑###############################################

#省略

  private

#省略

####↓追記↓###############################################
  def unless_signin
    redirect_to tweets_path unless user_signed_in?
  end
  def unless_mytweet
    redirect_to tweets_path unless user_signed_in? && current_user.id == Tweet.find(params[:id]).user.id
  end
####↑追記↑###############################################
end

⑧一覧ページネーション

Gemfile
#省略
gem 'kaminari'
Terminal
$ bundle install
Terminal
control + c
$ rails s
# @tweets = Tweet.all.includes(:user).order("created_at DESC")

#    |
#    V

@tweets = Tweet.includes(:user).order("created_at DESC").page(params[:page]).per(5)
app/views/tweets/index.html.erb
<!--省略-->
<%= paginate(@tweets) %>

⑨コメント機能

cheaptweet (2).jpeg

Terminal
$ rails g model comment
db/migrate/2020xxxxxxxx_create_comments.rb
#省略
  t.string :text, null: false
  t.references :user, foreign_key: true, null: false
  t.references :tweet, foreign_key: true, null: false
#省略
Terminal
$ rails db:migrate
comment.png
app/models/user.rb
#省略
 has_many :comments
#省略
app/models/tweet.rb
#省略
 has_many :comments
#省略
app/models/comment.rb
#省略
 validates :text, presence: true
 belongs_to :user
 belongs_to :tweet
#省略
config/routes.rb
# resources :tweets

#    |
#    V

resources :tweets do
  resources :comments, only: :create
end
app/controllers/tweets_controller.rb
#省略
def show
  @tweet = Tweet.find(params[:id])
####↓追記↓#############################################
  @comment = Comment.new
  @comments = Comment.where(tweet_id: params[:id]).order("created_at DESC").page(params[:page]).per(5)
####↑追記↑#############################################
end
#省略
Terminal
$ rails g controller comments
app/controllers/comments_controller.rb
class CommentsController < ApplicationController
  def create
    redirect_to tweets_path unless user_signed_in?
    @comment = Comment.new(params_comment)
    @comment.save
    redirect_to tweet_path(params[:tweet_id])
  end
  private
  def params_comment
    params.require(:comment).permit(:text).merge(user_id: current_user.id, tweet_id: params[:tweet_id])
  end
end
app/views/tweets/show.html.erb
<!--省略-->
<% if user_signed_in? %>
  <%= form_with(model: [@tweet, @comment], local: true) do |f| %>
    <%= f.text_area :text %>
    <%= f.submit 'コメント'%>
  <% end %>
<% end %>
<% if @comments %>
  <% @comments.each do |c| %>
    <div><span style="color: blue;"><%= c.user.nickname %></span><%= c.text %></div>
  <% end %>
  <%= paginate(@comments) %>
<% end %>
come.png ## ⑩ユーザー投稿一覧
Terminal
$ rails g controller users show
config/routes.rb
# devise_for :usersより下に
#省略
resources :users, only: :show
#省略
app/controllers/users_controller.rb
class UsersController < ApplicationController
  def show
    @tweets = Tweet.where(user_id: params[:id]).order("created_at DESC").page(params[:page]).per(5)
    @nickname = User.find(params[:id]).nickname
  end
end
app/views/layouts/application.html.erb
× <%= current_user.nickname %>

<!--      |       -->
<!--      V       -->

<%= link_to user_path(current_user.id) do %><%= current_user.nickname %><% end %>
app/views/tweets/index.html.erb
× <div><%= link_to tweet_path(t.id) do %><span style="color: red;"><%= t.user.nickname %></span><%= t.text %><% end %></div>

<!--      |       -->
<!--      V       -->

<div><%= link_to user_path(t.user.id),style:"color: red;" do %><%= t.user.nickname %><% end %><%= link_to tweet_path(t.id) do %><%= t.text %><% end %></div>
app/views/tweets/show.html.erb
× <div><span style="color: red;"><%= @tweet.user.nickname %></span><%= @tweet.text %></div>

<!--      |       -->
<!--      V       -->

<div><%= link_to user_path(@tweet.user.id),style:"color: red;" do %><%= @tweet.user.nickname %><% end %><%= @tweet.text %></div>
app/views/users/show.html.erb
<p><%= @nickname %>の投稿一覧</p>
<% @tweets.each do |t| %>
  <div><%= link_to tweet_path(t.id) do %><%= t.text %><% end %></div>
<% end %>
<%= paginate(@tweets) %>
anna.png ## ⑪検索機能 ```bash:Terminal rails g controller tweets::searches ```
config/routes.rb
#省略
 namespace :tweets do
   resources :searches, only: :index
 end
#省略
# resources :tweets do より上に
app/models/tweet.rb
#省略
  def self.search(search)
    if search
      Tweet.where('text LIKE(?)', "%#{search}%").includes(:user)
    else
      Tweet.all.includes(:user)
    end
  end
#省略
app/controllers/tweets/searches_controller.rb
class Tweets::SearchesController < ApplicationController
  def index
    @tweets = Tweet.search(params[:keyword]).order("created_at DESC").page(params[:page]).per(5)
  end
end
app/views/tweets/index.html.erb
<%= form_with(url: tweets_searches_path, local: true, method: :get) do |f| %>
  <%= f.text_field :keyword %>
  <%= f.submit "検索" %>
<% end %>
<!-- 省略 -->
app/views/tweets/searches/index.html.erb
<%= form_with(url: tweets_searches_path, local: true, method: :get) do |f| %>
  <%= f.text_field :keyword %>
  <%= f.submit "検索" %>
<% end %>
<% @tweets.each do |t| %>
  <div><%= link_to user_path(t.user.id),style:"color: red;" do %><%= t.user.nickname %><% end %><%= link_to tweet_path(t.id) do %><%= t.text %><% end %></div>
<% end %>
<%= paginate(@tweets) %>

まとめ

網羅的でいい教材ですね。

これで難しい場合は以下をまわってみてください。

超最低限のRailsアプリを丁寧に作る(もう一度きちんと復習して初心者を卒業しよう)
『メッセージを投稿』できる最低限のRailsアプリを丁寧に作る(これで初心者完全卒業!)

次のレベルに行きたければ以下に行ってみてください。

ツイッター風Railsアプリをデプロイする(前編:unicornのみで取り急ぎ繋げよう)
『メッセージと複数画像の投稿』ができる最低限のRailsアプリを丁寧に作る
『2ページ遷移して会員登録』できる最低限のRailsアプリを丁寧に作る(deviseをウィザード形式に拡張)
『非同期でのメッセージ投稿』が理解できる最低限のRailsアプリを丁寧に作る(Ajax苦手の自分とお別れしよう)

50
58
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
50
58

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?