2016-01-29 13 views
13

であるポリシー。Railsの評論家&ステーツマン宝石と4 - オブジェクトが私は政策の政治状態のための宝石、その後、評論家を使用しようとしていますRailsの4</p> <p>でアプリを作るしようとしている状態

私gemfileがあります

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

私は記事のモデルと記事遷移モデルとarticle_state_machineモデルを持っています。

私の目的は、記事を所有しているユーザーが記事が「承認済み」の状態で公開することを許可する自分の記事ポリシーで(評論家を使用して)公開ポリシーを定義することです。私は評論家の記事政策でこれをしようとしています

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'

ポリシーでステートマシンを使用するにはどうすればよいですか?それとも、ポリシーがユーザーにいつでも公開できるようにすることを意図していますが、記事が州の承認を得ているときは、記事の表示ページにボタンを表示するだけです(ただし、

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の 'authorize'と呼んでいますか? –

+0

良い点。 authorize @ articleをパブリッシュアクションに追加すると、StatesController :: TransitionFailedErrorがArticlesControllerで公開されます。 'パブリッシュ'から 'パブリッシュ'への切り替えができません – Mel

+0

Punditの部分に問題はないようです。理由は例外メッセージ/スタックトレースのどこかにあるはずです。 BTWのbangメソッド 'transition_to!'は、 'false'を返す代わりに例外を発生させます。 non-bangメソッドを使用し、その例外をキャッチしない場合は適切なエラーメッセージを出力することをお勧めします(プログラムフローの例外を使用するのは良い考えではありません)。 –

答えて

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、私はそれを試みましたが、このエラーが発生します:NoContentControllerのNoMethodError#公開 未定義のメソッド 'in_state 'for# Mel

+0

文書によると、in_stateを使用しないでください。疑問符で マシン番号in_state?(:state_1、:state_2、...) – Guilherme

+0

私もそれを試しました – Mel

2

あなたは、メソッドの最後に?を逃している:

in_state方法は、実際にクラスメソッドで、スコープのように動作します。

あなたはこのように、インスタンスメソッドであるin_state?メソッドを使用する必要があります。

article.state_machine.in_state?(:approve)

関連する問題