2016-07-18 9 views
2

Ich bin neu bei Rails und habe ein paar Fragen über die Validierung von Parametern und die Rückgabe von Fehlerreaktionen. Ich möchte eine JSON-API mit dem neuen Rails 5-API-Modus erstellen.Rails JSON API-Parameter Validierung und Fehler Antworten

Soweit ich das beurteilen kann, empfiehlt Rails "starke Parameter" als Basis für die Validierung von Parametern zu verwenden. Wenn ich zum Beispiel eine Benutzerklasse erstellen möchte, die entweder eine Telefonnummer oder eine E-Mail-Adresse benötigt, beginne ich in meinem UsersController mit so etwas.

def create 
    @user = User.new(create_user_params) 
end 

def create_user_params 
    params.require(:user).permit(:email, :phone) 
end 

Nun, wenn ich will etwas ein wenig komplexer, könnte ich die folgende

def create 
    arr_contains_at_least_one(params[:user], [:email, :phone]) 
    @user = User.new(create_user_params) 
end 

auf meine Frage Dies bringt uns hinzuzufügen.

Was ist der beste Weg, um eine "schöne" Fehlerantwort zurückzugeben, sowohl im Falle eines Standard-Rails-Fehler (ActionController :: ParameterMissing) oder eines benutzerdefinierten Fehlers? Ich meine, wenn ich den API-Endpunkt in einem Browser aufrufen würde, würde er lesbare JSON mit einer beschreibenden Nachricht zurückgeben. Wenn ich meinen Server im Produktionsmodus ausführen, und nicht einen Benutzerparameter im ersten Beispiel zu liefern, Schienen Rückgabe:

An unhandled lowlevel error occurred. The application logs may have details. 

Das ist natürlich nicht gut, vor allem, wenn ich den Fehler an einen Endbenutzer angezeigt werden wollte. Hier gehe ich davon aus, dass das starke Parametermuster für Sicherheit und Datenintegrität, nicht für Benutzererfahrung, ist. Dies scheint auch für die Modellfeldvalidierung zu gelten. Also mache ich folgende Anpassungen.

def create 
    return error_response("some error") unless arr_contains_at_least_one(params[:user], [:email, :phone]) 
    @user = User.new(create_user_params) 
end 

def error_response(msg, status = 400) 
    render json: {"code":status, "message": msg}, :status => status 
end 

Dies funktioniert, aber jetzt bin ich gezwungen, manuell Parameter Schecks (überprüfen auf das Vorhandensein von obligatorischen Parameter und Parameter bestätigen wie E-Mail-Adressen) und die entsprechenden Fehlerreaktionen. Wenn ich die in Rails integrierte Feldvalidierung auch für Modelle verwende, scheint dies das DRY-Prinzip zu verletzen. Des Weiteren erfordert das Entwerfen eines guten Fehlerbehandlungsmusters ziemlich viel an kundenspezifischer Implementierung.

Verpasse ich etwas Rails Magie oder bin ich hier auf dem richtigen Weg?

BEARBEITEN: Es sieht so aus, als könnten aktive Datensatzvalidierungen ziemlich einfach in eine JSON-Antwort (http://guides.rubyonrails.org/active_record_validations.html) eingewickelt werden, aber die Frage bleibt immer noch für die Validierung der Anwesenheit von Parametern.

Antwort

2

Ich glaube, Sie verwechseln die Verwendung von strong_parameters mit Validierungsmethoden.

Strong-Parameter bieten eine Schnittstelle zum Schützen von Attributen vor der Endbenutzerzuweisung. Dies macht es den Action Controller-Parametern verboten, in der aktiven Modell-Massenzuweisung verwendet zu werden, bis sie auf die weiße Liste gesetzt wurden.

http://edgeapi.rubyonrails.org/classes/ActionController/StrongParameters.html

Wenn Sie Weiße Liste Parameter in stark-Parameter, es bedeutet, sind Sie in der Lage sein, Massen ordnen sie Ihrem Active Modell. Oder besser, Attribute, die nicht auf der weißen Liste stehen, werden nicht an Ihr Modell weitergegeben.

Sie haben eigentlich nichts mit Validierungen selbst zu tun. Sie sollen Ihr Modell vor unerlaubter Parameterinjektion schützen.

def create 
    @user = User.new(create_user_params) 
end 

def create_user_params 
    params.require(:user).permit(:email, :phone) 
end 

so Ihr Beispiel:

POST /users body={user: {email: '[email protected]', phone: '1234', some_other: 'some other'}} 

das some_other Attribut nicht zu übergeben bekommen Ihre User.new

Was Sie suchen Activerecord Validierungen IS.

def create 
    @user = User.new(create_user_params) 
    if @user.save 
    render json: @user 
    else 
    render @user.errors.full_messages.as_json, status: 400 
    end 
end 

def create_user_params 
    params.require(:user).permit(:email, :phone) 
end 

und dann im Modell: In Ihrem speziellen Fall würde ich so etwas schreiben

class User < ActiveRecord::Base 
    validates_precense_of :some_other #this will cause the user not to save, end thus, report an errer message 
end 
+0

Vielen Dank !! –

1

Der "Rails Weg" sollte eine Form Roundtrip verwenden - alle Validierungen sollten in einem Modell leben. Controller haben möglicherweise nur eine einfache Validierung wie Sicherheit und Whitelist, die nicht mit der Geschäftslogik zu tun haben. "Model" ist möglicherweise nicht nur ActiveRecord selbst, sondern auch etwas wie FormObject https://robots.thoughtbot.com/activemodel-form-objects, insbesondere wenn einige Ihrer Ressourcen nicht eins zu eins in eine Datenbanktabelle reflektiert werden.

Wenn Sie nur API-Modus verwenden wollen, würde ich empfehlen, eine Chance für sehr ordentlich API DSL geben https://github.com/ruby-grape/grape#parameter-validation-and-coercion