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
Wo nennst du Pundits "autorisieren"? –
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
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). –