2013-05-17 11 views
6

Ich habe versucht, den ganzen Tag herauszufinden, und es macht mich verrückt.Rails Paginierung in API mit Her, Faraday

Ich habe zwei Rails Apps, ServerApp und ClientApp. ClientApp ruft Daten von ServerApp über eine API mit dem Her-Juwel ab. Alles war großartig, bis ich Seitenumbruch Informationen brauchte.

Dies ist die Methode, die ich um die Aufträge zu bekommen bin mit (dies verwendet kamainari für Paginierung und plündern für Suche):

# ServerApp 
def search 
    @search = Order.includes(:documents, :client).order('id desc').search(params[:q]) 
    @orders = @search.result(distinct: true).page(params[:page]).per(params[:per]) 

    respond_with @orders.as_json(include: :documents) 
end 

Es gibt ein Array von Hashes in json, die sie als eine Sammlung verwendet von Aufträge. Das funktioniert gut.

# Response 
[ 
    { 
    "client_id": 239, 
    "created_at": "2013-05-15T15:37:03-07:00", 
    "id": 2422, 
    "ordered_at": "2013-05-15T15:37:03-07:00", 
    "origin": "online", 
    "updated_at": "2013-05-15T15:37:03-07:00", 
    "documents": [ 
     { ... } 
    ] 
    }, 
    ... 
] 

Aber ich brauchte Seitenumbruch Informationen. Es sah aus, als ob ich send it as metadata with my json brauchte. Also habe ich meine Antwort auf diese ändern:

respond_to do |format| 
    format.json do 
    render json: { orders: @orders.as_json(include: :documents), metadata: 'sent' } 
    end 
end 

Diese in der Tat Metadaten sendet über, so in meinem ClientApp I @ orders.metadata schreiben und 'geschickt' bekommen. Aber jetzt sind meine Bestellungen in einem Array innerhalb von 'Bestellungen' verschachtelt, also muss ich @ orders.orders verwenden, und dann behandelt es es wie ein Array anstelle einer Her-Sammlung.

Nach dem Lesen, schien es Senden von Paginierung Informationen über Header war die Art und Weise, wie viele andere Leute dies (ich war in der Lage, die Header in einem After_filter mit this guide eingerichtet). Aber ich bin noch mehr darüber verloren, wie ich diese Antwort-Header in meiner ClientApp bekomme - ich glaube, ich brauche eine Faraday-Middleware, aber ich habe einfach kein Glück, dass das funktioniert.

Wenn jemand weiß, wie ich das schaffen kann, wäre ich sehr dankbar. Ich kann keinen weiteren Tag damit verbringen, meinen Kopf gegen die Wand zu schlagen, aber ich fühle mich, als wäre ich nur ein wichtiges Stück von Informationen weg von diesem zu lösen!

+0

evt. Dies könnte auch ein Problem für das Her-Projekt sein. Sie können ein Problem dort öffnen und sehen, ob Sie ein Feedback von den Projektbetreuern – poseid

+0

erhalten haben. Ich hatte darüber nachgedacht, es auf die Her github-Seite zu posten, aber ich dachte, dies wäre eher ein Missverständnis von meiner Seite und kein Problem von ihrer Seite. – d3vkit

Antwort

6

Ich stieß auf das gleiche Problem und löste es, indem ich meine eigene Middleware hinzufügte und die Methoden "parse" und "on_complete" ohne viel Aufwand umschrieb und die Verwendung globaler Variablen vermied.

Hier ist der Code:

