2013-07-20 5 views
17

Sto costruendo un'API utilizzando ActiveModel :: Serializzatori. Qual è il modo migliore per caricare i dati in modo condizionale usando i parametri?Sideloading condizionale con ActiveModel :: Serializzatori

Così posso fare richieste come GET /api/customers:

"customers": { 
    "first_name": "Bill", 
    "last_name": "Gates" 
} 

E GET /api/customers?embed=address,note

"customers": { 
    "first_name": "Bill", 
    "last_name": "Gates" 
}, 
"address: { 
    "street": "abc" 
}, 
"note": { 
    "body": "Banned" 
} 

Qualcosa del genere a seconda delle params. So che ActiveModel :: Serializer ha la sintassi include_[ASSOCIATION]? ma come posso usarlo in modo efficiente dai miei controller?


Questa è la mia soluzione attuale, ma non è pulito:

customer_serializer.rb:

def include_address? 
    !options[:embed].nil? && options[:embed].include?(:address) 
end 

application_controller.rb:

def embed_resources(resources = []) 
    params[:embed].split(',').map { |x| resources << x.to_sym } if params[:embed] 
    resources 
end 

customers_controller.rb:

def show 
    respond_with @customer, embed: embed_resources 
end 

Deve essere un modo più semplice?

risposta

8

Sto anche cercando un modo efficace e pulito per farlo.

Ho trovato una soluzione ma non è carina.

Nel mio BaseController/ApplicationController ho aggiunto questo metodo:

serialization_scope :params 

Così il campo di applicazione è ora la Hash params e posso usarlo nei include_[ASSOCIATION]? metodi dei miei serializzatori.

def include_associations? 
    if scope[:embed] 
     embed = scope[:embed].split(',') 
     return true if embed.include?('associations') 
    end 
end 

Non mi piace questo metodo perché se ho bisogno di usare il campo di applicazione per qualcos'altro come la current_user per restituire i dati in modo condizionale se si tratta di un amministratore per esempio.

Ma questa soluzione può funzionare in alcuni casi.

UPDATE

È possibile passare view_context invece di passare direttamente alla params.

E è possibile delegare nel proprio serializzatore per mantenere il nome params anziché scope.

nel ApplicationController:

serialization_scope :view_context 

nel vostro serializzatore:

delegate :params, to: :scope 

E voilà è possibile utilizzare params [: Embed] nei include_[ASSOCIATION]? metodi di vostri serializzatori.

+0

Mi piacciono i tuoi suggerimenti utilizzando view_context. È possibile testare l'unità con rspec? – Richard

+0

Ho aggiornato la mia domanda per mostrarvi come l'ho fatto. – Richard

+0

Risposta brillante, grazie @lou. Molto elegante. – tristanm

2

Ho ancora un'altra soluzione basata sulle tue risposte perché volevo funzionalità simili. Secondo la documentazione, se si desidera il controllo di livello inferiore della serializzazione dell'associazione, è possibile ignorare lo include_associations!.

Ad esempio:

def include_associations! 
    if scope[:embed] 
     include! :addresses, {embed: :ids, include: true} 
    else 
     include! :addresses, {embed: :ids} 
    end 
end 
1

Molto utile sapere su include_associations !, grazie! Notando che con la gemma active_model_serializers (versione 0.8.3) è possibile utilizzare @options per impostare il contesto nel controller. Ad esempio, se nel controller si chiama

render json: customer, include_addresses: true 

poi nel CustomerSerializer:

has_many :addresses 
def include_associations! 
    if @options[:include_addresses] 
    include! :addresses 
    end 
end 

poi verrà serializzato gli indirizzi. Se esegui il rendering con include_addresses impostato su false, non lo saranno. Con le versioni più recenti di active_model_serializers, utilizzare serialization_options anziché @options.