2016-04-13 6 views
4

Ich komme aus der .NET-Welt und ich versuche herauszufinden, was die "Rails Way", um ein Objekt über mehrere Ebenen in einer Multi-Tier-Anwendung zu übergeben.Was ist der 'Rails Way', um Objekte über mehrere (logische) Ebenen hinweg zu übergeben?

Ich schreibe eine Multi-Carrier-Preisgestaltung API. Im Grunde genommen in meiner Preis Controller ich Zugriff auf die folgenden Parameter haben params [: carrier], params [: address_from], params [: address_to], params [: CONTAINER_TYPE] usw. Ich habe eine Validierung Bibliothek, eine Compliance-Bibliothek und eine Preisfinder-Bibliothek, die sich jeweils mit einer Teilmenge der Parameter befassen.

In .NET würden die Parameter in Datenübertragungsobjekten (DTOs) oder Verträgen verkapselt werden. Vor dem Aufruf einer der Bibliotheken würden sie in Domänenobjekte (DOs) umgewandelt werden und jede Bibliothek würde auf den DOs arbeiten, wodurch eine enge Kopplung der DTOs vermieden würde. Die Ruby-Programmierung empfiehlt die Verwendung von "Duck Typing", so dass meine Bibliotheken direkt auf Params arbeiten können (obwohl Sie auf Symbole und nicht auf Objekte/Eigenschaften zugreifen würden). Oder sollte ich meine Params in ein PriceRequest-Objekt einordnen und meine Bibliotheken mit PriceRequest arbeiten lassen?

Option 1:

class PricesController < ApplicationController 
    def get 
    CarrierValidator.validate(params) 
    ... 
    end 
end 

class CarrierValidator 
    def self.validate(params) 
    raise CarrierError if !Carrier.find_by_name(params[:carrier_name]).exists? 
    end 
end 

Option 2:

class PricesController < ApplicationController 
    def get 
    pricesRequest = PricesRequest.new(carrier_name: params[:carrier_name], ...) 
    pricesRequest.validate 
    ... 
    end 
end 

class PriceRequest 
    attr_accessor : ... 

    def initalize 
    ... 
    end 

    def validate 
    CarrierValidator.validate(self.carrier_name) 
    end 
end 

class CarrierValidator 
    def self.validate(carrier_name) 
    raise CarrierError if !Carrier.find_by_name(carrier_name).exists? 
    end 
end 

TIA,
J

+0

können Sie hier einen Beispielcode posten? –

Antwort

1

Sie sollten eine Art erstellen. Ich würde ActiveModel verwenden, um die Daten (Attribute) & Geschäftslogik zu verkapseln (Validierungen & vielleicht einige Schicht-spezifische Methoden für die Verarbeitung der Daten).

Im Grunde wollen Sie in der Lage sein, Rails-y Dinge in der Steuerung zu tun:

def get 
    price_request = PriceRequest.new(params[:price_request]) 

    if price_request.valid? 
    # do something like redirect or render 
    else 
    # do something else 
    end 
end 

so möchten Sie erklären:

class PriceRequest 
    include ActiveModel::Model 

    attr_accessor :carrier, :address_from, :address_to, :container_type 

    validates :carrier, presence: true 
    validate :validate_address_from 

    def validate_address_from 
    # do something with errors.add 
    end 

    # and so on 

Dies ist ein guter Anfang: http://edgeguides.rubyonrails.org/active_model_basics.html

Weitere Details in der API: http://api.rubyonrails.org/classes/ActiveModel/Model.html

Hoffe, dass Sie in die richtige Richtung weist ...

+0

Ich habe bereits gewählt, das json_schema gem für die Anfrage json Validierung zu verwenden, die einige der Validierungsregeln in PriceRequest kümmern würde. Aber ich nehme an, dass das, was Sie vorgeschlagen haben, immer noch nicht ungültig wäre, da immer komplexere Geschäftsregeln für die Validierung in PriceRequest eingehen würden, oder? Wo würdest du diese Datei auch ablegen?/app/models,/app/business_models,/lib oder/lib/domain_objects? –

+0

yeah, du könntest einfach das Modell verwenden, um deinen json_schema call/config zu verpacken ... app/models funktionieren ... es liegt ganz bei dir - du kannst jedes Verzeichnis unter App setzen und es wird geladen –

Verwandte Themen