rails 開発日記3  投稿機能

# 投稿機能の実装

＊この記事は技術や知識の共有目的ではなく、完全に自己満足のアウトプット用です。

＜開発環境＞
1. ruby 2.6.3
2. Rails 5.1.6
3. AWS Cloud9
4. GitHub
5. Heroku（予定）
6. sqlite3(develop環境)

今回は投稿、投稿編集、投稿削除の基本的な動作を実装しました。

## 投稿

### postモデルの作成

``` 
rails g model Posts content:text user:reference image:string
```
postテーブルを作るときにreferenceを用いることでテーブルにuser_idカラムが自動で生成されます。
また、foreign_key: trueを記載することで外部キー制約をつけることができます。

### モデルの関連付け

投稿の編集、削除機能を作る事前準備をします。
Postモデルに
``` belongs_to :user ```
Userモデルに
``` has_many :posts ```

これでモデルの関連付けをし、Railsは参照先のデータを取得したり削除できるメソッドを追加してくれます。

### マイグレーション
``` rails db:migrate ```

### コントローラーの作成
``` rails g controller posts new ```

ルーティングに
``` resources :posts ```
を追加する。

```
class PostsController < ApplicationController
  before_action :ensure_correct_user, {only: [:edit, :update, :destroy]}
  
  def new
    @post = Post.new
  end
  
  def create
    @post = current_user.posts.new(post_params)
    
    @post.save
    flash[:notice] = "投稿に成功しました"
    redirect_to user_path(current_user.id)
  end
  
  
  def show
    @post = Post.find(id: params[:id])
  end
  
  def edit
    @post = Post.find_by(id: params[:id])
  end
  
  def update
    @post = Post.find_by(id: params[:id])
    @post.image = params[:image]
    @post.content = params[:content]
    @post.update(post_params)
    redirect_to user_path(current_user.id)
  end
  
  def destroy
    @post = Post.find_by(id: params[:id])
    @post.destroy(post_params)
    redirect_to user_path(current_user.id)
  end
  
  def ensure_correct_user
    @post = Post.find_by(id: params[:id])
    if current_user.id != @post.user_id
      flash[:notice] = "権限がありません"
      redirect_to user_path(current_user.id)
    end
  end
  
  private
  def post_params
    params.require(:post).permit(:image, :content)
  end

end
```

ensure_correct_userメソッドを追加することで、ログイン中のユーザー以外が自分の投稿を編集、削除することを防ぐようにしています。（viewの設定だけではurlから直接編集ページに飛べてしまう。）

これでコントローラーの設定は完了です。

### viewを整える

今回はTwiiterを参考にして、マイページに投稿画面、投稿一覧画面を載せました。
<img width="1440" alt="スクリーンショット 2020-04-20 16.40.51.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/618929/aee5ea85-44a1-a3aa-1796-886880032b0f.png">

show.html.erb

```
<div class="user-show-wrapper">
  <div class="container">
    <div class="row">
      <div class="col-md-3 text-center">
        <section class="user_info">
          <h1>
            <%= @user.name %>
          </h1>
          <%= form_for @post do |f| %>
            <div class="field-image">
              <%= f.label :image, class: "white" %>
              <%= f.file_field :image%>
            </div>
            <div class="form-group">
              <%= f.label :content, class: "white" %>
              <%= f.text_area :content, class: 'form-control' %>
            </div>
            <%= f.submit '投稿', class: 'btn btn-black btn-block' %>
          <% end %>
        </section>
      </div>
      <div class="col-md-6">
        <div class="post-index-wrapper">
          <div class="container">
            <div class="col-md-6">
              <% @posts.each do |post| %>
                  <div class="post-index-single">
                    <h2 class="post-author">
                      <%= post.user.name %>
                    </h2>
                      <%= image_tag post.image.url if post.image? %>
                    <p class="post-text">
                      <%= post.content %>
                    </p>
                    <% if post.user_id == current_user.id && user_signed_in? %>
                      <%= link_to '編集', edit_post_path, class: 'btn btn-default' %>
                      <%= link_to '削除', post_path, method: :delete, class: 'btn btn-default' %>
                    <% end %>
                  </div>
              <% end %>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
```


左側の投稿フォームはstickyを用いることでスクロールしてもそのまま固定されるようにしています。

custom.css

```
.col-md-3{
position: -webkit-sticky;
position: sticky;
top: 60px;
}
```

これで投稿機能は完成です！