2016-01-29 1 views
13

Я пытаюсь сделать приложение в Rails 4.Rails 4 с пандита & Statesman драгоценный камень - политики, когда объект находится в состоянии

Я пытаюсь использовать государственный деятель камень для государств, а затем пандита для политики.

Мой Gemfile имеет:

gem 'statesman', '~> 1.3', '>= 1.3.1' 
gem 'pundit' 

У меня есть модель статьи и модель статьи переходов и модель article_state_machine.

Моя цель - определить политику публикации (используя pundit) в моей политике статей, которая позволяет пользователю, которому принадлежит статья, публиковать эту статью, если она находится в состоянии «одобрено».

Я пытаюсь это в моей политике Пандита статьи:

class ArticlePolicy < ApplicationPolicy 

def publish? 

user.present? && user == article.user 
# if requires approval, then approved 

# and article.in_state(:approve) - why doesnt this work - see statesman docs? 

# user && user.article.exists?(article.id) 

end 
end 

Когда я пытаюсь проверить, если изделие находится в состоянии: утвердить (как заметил выше), я получаю сообщение об ошибке, говорящее неопределенный метод 'in_state.

Как использовать конечный автомат в политике? Или предполагается, что политика позволяет пользователю публиковать все время, но вы показываете только кнопку на странице статьи, когда статья находится в состоянии одобрить (хотя я думал, что это была точка pundit).

Article.rb

class Article < ActiveRecord::Base 
    include Statesman::Adapters::ActiveRecordQueries 
has_many :transitions, class_name: "ArticleTransition", autosave: false 
def state_machine 
    @state_machine ||= ArticleStateMachine.new(self, transition_class: ArticleTransition, association_name: :transitions) 
    end 

    # delegate :can_transition_to?. :trans 

    # def reindex_articles 
    # article.reindex_async 
    # end 

    private 

    def self.transition_name 
    :transitions 
    end 

    def self.transition_class 
    ArticleTransition 
    end 

    def self.initial_state 
    # ArticleTransition.initial_state 
    :draft 
    end 
end 

Статья модель состояние машины:

class ArticleStateMachine 
    include Statesman::Machine 

    state :draft, initial: :true #while author is drafting 
    state :review #while approver comments are being addressed (really still in draft) 
    state :reject # not suitable for publication 
    state :approve # suitable for publication 
    state :publish #published 
    state :remove # destroyed 
    # state :spotlight 

    transition from: :draft, to: [:reject, :approve, :publish, :remove] 
    # transition from: :review, to: [:rejected, :approved, :removed] 
    transition from: :reject, to: [:draft, :remove] 
    transition from: :approve, to: [:publish, :remove] 
    transition from: :publish, to: :remove 

end 

Статья перехода Модель:

class ArticleTransition < ActiveRecord::Base 
    include Statesman::Adapters::ActiveRecordTransition 


    belongs_to :article, inverse_of: :article_transitions 



end 

Статья Контроллер:

def approve 
    article = Article.find(params[:id]) 
    if article.state_machine.transition_to!(:approve) 
     flash[:notice] = "This article has been approved for publication" 
     redirect_to action: :show, id: article_id 
     # add mailer to send message to article owner that article has been approved 
    else 
     flash[:error] = "You're not able to approve this article" 
     redirect_to action: :show, id: article_id 
    end 
    end 

def publish 
    article = Article.find(params[:id]) 
    authorize @article 

    if article.state_machine.transition_to!(:publish) 
     redirect_to action: :show, id: article_id 
     # how do you catch the date the state became published? 
    else 
     flash[:error] = "You're not able to publish this article" 
     redirect_to action: :show, id: article_id 
    end 
    end 

Может ли кто-нибудь увидеть, что я сделал неправильно?

Весь контроллер статьи имеет:

class ArticlesController < ApplicationController 
    before_action :set_article, only: [:show, :edit, :update, :destroy, :reject, :approve, :publish, :remove] 
    before_action :authenticate_user!, except: [:index, :show, :search, :reject, :approve, :publish, :remove] 


    respond_to :html, :json 
