Mongoid удалить несохраненные вложенные документы - PullRequest
0 голосов
/ 16 января 2019

Я использую 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, чтобы избавиться от мусора, но мне кажется смешным, что мне придется обращаться к базе данных каждый раз, когда я хочу это сделать.Я мог бы также осиротить отношения после проверки, но это кажется хакерским.

Мне кажется, что это проблема, с которой люди должны постоянно сталкиваться со встроенными документами, так что я думаю, что будет какая-товстроенного решения, но я не могу найти его нигде.Я видел этот вопрос , который похож на мой, но я хочу что-то более расширяемое, чтобы мне не приходилось ставить его везде.

Я собираюсь создать модуль, который будет добавлять метод clear_unsaved_#{relation} в класс для каждого встроенного отношения, но эта идея меня расстраивает, поэтому я хотел посмотреть, есть ли у кого-нибудь лучшее представление о том, каксделайте это, а также, где это лучше всего назвать.

1 Ответ

0 голосов
/ 18 января 2019

В итоге я сделал патч обезьяны, который переопределяет классовые методы Mongoid embeds_many и embeds_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

Другие возможности

Другой патч обезьяны

Вы могли бы обезьянить патч setup_instance_methods! методов в Mongoid::Association::Embedded::EmbedsMany и Mongoid::Association::Embedded::EmbedsOne, чтобы включить настройку метода экземпляра для очистки несохраненных. Вы можете найти пример того, как монгоиды делают подобные вещи, посмотрев на Mongoid::Association::Accessors#self.define_ids_setter!. Я бы порекомендовал сделать ваше исправление с prepend, как в решении, с которым я пошел, чтобы вы могли наследовать остальную часть метода.

патч и наследование комбо-обезьяны

Mongoid выбирает, какой класс использовать для создания ассоциации из константы с именем MACRO_MAPPING в Mongoid::Association, чтобы вы могли создавать классы, которые наследуются от EmbedsMany и EmbedsOne всего с setup_instance_methods! переопределить, чтобы добавить необходимый метод экземпляра, тогда вам нужно будет только обезьяна заплатить MACRO_MAPPING для сопоставления с вашими новыми классами.

Концерн

Если вы исправляете ошибки, вы можете использовать код из моего DirtyTrackingEmbedded модуля, чтобы сделать ActiveSupport::Concern, который делает то же самое. Вы захотите поместить переопределенные методы в блок class_methods, а затем просто убедитесь, что вы включаете этот модуль после включения Mongoid::Document в любой класс модели, в котором вы хотите его использовать.

...