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.
質問
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?
解決
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.