2016-01-29 3 views
13

Ich versuche, eine app in Rails 4.Rails 4 mit Pundit & Statesman gem - Politik, wenn ein Objekt in einem Zustand ist,

ich für Staaten Staatsedelstein zu verwenden, ich versuche zu machen und dann Pandit für die Politik.

Mein gemfile hat:

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

Ich habe einen Artikel Modell und einen Artikel Transitionen Modell und ein article_state_machine Modell.

Mein Ziel ist es, eine Veröffentlichungsrichtlinie (mit Pandit) in meiner Artikelrichtlinie zu definieren, die es einem Benutzer, der einen Artikel besitzt, erlaubt, diesen Artikel zu veröffentlichen, wenn er im Status 'genehmigt' ist.

Ich versuche, dies in meiner Pandit Artikel Politik:

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 

Wenn ich versuche, zu überprüfen, ob der Artikel im Zustand: genehmigen (wie oben auf Kommentar), erhalte ich eine Fehlermeldung, die nicht definierte Methode sagt "in_state".

Wie kann ich State Machine in der Richtlinie verwenden? Oder ist es beabsichtigt, dass die Richtlinie dem Benutzer erlaubt, jederzeit zu veröffentlichen, aber Sie nur die Schaltfläche auf der Artikelshow anzeigen, wenn der Artikel im Status genehmigt ist (obwohl ich dachte, dass das der Sinn des Pandits war).

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 

Artikel Zustandsmaschinenmodell:

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 

Artikel Übergangsmodell:

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


    belongs_to :article, inverse_of: :article_transitions 



end 

Artikel Controller:

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 

Kann jemand sehen, was ich falsch gemacht habe?

Der gesamte Artikel Controller hat:

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

Wo nennst du Pundits "autorisieren"? –

+0

Guter Punkt. Wenn ich der Veröffentlichungsaktion authorize @ article hinzufüge, erhalte ich einen Fehler, der besagt: Statesman :: TransitionFailedError in ArticlesController # publish Kann nicht von "publish" zu "publish" wechseln – Mel

+0

Dann scheint es, dass es auf Pundits Part kein Problem gibt. Der Grund sollte irgendwo in der Ausnahmemeldung/Stack-Trace sein. BTW die Bang-Methode 'transition_to!' Löst Ausnahmen aus, anstatt 'false' zurückzugeben. Es könnte eine gute Idee sein, die non-bang-Methode zu verwenden und die entsprechende Fehlermeldung auszugeben, wenn Sie diese Ausnahmen nicht fangen (das Verwenden von Ausnahmen für den Programmablauf ist sowieso keine gute Idee). –

Antwort

3

Die Version von Staats Juwel Sie verwenden nicht in_state? definiert hat. Sie können den Edelstein aktualisieren.Oder Sie es definieren können sich ähnliche Codes als verbunden durch smallbuttoncom

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

jedoch für Ihren Fall eine einfache Überprüfung sollte genügen. Versuchen Sie folgenden Code in Ihrer Richtlinie

article.state_machine.current_state == "approve" 

Hoffe, dass hilft.

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'.

Haben Sie versucht, article.in_state zu ändern? (: Genehmigen) article.state_machine.in_state? (: Genehmigen) in Ihrer Politik ?.

+0

Guter Punkt Guilherme, habe ich das versucht, aber es gibt diesen Fehler: NoMethodError in ArticlesController # veröffentlichen undefined Methode 'in_state 'für # Mel

+0

Nach den Dokumenten sollten Sie nicht in_state verwenden? mit einem Fragezeichen. Maschine # in_state? (: State_1,: state_2, ...) – Guilherme

+0

Ich habe das auch versucht – Mel

2

Sie vermissen die ? am Ende des Verfahrens:

die in_state Methode ist eigentlich eine Klassenmethode und verhält sich wie ein Rahmen.

Sie müssen die in_state? Methode verwenden, die eine Instanzmethode ist, wie folgt aus:

article.state_machine.in_state?(:approve)