2017-07-14 1 views
0

J'ai un modèle qui a beaucoup de relation avec un modèle de version. Toute action sur le modèle parent doit être suivie. Au formulaire de suppression, j'ai ajouté un formulaire imbriqué pour entrer un numéro de billet qui sera ajouté aux versions. Comment puis-je vérifier les validations du modèle si le ticket est donné? Je vais écrire la version avant que la destruction sur le modèle ne soit appelée.before_destroy vérifier si l'attribut pour le modèle associé est donné (contrôle de version)

# model.rb 
class Model < ActiveRecord::Base 
     has_many :versions, 
        :as => :version_object 
end 

# models_controller.rb 
def destroy            
    @model = Model.find(params[:id])     
    self.write_versions('Destroy')       
    @Model.destroy          

    respond_to do |format|         
     ... 
    end             
    end 

# delete.html.erb 
<%= form_for [@model.parent_object, @model], :html => { :class => 'form-horizontal' }, :method => :delete 
    do |f| %> 
     <div class="form-actions"> 
     <%= f.fields_for :versions, @model.versions.build do |v| %> 
      <%= v.text_field :ticket, {:class => 'text_field', :placeholder => 'Ticket Nummer'}%> 
     <% end %> 
     <%= f.submit 'Delete Model', :class => 'btn btn-danger' %> 
     <%= link_to t('.cancel', :default => t("helpers.links.cancel")), 
        :back, :class => 'btn' %> 
     </div> 
    <% end %> 

Je l'ai déjà essayé de mettre en œuvre une méthode before_destroy pour vérifier si une version avec l'action « Destroy » est écrit, mais cela ne fonctionnera pas parce que les champs clés pour identifier l'action donnée pourrait être existe plus d'une fois . Les versions sont incrémentales et peuvent être annulées étape par étape pour obtenir une version plus ancienne et mon modèle pourrait avoir plus d'un identifiant de relation au cours de la vie de son parent.

Une solution consisterait à vérifier l'existence du ticket au niveau du contrôleur via les paramètres, mais les validations devraient être effectuées sur le modèle. Je ne veux pas utiliser une gem versioning.

Quelqu'un peut-il suggérer comment implémenter une telle validation?

Répondre

1

Vous pouvez essayer encapsuler la logique de versionnage entièrement dans votre classe Model et non accéder à la relation .versions dans les contrôleurs et les modèles du tout. Pensez à quelque chose comme ceci:

# model.rb 
class Model 
    has_many :versions 

    attr_accessor :_current_action, :_ticket_number 

    validates :_current_action, presence: true 
    validates :_ticket_number, presence: true 

    after_create :create_new_version 
    before_destroy :create_new_version 

    def set_next_action(action, ticket_number) 
    self._current_action = action 
    self._ticket_number = ticket_number 
    end 

    private 

    def create_new_version 
    unless _current_action.present? && _ticket_number.present? 
     raise RuntimeError, "Missing versioning action or ticket number" 
    end 

    # adjust this to store the actual model data as well 
    versions.create!(action: _current_action, ticket_number: _ticket_number) 

    self._current_action = nil 
    self._ticket_number = nil 
    end 
end 

Alors, voici comment vous faites une mise à jour:

<!-- edit.html.erb --> 
<%= form_for @model, method: :patch do |f| %> 
    <!-- other fields --> 
    <%= text_field_tag :_ticket_number, class: "text_field" %> 
    <%= f.submit "Update model" %> 
<% end %> 

Dans le contrôleur:

# models_controller.rb 
def update 
    @model = Model.find(params[:id]) 
    @model.set_next_action "Update", params[:_ticket_number] 

    if @model.update(params[:model]) 
    # ... 
    else 
    render :edit 
    end 
end 

Voici comment vous faites une suppression:

<!-- edit.html.erb --> 
<%= form_for @model, method: :delete do |f| %> 
    <!-- other fields --> 
    <%= text_field_tag :_ticket_number, class: "text_field" %> 
    <%= f.submit "Delete model" %> 
<% end %> 

Dans le contrôleur:

# models_controller.rb 
def destroy 
    @model = Model.find(params[:id]) 
    @model.set_next_action "Destroy", params[:_ticket_number] 

    if @model.valid? # validates presence of ticket number 
    @model.destroy 
    # ... 
    else 
    render :edit 
    end 
end 

Note: Je n'ai pas testé ce code, donc peut-être besoin de quelques changements avant qu'il ne fonctionnera.

+0

Bon indice et concept. Le callback doit être before_destroy car rails3 ne me laisse pas créer! un enfant sauf si le parent est enregistré. Et after_destroy le parent n'existera plus. – SonIcco