Search code examples
ruby-on-railsrubyruby-on-rails-4pundit

Authorization settings using pundit gem rails


I'm new at rails so bear with me pls. My problem is so specific. I'm creating a User blog, where they could put any posts. So Users has a blogs, and blogs has posts. So when user create a blog, all posts in his blog should be written by him. Other users can't write not on their blogs.

post_controller.rb

class PostsController < ApplicationController
  before_action :authenticate_user!
  before_action :authorize_user!, only: [:edit, :update, :destroy]

  expose :blog
  expose :post

  def show
  end

  def new
  end

  def edit
  end

  def create
    post.user = current_user
    post.save
    respond_with post, location: user_blog_path(post.blog.user, post.blog)
  end

  def update
    post.update(post_params)
    respond_with post, location: user_blog_path(post.blog.user, post.blog)
  end

  def destroy
    post.destroy
    respond_with post, location: user_blog_path(post.blog.user, post.blog)
  end

  private

  def authorize_user!
    authorize(post, :authorized?)
  end

  def post_params
    params.require(:post).permit(:title, :content, :user_id, :blog_id)
  end
end

Here i'm using pundit to authorize user, when they update or destroy posts (users can update or destroy only their own posts) and it works perfectly.

views/posts/new

.row
  .columns
    h2 = title("New post")

.row
  .medium-5.columns
    = simple_form_for post do |f|
      = f.error_notification

      .form-inputs
        = f.input :title
        = f.input :content
        = f.hidden_field :blog_id, value: blog.id
      .form-actions
        = f.button :submit

Here i'm using the hidden form to set the blog_id which I take from params. Http link looks like http://localhost:3000/posts/new?blog_id=6. The problem is that each user can copy this link to create the post( and they are not the blog owners).

post_policy.rb

class PostPolicy < ApplicationPolicy
  def authorized?
    record.user == user
  end
end

How should I check the blog's owner before post creating? Maybe I have a wrong way to create posts like this(using hidden form).

Link to create new post

= link_to 'New Post', new_post_path(blog_id: blog.id)

Solution

  • I hope, it will work for you

    application_controller.rb

      class ApplicationController
    
          include Pundit
    
          after_action :verify_authorized, except: :index
          after_action :verify_policy_scoped, only: :index
    
          before_action :authenticate_admin_user!
    
          helper_method :current_user
    
          def pundit_user
            current_admin_user
          end
    
          def current_user
            @current_user ||= User.find(current_admin_user.id)
          end
    
        end
    

    posts_controller.rb

    class PostsController < ApplicationController
    
      before_action :set_blog
    
      def new
        authorize(Post)
      end
    
      def edit
        @post = @blog.posts.find(params[:id])
        authorize(@post)
      end
    
      def index
        @posts = policy_scope(@blog.posts)
      end
    
      private
    
      def set_blog
        @blog = current_user.blogs.find(params[:blog_id])
      end
    
    end
    

    post_policy.rb

    class PostPolicy < ApplicationPolicy
    
      def show?
        true
      end
    
      def index?
        true
      end
    
      def new?
        create?
      end
    
      def create?
        true
      end
    
      def edit?
        update?
      end
    
      def update?
        scope_include_object?
      end
    
      def destroy?
        scope_include_object?
      end
    
      class Scope < Scope
    
        def resolve
          scope.joins(:blog).where(blogs: { admin_user_id: user.id })
        end
    
      end
    
      def scope_include_object?
        scope.where(id: record.id).exists?
      end
    
    end
    

    routes.rb

    Rails.application.routes.draw do
      devise_for :admin_users
    
      resources :blogs do
        resources :posts
      end
    end