1

Ist es möglich, eine Mongoid field zu deserialize als Struct statt Hash zu konfigurieren? (with defaults)Mongoid Feld Hash als Struct

Mein Anwendungsfall: ein Unternehmen mit einem Abonnement-Plan als Hash in meinem Modell gespeichert.

Früher als Hash

class Company 
    include Mongoid::Document 
    field :subscription, type: Hash, default: { 
     ends_at: 0, 
     quantity: 0, 
     started_at: 0, 
     cancelled: false, 
    } 

Ich wünschte, ich Company.first.subscription[:ends_at] schreiben nicht haben, würde ich eher Company.subscription.ends_at schreiben

ich so etwas wie die folgende dachte würde besser funktionieren

class Company 
    include Mongoid::Document 
    field :subscription_plan, type: Struct, default: Struct.new(
    :ends_at, :quantity, :started_at, :cancelled 
) do 
    def initialize(
     ends_at: nil, 
     quantity: 0, 
     starts_at: nil, 
     cancelled: false 
    ); super end 
    end 
end 

Es wäre noch besser, wenn der Plan in einer Klasse

definiert werden könnte
class SubscriptionPlan < Struct.new(
    ends_at, :quantity, :starts_at, :cancelled 
) do 
    def initialize(
    ends_at: nil, 
    quantity: 0, 
    starts_at: nil, 
    cancelled: false 
); super; end 
end 

class Company 
    field :subscription_plan, type: SubscriptionPlan, default: SubscriptionPlan.new 
end 

Wie kann ich es funktionieren lassen?

+0

Haben Sie meine Antwort versucht? –

Antwort

1

Nehmen Sie dies mit einem Körnchen Salz, wie ich MongoDB oder Mongoid nie verwendet habe. Noch googeln für "benutzerdefinierten Typ" brachte mich zu diesem documentation.

Hier ist eine angepasste Version des benutzerdefinierten Typ Beispiel:

class SubscriptionPlan 

    attr_reader :ends_at, :quantity, :started_at, :cancelled 

    def initialize(ends_at = 0, quantity = 0, started_at = 0, cancelled = false) 
    @ends_at = ends_at 
    @quantity = quantity 
    @started_at = started_at 
    @cancelled = cancelled 
    end 

    # Converts an object of this instance into a database friendly value. 
    def mongoize 
    [ends_at, quantity, started_at, cancelled] 
    end 

    class << self 

    # Get the object as it was stored in the database, and instantiate 
    # this custom class from it. 
    def demongoize(array) 
     SubscriptionPlan.new(*array) 
    end 

    # Takes any possible object and converts it to how it would be 
    # stored in the database. 
    def mongoize(object) 
     case object 
     when SubscriptionPlan then object.mongoize 
     when Hash then SubscriptionPlan.new(object.values_at(:ends_at, :quantity, :started_at, :cancelled)).mongoize 
     else object 
     end 
    end 

    # Converts the object that was supplied to a criteria and converts it 
    # into a database friendly form. 
    def evolve(object) 
     case object 
     when SubscriptionPlan then object.mongoize 
     else object 
     end 
    end 
    end 
end 

class Company 
    include Mongoid::Document 
    field :subscription, type: SubscriptionPlan, default: SubscriptionPlan.new 
end 

Dies sollte Ihnen näher bringen, was Sie tun wollte.

Beachten Sie, dass die Standardeinstellung von jedem Unternehmen mit einem Standard geteilt wird. Es kann zu einigen seltsamen Fehlern führen, wenn Sie den Standardplan in einer Firma ändern.

+0

Hallo, ich werde das versuchen, aber sei vorsichtig, du hast den Link zu einer sehr veralteten Mongoid-Dokumentation (ich denke, Version 2 oder so) gegeben. Ich arbeite mit Mongoide Edge (Mongoid 6/MongoDB 3.x). Es gibt sogar "alt" in der URL –

+0

Sie haben Recht. Ich habe nicht nachgesehen, ich habe nur den ersten Link verwendet, den ich bei Google gefunden habe. –

+0

Ich hatte Glück, die Dokumentation scheint sich seit dem alten Mongoid nicht geändert zu haben. –

0

Ich erkannte, dass ich nur ein verschachteltes Dokument ohne die ID reimplementiert wurde. Am Ende entschied ich mich, zu einem normalen eingebetteten Dokument für meine subscription zu wechseln, da ein zusätzliches ID-Feld kein Problem ist und ich Mongoid-Scopes als Bonus bekomme. Ich kann immer Mongoid::Attributes::Dynamic hinzufügen, falls ich irgendeinen Schlüssel unterstützen möchte.

Dennoch bleibt die Frage und andere Antwort relevant für jemanden, der seine eigenen Typen erstellen möchte.