感觉代码味道。处理父母和父母的更好方法通过控制器创建孩子?

时间:2011-11-25 20:40:26

标签: ruby-on-rails refactoring

我正在研究内部工具。以下是我使用的三个主要模型:

Site
  has_many Document
    has_many Version

文档模型实质上存储了一组内容。我想要做的是使用Version模型设置文档版本。所以版本会存储内容。

现在,我通过嵌套URL创建一个新文档:POST / sites /:id / documents。由于表单存在,并且我没有计划在此更改用户体验,因此我开始构建它以使用Document和Version模型。但是,我开始觉得这是错的。管理子对象的验证并将其推送到父对象变得很痛苦。

另一个注意事项:

Document包含一个名为active_version_id的整数字段。它存储当前是该文档的活动版本的版本。然后我使用该ID获取版本模型,以显示连接到该文档的主要内容。我将其设置为创建文档时创建的版本。

我想做什么

简而言之,这是我期望的工作流程:

  1. 去创建新文档
  2. 放入内容
  3. 提交表格
  4. 创建了父文档。
  5. 使用父文档,它会创建一个新版本。版本级别的内容上的任何验证错误都应该阻止两种模型的保存。
  6. 版本对象的错误应该显示在页面上,因此用户知道。
  7. 这是我的版本模型,因此您可以看到验证逻辑。它基本上检查文档中的标题是否有效(这只是一些标识文本)。并且标题不会在该站点中的任何其他文档的版本中使用:

    def document_is_in_valid_format
      p = CopyProcess::Processor.new
      if !p.contains_valid_headers(self.content)
        Rails.logger.debug "Headers invalid."
        msg = "Content headers must be in valid format."
        self.document.errors[:base] << msg
        self.errors[:base] << msg
      else
        # Check that headers are unique to the parent document
        headers = content.split(/\n/)[1..3].join(' - ').gsub(/\/\*|\\\*/,'')
        site_documents = []
        # get all documents where it's not this one's parent
        if self.id
          site_documents = Document.where(["site_id = ? AND id <> ?", self.site_id, self.document_id])
        else
          site_documents = Document.where(["site_id = ?", self.site_id])
        end
        site_documents.includes(:versions)
        site_documents.each do |doc|
          if doc.version_names.include?(headers)
            msg = "Content headers are not unique."
            self.document.errors[:base] << msg
            self.errors[:base] << msg
            break
          end
        end
      end
    end
    

    我想知道这里的解决方案是否可以使用嵌套表单。对于第5步,我认为交易有助于防止两次保存。

2 个答案:

答案 0 :(得分:2)

我建议您改用the PaperTrail gem,而不是滚动自己的版本控制系统。然后,您可以放弃Version模型,并为您只需要的Document模型添加版本控制:

class Document < ActiveRecord::Base
  has_paper_trail

  # ...
end

你完成了!宝石有很好的记录,所以一定要先检查一下。

答案 1 :(得分:1)

登入http://api.rubyonrails.org查询:

  • validates_associated
  • accepts_nested_attributes_for

另请注意,您可以在_id / _ids字段上使用验证,例如validates :document_ids, presence: true,以确保至少有一个文档。

为了使代码更具可读性,我会尝试使用以下方法在自定义验证器中拆分长验证序列:

  • ::加载ActiveModel验证
  • ::加载ActiveModel EachValidator