# GET /articles 
    # GET /articles.json 
    def index 
    @articles = policy_scope(Article) 
    # query = params[:query].presence || "*" 
    # @articles = Article.search(query) 
    end 

    # def index 
    # if params[:query].present? 
    #  @books = Book.search(params[:query], page: params[:page]) 
    # else 
    #  @books = Book.all.page params[:page] 
    # end 
    # end 

    # GET /articles/1 
    # GET /articles/1.json 
    def show 

    end 

    # GET /articles/new 
    def new 
    @article = Article.new 
    @article.comments.build 
    end 

    # GET /articles/1/edit 
    def edit 

    authorize @article 
    end 

    # POST /articles 
    # POST /articles.json 
    def create 
    # before_action :authenticate_user! 
    # authorize @article 
    @article = current_user.articles.new(article_params) 

    respond_to do |format| 
     if @article.save 
     format.html { redirect_to(@article) } 
     format.json { render :show, status: :created, location: @article } 
     else 
     format.html { render :new } 
     format.json { render json: @article.errors, status: :unprocessable_entity } 
     end 
    end 
    end 

    def search 
    if params[:search].present? 
     @articless = Article.search(params[:search]) 
    else 
     @articles = Articles.all 
    end 
    end 


    # PATCH/PUT /articles/1 
    # PATCH/PUT /articles/1.json 
    def update 
    # before_action :authenticate_user! 
    authorize @article 
    respond_to do |format| 
    # if @article.update(article_params) 
    #  format.json { render :show, status: :ok, location: @article } 
    # else 
    #  format.html { render :edit } 
    #  format.json { render json: @article.errors, status: :unprocessable_entity } 
    # end 
    # end 
     if @article.update(article_params) 
     format.html { redirect_to(@article) } 
     format.json { render :show, status: :ok, location: @article } 
     else 
     format.json { render json: @article.errors, status:  :unprocessable_entity } 
     end 
     format.html { render :edit } 
    end 
    end 



    # DELETE /articles/1 
    # DELETE /articles/1.json 
    def destroy 
    before_action :authenticate_user! 
    authorize @article 
    @article.destroy 
    respond_to do |format| 
     format.json { head :no_content } 
    end 
    end 

    # def review 
    # article = Article.find(params[:id]) 
    # if article.state_machine.transition_to!(:review) 
    #  flash[:notice] = "Comments on this article have been made for your review" 
    #  redirect_to action: :show, id: article_id 
    # else 
    #  flash[:error] = "You're not able to review this article" 
    #  redirect_to action: :show, id: article_id 
    # end 
    # end 

    def reject 
    end 

    def approve 
    article = Article.find(params[:id]) 
    if article.state_machine.transition_to!(:approve) 
     flash[:notice] = "This article has been approved for publication" 
     redirect_to action: :show, id: article_id 
     # add mailer to send message to article owner that article has been approved 
    else 
     flash[:error] = "You're not able to approve this article" 
     redirect_to action: :show, id: article_id 
    end 
    end 

    def publish 
    article = Article.find(params[:id]) 
    if article.state_machine.transition_to!(:publish) 
     redirect_to action: :show, id: article_id 
     # how do you catch the date the state became published? 
    else 
     flash[:error] = "You're not able to publish this article" 
     redirect_to action: :show, id: article_id 
    end 
    end 

    def remove 
    article = Article.find(params[:id]) 
    if article.state_machine.transition_to!(:remove) 
     redirect_to root_path 
    else 
     flash[:error] = "You're not able to destroy this article" 
     redirect_to action: :show, id: article_id 
    end 
    end 

    private 
    # Use callbacks to share common setup or constraints between actions. 
    def set_article 
     @article = Article.find(params[:id]) 
     authorize @article 
    end 

    # Never trust parameters from the scary internet, only allow the white list through. 
    def article_params 
     params.require(:article).permit(:body, :title, :image, :tag_list, 
     comment_attributes: [:opinion]) 
    end 

end 
+0

Где вы звоните "уполномочить" Pundit? –

+0

Хорошая точка. Когда я добавляю authorize @ article к действию публикации, я получаю сообщение об ошибке: Statesman :: TransitionFailedError в ArticlesController # publish Невозможно перейти из 'publish' to 'publish' – Mel

+0

Тогда, похоже, у Pundit нет проблем. Причина должна быть где-то в трассе исключения/стека исключений. Кстати, метод bang 'transition_to!' Вызывает исключения вместо возврата 'false'. Возможно, неплохо было бы использовать метод non-bang и напечатать соответствующее сообщение об ошибке, если вы не поймаете catch этих исключений (использование исключений для потока программы в любом случае не является хорошей идеей). –

ответ

3

версия государственного деятеля драгоценный камень используется не in_state? определена. Вы можете обновить драгоценный камень.Или вы можете определить его самостоятельно, используя подобные коды, как связаны smallbuttoncom

https://github.com/gocardless/statesman/blob/1fd4ee84c87765b7855688b8eb5dddea7ddddbdd/lib/statesman/machine.rb#L180-L182

Однако для случая, простая проверка должна быть достаточно. Попробуйте выполнить код в вашей политике

article.state_machine.current_state == "approve" 

Надеюсь, что это поможет.

2

When I try to check if the article is in state :approve (as commented out above), I get an error message that says undefined method 'in_state'.

Пытались ли вы изменить article.in_state? (: Утвердить) в article.state_machine.in_state? (: Утвердить) в политике ?.

+0

Хорошая точка Guilherme, я пробовал это, но он дает эту ошибку: NoMethodError в ArticlesController # publish undefined method 'in_state 'для # Mel

+0

В соответствии с документами вы не должны использовать in_state? с вопросительным знаком. Машина # in_state? (: State_1,: state_2, ...) – Guilherme

+0

Я тоже пробовал это – Mel

2

Вы пропускаете в ? в конце метода:

in_state метод на самом деле метод класса и ведет себя как сферу.

Вы должны использовать in_state? метод, который представляет собой метод экземпляра, например:

article.state_machine.in_state?(:approve)

Смежные вопросы