2016-01-29 13 views
13

Próbuję złożyć aplikację w Rails 4.Szyny 4 z Pundit & Statesman gem - Polityka, gdy obiekt znajduje się w stanie

próbuję użyć Statesman gem dla państw, a następnie ekspert polityk.

Moja gemfile posiada:

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

Mam modelu artykułu oraz model przejścia artykułu oraz model article_state_machine.

Moim celem jest zdefiniowanie polityki publikowania (przy użyciu narzędzia pundit) w moich zasadach dotyczących artykułów, która pozwala użytkownikowi, który jest właścicielem artykułu, na opublikowanie tego artykułu, jeśli jest on w stanie "zatwierdzony".

Próbuję to w moim polityki artykułu ekspert:

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 

Przy próbie sprawdzenia, czy wyrób jest w stanie: zatwierdzenie (jak skomentował powyżej), pojawia się komunikat o błędzie metody niezdefiniowanej "in_state".

Jak korzystać z automatu stanów w polityce? Czy jest to zamierzone, że polityka pozwala użytkownikowi na publikowanie przez cały czas, ale pokazujesz tylko przycisk na stronie pokazu artykułu, gdy artykuł jest w stanie zatwierdzić (chociaż myślałem, że to był cel 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 

Artykuł maszyna stanów model:

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 

Artykuł modelu przejściowego: kontroler

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


    belongs_to :article, inverse_of: :article_transitions 



end 

artykułu:

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 

Czy ktoś może zobaczyć, co zrobiłem źle?

Cały sterownik artykułów posiada:

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

Gdzie nazywasz 'upoważnić' Pundit? –

+0

Dobra uwaga. Kiedy dodam Authorize @ artykuł do akcji publikowania, pojawia się komunikat o błędzie: Statesman :: TransitionFailedError in ArticleController # publish Nie można przejść z "publikowania" do "publikowania" – Mel

+0

Następnie wydaje się, że nie ma problemu ze stroną Pundit. Powód powinien znajdować się gdzieś w komunikacie wyjątku/ślad stosu. BTW metoda bang 'transition_to!' Podnosi wyjątki zamiast zwracać 'false'. Dobrym pomysłem może być użycie metody non-bang i wydrukowanie odpowiedniego komunikatu o błędzie, jeśli nie zamierzasz przechwytywać tych wyjątków (używanie wyjątków dla przepływu programu nie jest dobrym pomysłem). –

Odpowiedz

3

Wersja dyplomata gem używasz nie posiada in_state? zdefiniowane. Możesz zaktualizować klejnot.Lub można go samodzielnie określić stosując podobne kody, połączone smallbuttoncom

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

jednak w Twoim przypadku, proste sprawdzenie powinno wystarczyć. Wypróbuj poniższy kod w swojej polityce:

article.state_machine.current_state == "approve" 

Nadzieję, że pomaga.

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

Czy próbowałeś zmienić article.in_state? (: Zatwierdzenie) do article.state_machine.in_state? (: Zatwierdzenie) w swojej polityce ?.

+0

Dobry punkt Guilherme, próbowałem, ale to daje ten błąd: NoMethodError w ArticlesController # publikuj niezdefiniowana metoda 'in_state 'dla # Mel

+0

Według dokumentów nie powinieneś używać stanu in_state? ze znakiem zapytania. Machine # in_state? (: Stan_1,: stan_2, ...) – Guilherme

+0

Próbowałem tego też – Mel

2

brakuje obecnie na ? na końcu metody:

in_state metoda jest rzeczywiście metoda klasy i zachowuje się jak zakres.

trzeba użyć metody in_state?, który jest metoda instancji, podobnie jak to:

article.state_machine.in_state?(:approve)

Powiązane problemy