2013-08-21 1 views
5

Active Record Store consente di serializzare i parametri all'interno di una singola cella.Dynamic Active Record Accede ai programmi basati su un modulo utente?

I.e.

class User < ActiveRecord::Base 
    store :options, accessors: [ :option1, :option2, :another_random_option ] 
end 

Tutte le funzioni di accesso vengono serializzati all'interno della colonna "Opzioni" della tabella utenti ora.

u = User.new 
u.option2 = 'some option' 
u.option2 # => 'some option' 

Questa grande opera per la mia applicazione perché devo creare molte forme su una base quotidiana, dove il 90% della forma è la stessa (nome utente, hobby, interessi, ecc) e quindi il 10% sono schema -less (random_option_here, another_random_option_in_another_form). Non ho nemmeno bisogno di ordinare le opzioni senza schema.

Quello che ho fatto è stato creare 1 tabella per il 90% dei campi modulo sempre uguali, quindi ho un'altra tabella con l'ultimo 10% dei campi (il motivo per cui ho un'altra tabella è perché questo è una relazione belongs_to, quindi l'utente può avere molte righe in questa tabella).

<%= form_tag do %> 
    <%= #render partial form for an object that has non-changing fields %> 
    ... 
    <%= #render a schema-less partial form based off an ID passed here %> 
<% end > 

Ora l'unico problema è che ogni volta che creare un nuovo campo nel modulo personalizzato, devo aggiungere che il parametro in Active Record Store di accesso, altrimenti ottengo un metodo di errore mancante. Sarebbe bello se potessi entrare e creare tutti i moduli View che voglio per i campi senza schema e non aggiornare mai gli accessor nel Modello.

Quindi la mia domanda è: c'è comunque un modo per aggiungere dinamicamente tutti i campi personalizzati inviati dall'utente all'array degli accessors, in questo modo se l'utente ha inviato campi "some_random_option1221", "another_option_here", quindi non devo entrare nel array di accessori e aggiungere quel campo?

Grazie!

risposta

11

Con binari 4 e PostgreSQL seguenti funziona per me. Sembra che con alcuni piccoli aggiustamenti delle rotaie potrebbero essere usati anche 3 metodi di deposito.

Call store_accessor in modo dinamico su ciascuna delle chiavi di campo nell'hash del negozio di proprietà di una determinata istanza di modello. Se si dispone di un modello utente con una colonna denominata opzioni di tipo hstore, è possibile accedere già all'hash delle opzioni. (In rails 3, chiamerai il metodo store come nel codice della tua domanda per far funzionare il metodo options.)

Creare un metodo per farlo ogni volta che l'interfaccia utente aggiunge un nuovo campo. Quindi chiama anche questo metodo after_initialize, in modo che il caricamento di un utente dal db imposterà gli accessors del nome del campo al momento del caricamento. Si potrebbe anche voler chiamare questo metodo after_save.

class User < ActiveRecord::Base 
    after_initialize :add_field_accessors 
    after_save  :add_field_accessors 

    def add_store_accessor field_name 
    singleton_class.class_eval {store_accessor :options, field_name} 
    end 

    def add_field_accessors 
    num_fields = options.try(:keys).try(:count) || 0 
    options.keys.each {|field_name| add_store_accessor field_name} if num_fields > 0 
    end 
end 

Poi ogni istanza utente può avere diversi metodi store_accessor seconda di ciò campi ogni utente ha nella colonna opzioni nella riga db per quell'utente.

Nel controller, a seconda dell'interfaccia utente preferita per aggiungere/rimuovere/modificare le opzioni, è possibile avere un metodo di supporto per creare le opzioni su un utente e chiamarlo da nuovo, creare, aggiornare, ecc.

def build_options 
    @user.options = options_hash 
    @user.add_field_accessors 
end 

in Rails 3, invece di chiamare store_accessor, si sarebbe chiamata attr_accessor.

Si noti che non sarà possibile chiamare User.new (: option_1 => 'some_option_value') perché l'oggetto della classe User non ha i metodi accessor (poiché ogni istanza utente potrebbe avere attributi diversi.)

+0

Così bello, sembra come '' num_fields = options.try (: keys) .try (: count) || 0'' non è necessario, è possibile aggiungere un valore predefinito '' {} '' ai campi delle opzioni, quindi options.keys solo una matrice vuota. – zw963