【Rails】railsブログサイトの練習で躓いたところメモ

railsチュートリアル＋αでブログサイトを作成していて躓いたところをまとめました。

#環境
- ruby on rails 
- mysql
- docker
- macOS

#作ってみて
railsのブログアプリを作ること自体はそこまで難しいものではありませんでした。
ただデータベース周りがややこしくてそこにかなり時間をとられてしまったことが今回の反省点です。

#Rails deviceを使ってユーザー関連機能を作る
ブログアプリにまず必要なのはユーザー関連のあれこれです。Railsはその辺かなり楽に作れるdeviceというgemがあります。

deviceを利用するとログイン認証やアクセス制限などが簡単に実装出来ます。今まで練習も兼ねてユーザー関連は自分で作ってたのですが、一度こういった機能を知ってしまうと戻れなくなってしまいますね。

ここはそこまで詰まらなかったので以下の参考サイトを見れば大丈夫だと思います。

view関連なども「Rails device view」とかで調べたらたくさん出てきます。

【https://qiita.com/Hal_mai/items/350c400e8763ce0487a3】

【https://www.pikawaka.com/rails/devise】

【https://qiita.com/Hal_mai/items/350c400e8763ce0487a3】


#Rails scaffoldを使って投稿機能を作る
投稿機能はRailsのscaffoldが便利です。勝手にMVCを作ってくれます。

これも以下の記事を見たら出来るので割愛します。

【https://techacademy.jp/magazine/7204】

##注意点
ここで1つ注意点と言いますか、知っておいた方が良いなと個人的に思ったことを書きます。

先にあげたdeviceとscaffoldは大変便利な代物で、私みたいな初心者でも簡単に実装できてしまうものなのですが、これらはあくまで時短や効率化のためにあるものだと思うので初心者が最初から多用するのは危ないと思いました。

私はこのブログ練習サイトの前に3つほどscaffoldとdeviceなしで1から似たようなものを作って練習しているのですが、その練習がなかったらいきなりこれを使っても結局何をしてくれてるのか分からずじまいだったと思います。

分からないのに実装出来ちゃうからわかった気になってしまう危険性があるので、まずはMVCの理解を深めるためにもプロゲートやドットインストールなどの基本的なサイトを見て仕組みをなんとなくでも理解しながら進めていくのがいいのではないかと思いました。

#現在のユーザーとアクセス制限
##current_user
deviceにはオプションとしてcurrent_user（現在のユーザー）なるものがついています。

例えば「投稿者が他の投稿者の記事の編集や削除を出来ないようにする」といった時に便利な機能です。

今回は投稿の編集と削除を投稿者以外できないようにしたかったので、posts_controller.rbに以下のように記述しました。

```posts_controller.rb
before_action :ensure_correct_user, only: [:edit, :update, :destroy]
 
省略

private
 
省略

def ensure_correct_user
      if current_user.id!=@post.user.id
        flash[:notice]="Not yours"
        redirect_to(posts_path)
      end
end
``` 

private以下でensure_correct_userを定義して、before_actionでcurrent_user以外が使えないようにアクションに対して適応させています。
 
@post.user.idは投稿者のユーザーidのことです。これとcurrent_user.idが違ったら編集（update,edit）も削除（destroy）もできないですよって感じです。
 
 
##user_signed_in?
user_signed_in?はユーザーがログインしているかどうかを確かめます。

例えば「ログインしている時としていない時で表示内容を変えたい」といった時に使える機能です。

今回はviewにこんな感じで書きました。

```show.rb
<% if user_signed_in? %>
     <li class="nav-item active"><%= link_to("新規投稿", new_post_path,{class:"nav-link"}) %></li>
     <li class="nav-item active"><%= link_to("ログアウト", destroy_user_session_path,{method: :delete,data:{confirm: "ログアウトしますか？"},class:"nav-link"}) %></li>
<% else %>
     <li class="nav-item active"><%= link_to("新規登録", new_user_registration_path,{class:"nav-link"}) %></li>
     <li class="nav-item active"><%= link_to("ログイン", new_user_session_path,{class:"nav-link"}) %></li>
<% end %>
```

user_signed_in?していたら新規投稿・ログアウトを表示、していなかったら新規登録とログインを表示、という単純なものです。

これらもdeviceを使った機能なので基本的に書くだけで簡単に実装出来てしまうのですが、もし使わない場合だとインスタンス変数@current_userを定義するところから始めなければいけません。今回はそこは割愛しますが、その辺の仕組みもまた理解を深めるためにも記事にできたらと思います。

 
#ユーザーと投稿の紐付け
最初に躓いたのはここでした。ユーザーと投稿を用意できたはいいがこれをどうやって紐付けるかが問題です。

私はプロゲートに倣ってPostモデルにuser_idカラムを追加しました。記事を投稿するときにuser_idカラムにcurrent_user.idを入れて紐づけるといった感じです。

posts_controller.rbでscaffoldで自動生成されたpost_paramsのpermitにuser_idを追加します。

```posts_controller.rb
def post_params
       params.require(:post).permit(:title, :content, :user_id)
end
``` 

これでuser_idに値が届くようになります。

続いてapp/views/posts/_form.html.erbではuser_idを送信できるように以下のように変更します。

```app/views/posts/_form.html.erb
<div class="field">
    <%= form.label :記事内容 %>
    <%= form.text_area :content,value:@post.content %>
    <%= form.hidden_field :user_id, value: current_user.id %>
</div>
``` 

form.hidden_fieldを設置して、こっそりuser_idテーブルにvalueに設定したcurrent_user.idを送ります。これで投稿とユーザーの紐付けはおkです。

#追記（2020/02/09）
Redisの導入ですが[【Rails+Redis+Docker】RailsアプリにRedis導入＆ランキングの実装](https://qiita.com/soehina/items/9caef2b3dda17632fea8)に移動しました。
 
#まとめ
以上今回作ったブログサイトの大雑把なまとめでした。
初心者のメモ程度のものなので間違ってたり足りないところとかたくさんあると思いますが、初心者の方とかの参考になれば嬉しいです。
また、アドバイスなどあればコメントなどしてくれたら嬉しいです。
 
お付き合い頂きありがとうございました。