2012-03-31 13 views
48

Chcę PUT na szynach i unikam pobierania 204. Używam tego wzoru:Prosta odpowiedź z szynami, które unikają 204 z PUT

class SomeController < ApplicationController 
    respond_to :json 

    def update 
    # ... 
    respond_with(some_object) 
    end 
end 

Jednak, kiedy zrobić put zaktualizować, dostaję 204 plecy. Zdaję sobie sprawę, że jest to całkowicie poprawne itp., Ale wyraźnie chcę, aby zawartość została zwrócona. Mogę to zmienić w pewnym stopniu:

def update 
    respond_with(some_object) do |format| 
    format.json{render json: some_object} 
    end 
end 

, ale wydaje się to zbyt praktyczne dla szyn. Czy istnieje bardziej idiomatyczny sposób uniknięcia numeru 204 i żądanie przesłania całej zawartości? To jest Rails 3.2.

Podsumowując: Chcę maksymalnie idiomatycznych szyn, które unikają 204.

Odpowiedz

29

Zrobiłem niestandardowy responder, który zawsze zwraca mój zasób zakodowany JSON nawet na PUT/POST.

Położyłem ten plik w lib/responders/json_responder.rb. Twój katalog /lib powinien być ładowany automatycznie.

module Responders::JsonResponder 
    protected 

    # simply render the resource even on POST instead of redirecting for ajax 
    def api_behavior(error) 
    if post? 
     display resource, :status => :created 
    # render resource instead of 204 no content 
    elsif put? 
     display resource, :status => :ok 
    else 
     super 
    end 
    end 
end 

Teraz należy jawnie zmodyfikować kontroler, który wymaga tego zachowania, lub umieścić go w kontrolerze aplikacji.

class ApplicationController < ActionController::Base 

    protect_from_forgery 

    responders :json 

end 

Powinieneś teraz odzyskać zakodowane zasoby JSON na PUT.

+8

Dodam, że trzeba do „gem reagujących”, aby móc korzystać z metody odpowiadające, kontrolera. – iterion

3

Co w tym złego po prostu robi:

def update 
    some_object = SomeObject.update() 
    render json: some_object 
end 
+2

Nie otrzymasz prawidłowych kodów odpowiedzi lub błędów http –

+0

Tak jak w powyższym komentarzu, nie otrzymujesz żadnych informacji zwrotnych na temat tego, czy aktualizacja jest udana, czy nie. – Leito

11

Takie zachowanie wydaje się celowe, aby spaść zgodnie z specyfikacją HTTP i „idealnie” należy być wystrzelenie dodatkowego żądania GET, aby zobaczyć wyniki. Zgadzam się jednak w świecie rzeczywistym, że wolałbym, aby zwrócił JSON.

@ Powyższe rozwiązanie jpfuentes2 powinno wystarczyć (jest bardzo podobne do żądania ściągnięcia poniżej), ale jestem niezdecydowany, aby zastosować wszystko, co łata wewnętrzne szyny, ponieważ może to być prawdziwy ból, aby uaktualnić główne wersje, szczególnie jeśli nie masz na to testów (i spójrzmy prawdzie w oczy, programiści często skąpią na testach kontrolerów).

Referencje

+0

Dzięki za odpowiedź. Masz rację, wolałbym zrobić kolejny '$ .get' z' JS' niż zacząć walczyć z frameworkiem. – jibiel

6

Właśnie w celu wyjaśnienia, nie trzeba gem ankietowanym to zrobić ... Można po prostu zrobić:

config/initializers/responder_with_put_content.rb

class ResponderWithPutContent < ActionController::Responder 
    def api_behavior(*args, &block) 
    if put? 
     display resource, :status => :ok 
    else 
     super 
    end 
    end 
end 

a następnie albo (dla wszystkich aktualizacji akcje, które zostaną dotknięte):

class ApplicationController < ActionController::Base 
    def self.responder 
    ResponderWithPutContent 
    end 
end 

lub w swoim działaniu:

def update 
    foo = Foo.find(params[:id]) 
    foo.update_attributes(params[:foo]) 
    respond_with foo, responder: ResponderWithPutContent 
end 
+0

Uratowałeś mój dzień. (y) –

9

Jako mniej inwazyjną alternatywę można przekazać json: Opcja wywołania metody respond_with wewnątrz kontrolera update, akcja taka:

def update 
    # ... 
    respond_with some_object, json: some_object 
end 

Przyznaję, że wydaje mi się trochę niepotrzebne powtórzenie obiektu dwukrotnie w argumentach, ale da ci to, czego chcesz, jsonową reprezentację obiektu w odpowiedzi na żądanie PUT, a ty nie trzeba użyć metody render json:, która nie zapewni korzyści respondentom.

Jeśli jednak masz dużo kontrolerów w tej sytuacji, to dostosowywanie respondentów, tak jak jpfuentes2 pokazane w zaakceptowanym anwseście, jest drogą do zrobienia. Ale dla szybkiego pojedynczego przypadku ta alternatywa może być łatwiejsza.

Źródło: https://github.com/plataformatec/responders/pull/115#issuecomment-72517532

1

Nie wielkim fanem tego zachowania. Aby uzyskać wokół niego, musiałem uniknąć stosując metodę respond_with:

class SomeController < ApplicationController 
    respond_to :json 

    def update 
    # ... 
    respond_to do |format| 
     format.json { render(json: some_object, status: 200) } 
    end 
    end 
end