Mongoid删除未保存的嵌入文档

问题描述 投票:0回答:1

我正在使用mongoid作为用户是父文档的应用程序,并且几乎所有其他信息都嵌入在用户中。因此,例如,我的控制器#new对属于该用户的Relationship的操作看起来像:

def new
  @relationship = current_user.relationships.new(friend_id: params[:fid])
  @relationship.validate
end

因为我对将在视图中显示的关系运行验证,并且其中一些验证需要能够引用父级,我不能只调用@relationship = Relationship.new(friend_id: params[:fid]),但是在用户的关系数组中实例化了这种关系,它现在挂起了在那里,即使用户决定他们不想建立新的关系,他们也会去网站的另一部分。如果他们进入关系索引页面,除非我将其过滤掉,否则他们会在列表中看到它。

如果关系有效并且他们在其他地方执行导致用户保存的事情,则该虚拟关系现在是真实关系。如果它无效,则保存将因未知原因而失败。

我有许多我打算嵌入用户的模型,所以每个人都会遇到这个问题。

我知道我可以打电话给current_user.reload来清除垃圾,但是每次我想要这样做时我都必须打到数据库。验证后我也可以孤立关系,但这感觉很糟糕。

在我看来,这是一个人们应该一直遇到嵌入式文档的问题,所以我认为会有某种内置的解决方案,但我似乎无法在任何地方找到它。我看到this question,它与我的相似,但我想要一些更具伸缩性的东西,这样我就不必把它放在任何地方。

我即将制作一个模块,将为每个嵌入式关系添加一个clear_unsaved_#{relation}方法,但这个想法让我感到沮丧,所以我想看看是否有人更好地了解如何做到这一点,以及哪里最好打电话给它。

ruby-on-rails mongoid
1个回答
1
投票

我最终创建了一个猴子补丁,它覆盖了Mongoid的embeds_manyembeds_one类方法,还定义了一个实例方法,用于清除该关系的未保存文档。这对我来说是最直接的方式,因为它的代码很少,这意味着我不必记住包含它的位置。

# config/initializers/patches/dirty_tracking_embedded.rb
module DirtyTrackingEmbedded
    # override the embedding methods to also make dirty-tracking
    def embeds_many(name, options= {}, &block)
        define_method "clear_unsaved_#{name}" do
            # remove_child removes it from the array without hitting the database
            send(name).each {|o| remove_child(o) unless o.persisted?}
        end
        super
    end

    def embeds_one(name, options={}, &block)
        define_method "clear_unsaved_#{name}" do
            dirty = send(name)
            remove_child(dirty) unless dirty.persisted?
        end
        super
    end
end

module Mongoid
    module Association
        module Macros
            module ClassMethods
                prepend DirtyTrackingEmbedded
            end
        end
    end
end

然后在我的控制器中我使用了after_action

# app/controllers/relationships_controller.rb
class RelationshipsController < ApplicationController
    after_action :clear_unsaved, only: [:new]

    def new
        @relationship = current_user.relationships.new(friend_id: params[:fid])
        @relationship.validate
    end

    private
    def clear_unsaved
        current_user.clear_unsaved_relationships
    end
end

Other Possibilities

不同的猴子补丁

您可以在setup_instance_methods!Mongoid::Association::Embedded::EmbedsMany中修补Mongoid::Association::Embedded::EmbedsOne方法,以包括设置实例方法以清除未保存的。你可以通过查看Mongoid::Association::Accessors#self.define_ids_setter!找到一个Mongoid人如何做这种事情的例子。我建议你在我使用的解决方案中使用prepend进行修补,这样你就可以继承方法的其余部分了。

组合猴子补丁和继承

Mongoid选择使用哪个类来实例化来自a constant called MACRO_MAPPING in Mongoid::Association的关联,所以你可以创建继承EmbedsManyEmbedsOne的类,仅重写setup_instance_methods!以添加所需的实例方法,然后你只需要修补MACRO_MAPPING来映射到你的新类。

关心

如果你是反猴子补丁,你可以使用我的DirtyTrackingEmbedded模块中的代码来制作一个同样的东西的ActiveSupport::Concern。您需要将重写的方法放在class_methods块中,然后确保在将Mongoid::Document包含在您想要的任何模型类中之后包含此模块。

© www.soinside.com 2019 - 2024. All rights reserved.