class CustomParserMiddleware < Her::Middleware::DefaultParseJSON 
     def parse(env) 
     json = parse_json(env[:body]) 
     pagination = parse_json(env[:response_headers][:pagination_key]) || {} 
     errors = json.delete(:errors) || {} 
     metadata = json.delete(:metadata) || {} 
     { 
      :data => json, 
      :errors => errors, 
      :metadata => { 
       :pagination => pagination, 
       :additional_metadata => metadata 
      }, 

    end 

     def on_complete(env) 
     env[:body] = case env[:status] 
      when 204 
      parse('{}') 
      else 
      parse(env) 
     end 
     end 
    end 

dann können Sie die Paginierung zugreifen wie folgt:

model = Model.all 
    model.metadata[:pagination] 
0
  • Sie können Header-Optionen zu Faraday übergeben, wenn der Verbindungsaufbau, bei http://rubydoc.info/gems/faraday/0.8.7/Faraday/Connection:initialize

  • die Dokumentation sehen Manchmal hilft es, besonders zuerst eine curl Anfrage zu tun. Verwenden Sie die Option -vv Option für ausführliche Ausgabe, wo Sie alle Überschriften sehen. (Vielleicht können Sie auch einige Protokollausgaben vom Server hinzufügen)

  • Sie können z. clogger (http://clogger.rubyforge.org/) tun Header-Informationen auf der Seite Rails-Server überwachen

+0

Ich füge bereits Header in Faraday hinzu, indem ich die Middleware verwende, die auf ihrer github-Seite gepostet wird. Das Problem ist, dass ich nicht vollständig verstehe, wie man die Middleware on_complete schreibt, um die Header, die von der API zurückgesendet werden, zu erhalten und sie dann meinem Controller zur Verfügung zu stellen. Und ich benutze Postman Chrome-Erweiterung, und die Header sind da - ich bin mir einfach nicht sicher, wie man sie benutzt! Am weitesten habe ich einen Leitfaden gesehen, der beschreibt, was man mit Kopfzeilen machen soll, wenn man nur in ein Protokoll schreibt. – d3vkit

2

ich diese Arbeit endlich. Der Trick bestand darin, eine globale Variable im Faraday on_complete zu verwenden - ich habe versucht, eine bessere Lösung zu finden, aber das war das Beste, was ich tun konnte. Noch einmal, ich habe den Header-Code von here. Hier ist die vollständige Anleitung, wie Sie Paginierung mit Her:

Zuerst auf meiner Server-Seite, ich habe die Kaminari Edelstein, und ich übergeben page und per als Parameter an den Server vom Client.(Dies ist auch ransack mit für die Suche)

def search 
    @search = Order.order('id desc').search(params[:q]) 
    @orders = @search.result(distinct: true).page(params[:page]).per(params[:per]) 

    respond_with @orders.as_json(include: :items) 
end 

Mein Klient die Anfrage wie macht so:

@orders = Order.search(q: { client_id_eq: @current_user.id }, page: params[:page], per: 3)` 

Zurück auf dem Server, ich habe dies in meinem ApiController (app-Controller für api):

protected 
    def self.set_pagination_headers(name, options = {}) 
    after_filter(options) do |controller| 
     results = instance_variable_get("@#{name}") 
     headers["X-Pagination"] = { 
     total_count: results.total_count, 
     offset_value: results.offset_value 
     }.to_json 
    end 
    end 

im Server orders_controller.rb, stelle ich die Paginierung Header für die Suchmethode:

class OrdersController < ApiController 
    set_pagination_headers :orders, only: [:search] 
    ... 
end 

Um jetzt die Header zu erhalten, benötigen wir eine Faraday-Middleware in Her auf dem Client.

# config/initializers/her.rb 
Her::API.setup url: Constants.api.url do |c| 
    c.use TokenAuthentication 
    c.use HeaderParser # <= This is my middleware for headers 
    c.use Faraday::Request::UrlEncoded 
    c.use Her::Middleware::DefaultParseJSON 
    c.use Faraday::Adapter::NetHttp 
    c.use Faraday::Response::RaiseError 
end 

# lib/header_parser.rb 
# don't forget to load this file in application.rb with something like: 
# config.autoload_paths += Dir[File.join(Rails.root, "lib", "*.rb")].each { |l| require l } 

class HeaderParser < Faraday::Response::Middleware 
    def on_complete(env) 
    unless env[:response_headers]['x-pagination'].nil? 
     # Set the global var for pagination 
     $pagination = JSON.parse(env[:response_headers]['x-pagination'], symbolize_names: true) 
    end 
    end 
end 

Jetzt zurück in Ihrem Client-Controller, haben Sie eine globale Variable von Hash namens $ Paginierung; Mine sieht wie folgt aus:

$pagintation = { total_count: 0, offset_value: 0 }` 

Schließlich habe ich Kaminari Juwel zu meinem Client-Anwendung das Array Paginieren und diese leicht Paginierung Links zu erhalten:

@orders = Kaminari.paginate_array(@orders, total_count: $pagination[:total_count]).page(params[:page]).per(params[:per_page])` 

Ich hoffe, das jemand anderes helfen kann, und wenn jemand weiß einen besseren Weg, dies zu tun, lass es mich wissen!

Verwandte Themen