2012-02-19 7 views
6

Ho riscontrato un problema nella mia app Rails 3.2 in cui un attributo virtuale inviato restfully tramite JSON non si trova nel punto giusto dell'hash params. Beh, non è dove mi aspetto. Resta da vedere se le mie aspettative sono corrette. :)L'attributo virtuale non è stato spostato nell'hash del modello all'interno dei parametri

Ho un modello utilizzando il modello standard di attributi virtuali, in questo modo:

class Track < ActiveRecord::Base 
    def rating 
    # get logic removed for brevity 
    end 

    def rating=(value) 
    # set logic 
    end 

    def as_json(options={}) # so my method is in the JSON when I use respond_with/to_json 
    super(options.merge(methods: [:rating])) 
    end 
end 

Il JSON inviato al mio controller simile a questo:

{"id":1,"name":"Icarus - Main Theme 2","rating":2} 

Per essere chiari, il nome e l'id non è virtuale, la valutazione è.

io alla fine con questo l'hash params, dopo rotaie fa la sua magia:

{"id"=>"1", "name"=>"Icarus - Main Theme 2", "rating"=>2, "track"=>{"id"=>"1", "name"=>"Icarus - Main Theme 2"}} 

Come si può vedere, l'ID e il nome lo fanno alla nidificato: hash pista, ma voto non lo fa. È questo comportamento previsto? Rompe la (un po ') pratica standard di usare l'hash annidato nel controller perché l'hash annidato non contiene tutti i parametri che mi servono.

Track.update(params[:id], params[:track]) # :track is missing rating 

Grazie per il vostro aiuto!

+0

È possibile incollare il modulo che sta effettuando l'invio, sembra che non sia correttamente impostato per tracciare – MatthewFord

risposta

7

Recentemente mi sono imbattuto in questo gotcha. Il problema è che il wrapper params sta guardando il tuo modello Track.attribute_names per determinare come mappare i dati in un hash: track => {params}. Se non si dispone di un modello associato, il default sarà quello di avvolgere i params in base al nome del controller, e comprendono tutti i valori:

class SinglesController < ApplicationController 
    def create 
    #params[:single] will contain all of your attributes as it doesn't 
    # have an activerecord model to look at. 
    @track_single = Track.new(params[:single]) 
    end 
end 

È possibile chiamare wrap_parameters nel controller per raccontare cosa Action Controller attributi da includere quando suo involucro tuoi params, in questo modo:

class TracksController < ApplicationController 
    wrap_parameters :track, :include => :rating 
    #other controller stuff below 
end 

Vedere più qui: http://api.rubyonrails.org/classes/ActionController/ParamsWrapper.html

+3

Ho riscontrato problemi simili, quando si utilizza wrap_parameters, se ho molti altri attributi non virtuali, ho dovuto scrivere tutti loro alla matrice include. altrimenti non saranno inclusi nell'hash della richiesta, come farlo in un modo semplice? dal momento che ho solo un attributo virtuale che voglio includere nell'hash della richiesta? Grazie – user1883793

0

Forse se si assegna l'attributo virtuale rating all'interno del hash nidificato in questo modo:

def as_json(options={}) 
    super(options.merge(:track => {:methods => @rating})) 
end 

si comporterebbe all'altezza di ogni aspettativa.

0

proprio imbattuto in questo problema e capito una soluzione abbastanza decente. Aggiungere quanto segue al vostro ApplicationController

wrap_parameters exclude: [:controller, :action, :format] + ActionController::ParamsWrapper::EXCLUDE_PARAMETERS 

In questo modo, tutto ciò che è nidificato sotto la risorsa (ad eccezione di Rails roba aggiunge l'hash params) e non sarà mai avere da aggiungere a una specifica chiamata controllore della wrap_parameters nuovo . : D