【Rails】deviseでUserの子要素のvalidationにcurrent_userを使いたい


ユーザー(User)が複数の記事(article)を一対多で持っている。
そしてユーザーは記事の作成・更新・削除を行うことができる。

このような実装を行った際、記事の所有者がdeviseのヘルパーであるcurrent_useであることをチェックするためにタイトルのような処理が必要となりました。

更新処理時のチェックとなるとモデルで行った方が自然。
しかしdeviseのヘルパーcurrent_userですが、モデルでは使用することができません。

その為更新処理前にモデルに対してcurrent_userを渡してあげる必要がありました。
データ更新処理の前に @article.current_user = current_user を追加します。

実装

articles_controller.rb
...(省略)
  def update
    @article = Article.find(params[:id])
    @article.current_user = current_user  # これを追加
    if @article.update_attributes(article_params)
      flash[:success] = "記事を更新しました"
      redirect_to articles_url
    else
      render 'edit'
    end
  end
...(省略)

これでモデルにcurrent_userが受け渡されたので、モデル側のバリデーションに使うことができます。

article.rb
...(省略)
  validate :check_user
  attr_accessor :current_user
...(省略)
  def check_user
    errors[:current_user] = "user does not have permission" unless user == current_user
  end

これでたとえば
http://[ドメイン]/articles/[article.id]
にURLで直接アクセスし、更新したり、POSTで更新を行ったとしても更新エラーとなります。

その他

これで更新時に記事の所有者チェックが行われるようになりました。
しかし実際には更新画面に遷移させないべきですし、削除時にはvalidationが動いてくれないため、
before_destroyの使用やコントローラーでのチェックが必要となります。
deviseは便利で頼もしいgemですが標準ヘルパーのみで油断していると致命的なセキュリティ問題を抱えかねませんので注意していきたいですね。

もし関連付け段階でもっといい実装方法などありましたら、教えていただけると大変ありがたいです。