【Ruby on Rails】ログインユーザーのみが投稿できる投稿機能

# 目標


![post.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700999/09f6b09b-355c-bf28-8a29-087e59c1cd2d.gif)


# 開発環境
ruby 2.5.7
Rails 5.2.4.3
OS: macOS Catalina

# 前提
※　▶◯◯　を選択すると、説明等が出てきますので、
　　よくわからない場合の参考にしていただければと思います。

[deviseで名前ログイン環境構築](https://qiita.com/japwork/items/275110b810965fbdf72f)
controller名はpost（今回は投稿機能のみ）


# １、テーブルの作成
## Postモデルを追加
```:ターミナル
$ rails g model Post user:references title:string body:string
```
実行すると下記のようになり、カラムが追加され保存可能。

```rb:db/migrate/xxxxxxxxxxxxx_create_posts.rb
class CreatePosts < ActiveRecord::Migration[5.2]
  def change
    create_table :posts do |t|
      t.references :user, foreign_key: true
      t.string :title
      t.string :body

      t.timestamps
    end
  end
end

```
<details><summary>補足</summary>
t.references :user, foreign_key: trueはuserの外部キーになります。
外部キーに関しては、[こちら](https://qiita.com/kamillle/items/5ca2db470f199c1bc3ef)。</details>

```:ターミナル
$ rails db:migrate
```
## モデルを編集

```rb:app/models/post.rb
class Post < ApplicationRecord
  belongs_to :user
end
```

```rb:app/models/user.rb
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 :posts, dependent: :destroy ←ここを追加
end
```
<details><summary>解説</summary>
コントローラー作成時のuser:referencesにより、
post側にはbelongs_to :userと記述され、1投稿1投稿が誰の投稿か保存できる。
user側にはhas_many :posts, dependent: :destroyと追加することで
1対多の関係を作ることができ、1人のユーザーが多くの投稿ができる。
</details>

# ２、controllerの作成

```:ターミナル
$ rails g controller posts create new
```

```rb:app/controllers/posts_controller.rb
class PostsController < ApplicationController
  before_action :authenticate_user!
  def create
  	@post = Post.new(post_params)　　# 何を新しく保存するか指定
  	@post.user_id = current_user.id　　# 誰が投稿したかを指定
  	if @post.save　　# もし保存ができたら
   	 redirect_to new_post_path  # 投稿画面に遷移
  	else  # できなければ
   	 render :new  # newに遷移
  	end
  end

  def new
   @post = Post.new
   @posts = Post.all
  end

  private  # ストロングパラメーター（予期しない値を変更されてしまう脆弱性を防ぐ機能）
  def post_params
   params.require(:post).permit(:title, :body)  # titleとbodyの変更を許可
  end
end

```
<details><summary>補足</summary>
before_action :authenticate_user!と記述することで、
URLをベタ打ちしてもログインしていない限り、new・createアクションを実行できず、
ログイン画面に遷移するようにする。</details>

下記のように変更。

```rb:config/routes.rb
  get 'posts/create' ←削除
  get 'posts/new'　←削除
  resources :posts, only: [:create, :new] ←追加
```
↓変更後

```rb:config/routes.rb
Rails.application.routes.draw do
  devise_for :users, controllers: {
    sessions: 'users/sessions',
    registrations: 'users/registrations',
  }
  root 'homes#top'
  get 'mypage', to: 'homes#mypage'
  resources :posts, only: [:create, :new]　←追加
end
```
<details><summary>補足</summary>
resourcesはRESTfulなURLであり、getやpatchなどの記述を省略できる。</details>

# ３、Viewsの変更
app/views/posts/create.html.erb を右クリックで削除。

```erb:app/views/posts/new.html.erb
<h1>Posts#new</h1>
<span>現在ログイン中のユーザー：<%= current_user.name %></span>

<%= form_for(@post, url: posts_path) do |f| %>
	<div>
		<%= f.label :タイトル %><br>
		<%= f.text_field :title, autofocus: true %>
	</div>
	<div>
		<%= f.label :中身 %><br>
		<%= f.text_area :body %>
	</div>
	<div><%= f.submit "投稿する" %></div>
<% end %>


<table>
	<thead>
		<tr>
			<th>投稿者名</th>
			<th>タイトル</th>
			<th>本文</th>
		</tr>
	</thead>
	<tbody>
		<% @posts.each do |post| %>
			<tr>
				<td><%= post.user.name %></td>
				<td><%= post.title %></td>
				<td><%= post.body %></td>
			</tr>
		<% end %>
	</tbody>
</table>
```
<details><summary>補足</summary>
form_forヘルパーで投稿機能、eachメソッドで投稿内容取得。</details>

# P.S.
twitterではQiitaにはアップしていない技術や考え方もアップしていますので、
よければフォローして頂けると嬉しいです。
詳しくはこちら　https://twitter.com/japwork