2012-04-18 10 views
17

Mam metody kontrolera w Ruby na Rails 3, który akceptuje aplikacji/JSON jako typ zawartości. Wszystko działa zgodnie z oczekiwaniami, ale w rzeczywistości nie chcę, aby railsy automatycznie analizowały JSON w treści żądania POST. Ta metoda działa jak brama i po prostu przenosi informacje do kolejki i może być dość duża. Nie chcę tracić czasu na przetwarzanie danych w @paramach, ponieważ jest to niepotrzebne.Zapobieganie Ruby na szynach 3 z parsowania JSON post

Wierzę, że mógłbym obejść ten problem, ustawiając typ zawartości w nagłówku żądania na coś innego, ale chciałbym być semantycznie poprawny dla żądań HTTP.

Jak wyłączyć tę funkcję?

EDYCJA: dokładniej, jak mogę edytować tę funkcję tylko dla tej jednej trasy?

+0

Wiesz, jeśli piszesz go jako JSON i powiedz szyn spodziewać się go do być ogłoszone jako JSON, myślę, że Railsy zawsze będą parsować. Aby zrobić to, co opisujesz, myślę, że prawie chcesz zamontować punkt końcowy stojaka na tej trasie i obsłużyć POST za pomocą narzędzia takiego jak 'rack_raw_upload' ... Dobre pytanie, przepraszam, tak naprawdę nie znam odpowiedzi. – Andrew

+0

Interesująca myśl ... Mogę dać temu ujęcie i zobaczyć, jak idzie. – Macdiesel

Odpowiedz

13

Parsowanie parametrów jest bardzo głęboko upieczone wewnątrz pakietu akcji lib/action_dispatch/middleware/params_parser.rb.

Powiedziałbym, że najlepiej sobie poradzisz, przechwytując prośbę za pomocą Rack, coś w tym stylu.

W lib/raw_json.rb

module Rack 
    class RawJSON 
    def initialize(app) 
     @app = app 
    end 

    def call(env) 
     request = Request.new(env) 
     if request.content_type =~ /application\/json/i 
     # test request.path here to limit your processing to particular actions 
     raw_json = env['rack.input'].read 
     env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded' 
     env['rack.input'] = StringIO.new("raw_json=#{raw_json}") 
     end 
     return @app.call(env) 
    end 
    end 
end 

W config.ru, włóż to przed wywołaniem run <your app name>::Application

require 'raw_json' 
use Rack::RawJSON 
+0

wydaje się, że wszystko, co musisz dodać do tego rozwiązania, to wykrycie określonej trasy - np. 'if request.path == '/ foo' i request.content_type = ~/application \/json/i' –

+0

Tak, dlatego wstawiłem komentarz do kodu, aby przetestować request.path. –

+0

Nie próbowałem tego jeszcze, ale wydaje się rozsądnym rozwiązaniem, dam mu szansę. – Macdiesel

1

napowietrznej do parsowania JSON z pojedynczego żądania jest stosunkowo niska. Czy masz konkretny powód, aby sądzić, że przetwarzanie JSON przyczynia się do wszelkiego rodzaju powolności w ogólnym przetwarzaniu?

Jeśli nie, to zaleca się pozostawienie go tak, jak jest, do czasu, gdy można go zidentyfikować jako problem.

Konfiguracja szyny nie analizować tego JSON (albo za pośrednictwem jakiejś konfiguracji regału lub w inny sposób) stworzy co zeby jednej trasy w aplikacji, które nie są obsługiwane w standardowym Rails Way.

W końcu może zajść potrzeba przetworzenia tych danych. A może będziesz musiał umieścić przed nim jakieś zabezpieczenia. A może chcesz go zalogować i powiązać z użytkownikiem, który go wysłał. A kiedy nadejdzie ten dzień, ty (lub ktoś inny w zespole) będzie musiał wejść i wprowadzić zmiany do tej niestandardowej implementacji.

Robienie rzeczy w nietypowy sposób w implementacji Railsów może zwiększyć złożoność i czas potrzebny na konserwację oprogramowania. Jest również powszechnym źródłem defektów, ponieważ ludzie są mniej zaznajomieni z niestandardowym przetwarzaniem.

Więc jeśli nie jest to prawdziwy problem, polecam po prostu pozwalając szyn przetworzyć JSON, a następnie po prostu przekazać je poprzez normalną Rails Way.

+1

To nie odpowiada na pytanie. Nie chcę analizować nadchodzącej odpowiedzi jsona, głównie ze względu na optymalizację. Ciało JSON może potencjalnie być tablicą zawierającą dziesiątki tysięcy elementów, a przetwarzanie i iteracja wymaga od aplikacji czasu i pamięci, kiedy może/powinna robić inne rzeczy. Ta czynność jest jedynie przejściem dla danych. – Macdiesel

+0

To wcale NIE jest względnie niskie, Railsy analizują całe wejście, filtry i logi WSZYSTKIE parametry i koszt są OGROMNE, gdy mamy do czynienia z wieloma żądaniami o wielkości 100k. – lzap

1

To może być pieczony w, ale patrząc na kod:

module ActionDispatch 
    class ParamsParser 
    DEFAULT_PARSERS = { 
     Mime::XML => :xml_simple, 
     Mime::JSON => :json 
    } 

    def initialize(app, parsers = {}) 
     @app, @parsers = app, DEFAULT_PARSERS.merge(parsers) 
    end 

    [ ... ] 

     strategy = @parsers[mime_type] 

Więc, czy można zorganizować wysłać mieszania do tego inicjatora można dodać lub zmienić domyślne. Nie wiesz, czy zezwolić na usunięcie, ale może działać pusta metoda analizatora składni.

Parsery odpowiedzieć tutaj: How do I initialize ActionDispatch::ParamsParser in Rails 3.1?

Code jest od actionpack-3.2.8/lib/action_dispatch/middleware/params_parser.rb

Powiązane problemy