S'il y a des données qui passent à un état, ce type de code se produira fréquemment.
erb:view.html.erb
<%#Il semble que l'approbation ne peut pas être faite si l'état du rapport est 1 ou 2, mais quels sont les états 1 et 2?%>
<%= button_tag('Approbation', disabled: (report.state == 1 || report.state == 2)) %>
reports_controller.rb
def accept
report = Report.find(params[:id])
#La même instruction conditionnelle que view est requise pour la gestion!
if report.state == 1 || report.state == 2
flash[:error] = 'Impossible d'approuver'
redirect_to root_url
end
report.state = 3 #Valeur d'approbation!
report.save!
end
Si vous utilisez une constante, cela s'améliorera un peu, mais ...
erb:view.html.erb
<%= button_tag('Approbation', disabled: (report.state == Report::STATE_DRAFT || report.state == Report::STATE_TRASH)) %>
reports_controller.rb
def accept
report = Report.find(params[:id])
#Après tout, la même instruction conditionnelle que view est requise!
if report.state == Report::STATE_DRAFT || report.state == Report::STATE_TRASH
flash[:error] = 'Impossible d'approuver'
redirect_to root_url
end
report.state = Report::STATE_APPROBAL
report.save!
end
report.rb
class Report < ApplicationRecord
#Si de nombreuses colonnes nécessitent des constantes, de nombreuses constantes seront nécessaires.
#De plus, la portée est trop large et il est difficile d'en voir le but.
STATE_DRAFT = 1
STATE_TRASH = 2
STATE_APPROBAL = 3
end
Il existe un moyen d'utiliser ActiveRecord :: Enum au lieu d'une constante, mais cela ne résout pas le besoin de la même instruction conditionnelle à divers endroits ... Il peut être résolu en ajoutant une méthode au modèle ActiveRecord.
report.rb
class Report < ApplicationRecord
STATE_DRAFT = 1
STATE_TRASH = 2
STATE_APPROBAL = 3
def can_accept?
state != STATE_DRAFT && state != STATE_TRASH
end
end
Mais c'est la route vers Fat Model ... Donc ...
Évitez la modélisation en masse du modèle ActiveRecord et créez une classe de transition d'état avec des responsabilités claires.
Ce serait bien si l'instruction conditionnelle avait une méthode de changement d'état appelée report_state.to_approval
, avec le sentiment de report_state.approval_in_next?
[^ 1](peut-il être dans l'état approuvé).
[^ 1]: Le nom de la méthode est censé être "Y a-t-il une approbation dans l'état suivant?", Mais comme c'est un putain de poisson anglais, il peut y avoir d'autres bons noms de méthode.
reports_controller.rb
def accept
report = Report.find(params[:id])
report_state = report.state_object
#Nettoyer
unless report_state.approval_in_next?
flash[:error] = 'Impossible d'approuver'
redirect_to root_url
end
#Ceci est un exemple simple avec une seule colonne, mais même si le traitement de la transition d'état est compliqué,_*Peut être caché dans la méthode!
new_report_state = report_state.to_approval
report.state = new_report_state.state
report.save!
end
report.rb
class Report < ApplicationRecord
# state_object=Il peut être pratique de créer une méthode
def state_object
ReportState.new(state)
end
end
La classe ReportState réelle ressemble à ceci.
report_state.rb
class ReportState
attr_accessor :state
#Déplacez les constantes de la classe Report. Ça va mieux tout le temps
DRAFT = 1
TRASH = 2
APPROBAL = 3
def initialize(state)
self.state = state
end
def approval_in_next?
state != DRAFT && state != TRASH
end
def to_approval
raise 'Transition d'état illégale!' unless approval_in_next?
self.class.new(APPROBAL)
end
end
Maintenant, même si les conditions qui peuvent être approuvées se compliquent ou que le processus de transition de l'état vers le statut d'approbation se complique, il ne vous reste plus qu'à changer ici!
Cette entrée est le State Transition Diagram, State Transition Table de Requirements Analysis Driven Design #% E7% 8A% B6% E6% 85% 8B% E9% 81% B7% E7% A7% BB% E5% 9B% B3% E7% 8A% B6% E6% 85% 8B% E9% 81% B7% E7% A7% BB% E8% A1% A8) a été réorganisé et réécrit en contenu à usage général. C'est une longue histoire, mais c'est une histoire de choses de type DDD dans Rails.
Recommended Posts