如何为更新操作创建表单对象?

时间:2017-06-10 20:32:22

标签: ruby-on-rails ruby design-patterns

有一个表单对象允许创建具有关联的对象。 这个主要问题是关联更新。我真的不知道如何在没有大量each和条件的情况下扩展它。 扩展此类以更新对象的最方便方法是什么?

module Company
  class JobForm
    include ActiveModel::Model

    attr_accessor :title, :body, :city, :start_date, :attachments, 
                          :requirements, :company
    attr_reader :object

    validates :title, :body, :start_date, :city, presence: true

    def save
      persist! if valid?
    end

    private

    def persist!
      ActiveRecord::Base.transaction do
        save_job
        save_attachments
        save_requirements
      end
      object
    end

    def save_job
      @object = company.jobs.create( 
          # attributes.. ..)
    end

    def save_attachments
      return unless attachments&.present?
      attachments.each do |attacment_attributes|
        object.attachments.create(attacment_attributes)
      end
    end

    def save_requirements
      return unless requirements&.present?
      object.requirements.destroy_all
      requirements.each do |requirement_attributes|
        object.requirements.create(requirement_attributes)
      end
    end
  end
end

2 个答案:

答案 0 :(得分:1)

您询问了在自定义表单对象中实现更新的最便捷方式...但是自定义表单对象不是在Rails中使用表单的便捷方式。

有一些方便的宝石有助于构建复杂的形式。其中一个是reform。查看Populator部分http://trailblazer.to/gems/reform/populator.html

如果您使用收藏,通常您必须按正确的顺序手动匹配incomming params和相关对象,请查看以下示例

collection :songs,
  populator: ->(fragment:, **) {
    # find out if incoming song is already added.
    item = songs.find { |song| song.id == fragment["id"].to_i }

    item ? item : songs.append(Song.new)
  }

如果您已经有关联模型 - 您从populator返回它,它将使用incomming参数进行更新。如果你没有它 - 你建立一个新模型,它将使用incomming参数创建...

答案 1 :(得分:1)

您可以利用质量赋值的功能,如果具有一对多关联的对象使用params哈希实例化,并且该哈希具有关联键,则Rails将调用<association_name>_attributes=

因此,您可以在表单对象类上定义该方法:

def attachments_attributes=(attributes)
  @attachments ||= []
  attributes.each do |_, attachment_params|
    attachment = @attachments.find {|a| a.id.to_s == attachment_params[:id]}
    attachment ? attachment.assign_attributes(document_params) : @attachments.push(Attachment.new(attachment_params))
  end
end