Question

I'm making an app with adding posters and it's moderation. I have two roles: admin and user. User can create poster and can update it. When user finishes he push the button "push" and the poster pushed for moderation, so admin can accept it or reject. What I want to do that after "push" action, when user's poster has satate "pushed", user couldn't change the poster. Here some of my files:

ability.rb

class Ability
include CanCan::Ability

def initialize(user)
  user ||= User.new # guest user (not logged in)
  if user.has_role? :admin
    can :manage, :all
    cannot :create, Poster
  end
  can :read, Poster

  if user.has_role? :user
    can :create, Poster
    can :update, Poster, user_id: user.id
    cannot :update, Poster, state: "pushed"
    can :destroy, Poster, user_id: user.id

  end

poster.rb

class Poster < ActiveRecord::Base
  has_many :poster_images, dependent: :destroy
  accepts_nested_attributes_for :poster_images, allow_destroy: true
  belongs_to :type
  belongs_to :user
  default_scope -> { order('created_at DESC') }

  validates :title, :body, :publish_date, :user_id, :type_id, presence: true


  state_machine initial: :draft do

    event :push do
      transition draft: :pushed
    end

    event :reject do
      transition pushed: :rejected
    end

    event :accept do
      transition pushed: :accepted
    end

    event :publish do
      transition accepted: :published
    end

    event :archive do
      transition published: :archived
    end
  end
end

posters_controller.rb

class PostersController < ApplicationController
  before_action :authenticate_user!, except: [:index, :show]
  authorize_resource except: [:push, :my_posters]
  load_resource except: :create
  # GET /posters
  # GET /posters.json
  def index
    @posters = Poster.paginate(page: params[:page], per_page: 10)
  end

  # GET /posters/1
  # GET /posters/1.json
  def show; end

  def admin_show
    @posters = Poster.paginate(page: params[:page], per_page: 10)
  end

  def my_posters
    @posters = Poster.paginate(page: params[:page], per_page: 10)
  end

  # GET /posters/new
  def new; end

  # GET /posters/1/edit
  def edit

  end

  # POST /posters
  # POST /posters.json
  def create
    @poster = Poster.new(poster_params)
    @poster.user_id = current_user.id
    @poster.publish_date = DateTime.now
    respond_to do |format|
      if @poster.save
        format.html { redirect_to @poster, notice: 'Poster was successfully created.' }
      else
        format.html { render action: 'new' }
      end
    end
  end

  # PATCH/PUT /posters/1
  # PATCH/PUT /posters/1.json
  def update
    respond_to do |format|
      if @poster.update(poster_params)
        format.html { redirect_to @poster, notice: 'Poster was successfully updated.' }
      else
        format.html { render action: 'edit' }
      end
    end
  end

  # DELETE /posters/1
  # DELETE /posters/1.json
  def destroy
    @poster.destroy
    respond_to do |format|
      format.html { redirect_to posters_url }
    end
  end

  [:accept, :reject, :publish].each do |method_name|
    define_method method_name do
      @poster.send(method_name)
      flash[:notice] = "#{method_name.capitalize} was successful."
      redirect_to posters_path
   end
  end

  [:push].each do |method_name|
    define_method method_name do
      @poster.send(method_name)
      flash[:notice] = "#{method_name.capitalize} was successful."
      redirect_to posters_path
    end
  end

  private
    # Never trust parameters from the scary internet, only allow the white list through.
    def poster_params
      params.require(:poster).permit(:title, :body, :type_id, :type_name,
      poster_images_attributes: [:image, :id] )
    end  
end

As I understand, I wrote cannot :update, Poster, state: "pushed"(in my migration I have state as a string), and it should work, but user, after push-button still can change the poster, although poster changes it's state to pushed. What do I do wrong?

Was it helpful?

Solution

I found stupid mistake. Everything is ok except controller. I had to do this

authorize_resource except: [:push, :my_posters, :edit]

and this

def edit
  authorize! :update, @poster
end

everything works.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top