Ruby on RailsでユーザIDと入力データの関連付けをする

前回の記事では、Deviseを利用して、ユーザ認証を実装しました。今回はその続きでログインユーザ自身が入力したデータのみ参照・追加・更新が出来るようにデータのアクセスコントロールをしていこうを思います。

実装仕様

1. ログインしたユーザ自身が投稿した内容しか表示されない。
2. もちろんですが、ログインしないと投稿が出来ない。

上記のイメージで作っていきたいと思います。

利用環境

今回の利用したRails環境は以下のとおりです。

OS:    Windows XP (そろそろ変えたい…)
Ruby:  Ruby 2.0.0p247
Rails: Rails 4.0.0
* 前回の記事内容のDevise実装が出来ている事とします。

実施内容

まず、scaffoldを利用して、postsモデルとビューを作成とdb:migrate

$ rails generate scaffold post content:string
$ bundle exec rake db:migrate

postsモデルにuser_idを追加する。

$ rails generate migration add_user_id_to_posts user_id

user_idの型をIntegerに変更

ファイル:db/migrate/(日付時間)_add_user_id_to_posts.rb
以下の記述に変更
add_column :posts, :user_id, :integer

db:migrateを実施し、DBに変更を反映する。

$ bundle exec rake db:migrate

モデル間の関係を記載する。

1. postsがusersに所属している。かつpostのuser_idは必須
ファイル:app/models/post.rb
以下の記述を追加
belongs_to :user
validates :user_id, presence: true

2. usersとpostsは1対多になる。
ファイル:app/models/user.rb
以下の記述を追加
belongs_to :user

コントローラを修正する。自分が投稿した内容のみを表示するようにする。

current_userというDeviseのヘルパーを利用すると、現在ログインしているuserオブジェクトを返してくれるみたいなので、それを利用する。基本現状Postとなっている箇所をcurrent_user.postsに変更する。

ファイル:app/controllers/posts_controller.rb
まずは、以下の記述を追加
before_filter :authenticate_user!

修正1:自分で投稿した内容のみ表示する。(index)
・修正前
  def index
    @posts = Post.all
  end

・修正後
  def index
    @posts = current_user.posts.all
  end

修正2:自分で投稿した内容のみ表示する。(show)
・修正前
    def set_post
      @post = Post.find(params[:id])
    end

・修正後
    def set_post
      @post = current_user.posts.find(params[:id])
    end

修正3:セキュリティの設定をいじって、user_idデータも許すようにする。
・修正前
    def post_params
      params.require(:post).permit(:content)
    end

・修正後
    def post_params
      params.require(:post).permit(:content, :user_id)
    end

ビューを修正する。_form.html.erb(newとeditで利用している)のviewを修正。内容は、user_idをhiddenで追加して、Submitするようにする。

ファイル:app/views/posts/_form.html.erb
・修正前
  <div class="field">
    <%= f.label :content %><br>
    <%= f.text_field :content %>
  </div>

・修正後
  <div class="field">
    <%= f.label :content %><br>
    <%= f.text_field :content %>
    <%= f.hidden_field :user_id, value: current_user.id %>
  </div>

これで、ログインしたユーザの投稿内容のみ表示できるようになりました。今日の所は疲れたので、ここまでとします。