【问题标题】:before_destroy check if attribute for related model is given (version control)before_destroy 检查是否给出了相关模型的属性(版本控制)
【发布时间】:2017-12-19 11:59:21
【问题描述】:

我有一个与版本模型有很多关系的模型。需要跟踪对父模型的任何操作。在删除表格中,我添加了一个嵌套表格以输入将添加到版本中的票号。如果给出票,我如何检查模型验证?我会在模型上的destroy被调用之前编写版本。

# 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 %>

我已经尝试实现 before_destroy 方法来检查是否编写了具有“Destroy”操作的版本,但这不起作用,因为识别特定操作的关键字段可能存在不止一次。版本是增量的,可以逐步回滚以获得旧版本,并且我的模型在其父级的生命周期中可能具有多个关系标识符。

一种解决方案是通过参数检查控制器是否存在票证,但验证应该在模型中。

我不想使用版本控制 gem。

有人提示如何实现这样的验证吗?

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3 relation before-filter


    【解决方案1】:

    您可以尝试将版本控制逻辑完全封装在您的 Model 类中,而不是访问控制器和模板中的 .versions 关系。考虑这样的事情:

    # 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
    

    那么,这就是你进行更新的方式:

    <!-- 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 %>
    

    在控制器中:

    # 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
    

    这是删除的方式:

    <!-- 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 %>
    

    在控制器中:

    # 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
    

    注意:我没有测试此代码,因此可能需要进行一些更改才能工作。

    【讨论】:

    • 很好的提示和概念。回调必须是 before_destroy 因为 rails3 不允许我创建!一个孩子,除非父母得救。而 after_destroy 父级将不再存在。
    猜你喜欢
    • 1970-01-01
    • 2021-06-03
    • 1970-01-01
    • 1970-01-01
    • 2015-02-19
    • 2022-01-25
    • 1970-01-01
    • 2014-07-17
    • 2013-08-25
    相关资源
    最近更新 更多