2012-03-08 1 views
10

Ho il seguente.Campo hash serializzato e modulo semplice

class Page < ActiveRecord::Base 
    belongs_to :category 
    serialize :fields 
end 

Il valore di fields dipende dalla categoria. Ma ad esempio;

{"address" => "8 finance street, hong kong", 
"founded" => "1973"} 

In questo esempio la categoria ha definito "address" e "founded" come i campi personalizzati.

Quello che voglio è dire;

= simple_form_for(@page) do |f| 
    = f.association :category 
    - f.object.category.fields.each do |field| 
    = f.input field.name 

ma ho bisogno di fare qualcosa di magico a che fare con il fatto che non è valida @page.founded

Invece dovrebbe essere guardando @page.fields["founded"].

Qualche suggerimento?


Aggiornamento:

devo un po 'più vicino

- if f.object.category 
    - f.object.category.fields.each do |field| 
    = f.input field.name do 
     = text_field_tag "post[fields][#{field.name}]", f.object.fields[file.name] 

ora necessario rendere questa biancheria (non si vuole specificare il nome dell'oggetto).

Vedrò se riesco a scrivere un'estensione di modulo semplice decente per questo.

risposta

25

Mi sono imbattuto in un problema simile cercando di utilizzare simple_fields_for su un tipo di campo hash di un modello mongolo. La versione Mongoid del vostro esempio avevo a che fare con si presentava così:

class Page 
    include Mongoid::Document 
    field :fields, type: Hash 
end 

La mia situazione potrebbe essere leggermente diversa anche se, come so già le chiavi hash sto cercando prima del tempo, e solo bisogno simple_fields_for al lavoro con il campo dell'hash. Il metodo ingenuo (base fields_for utilizzo) usavo si presentava così:

= simple_form_for(@page) do |f| 
    = f.simple_fields_for :fields do |ff| 
    = ff.input :address 
    = ff.input :founded 

ma che non era popolare il modulo correttamente.soluzione di avvolgere l'hash in una struttura di nicholaides ha funzionato per me:

- require 'ostruct' 
= simple_form_for(@page) do |f| 
    = f.simple_fields_for :fields, OpenStruct.new(@page.fields) do |ff| 
    = ff.input :address 
    = ff.input :founded 

per evitare di dover mescolare la roba OpenStruct nel mio punto di vista, ho creato una patch scimmia per simple_form per avvolgere automaticamente i tipi di hash in un OpenStruct e metterlo in un inizializzatore:

require 'ostruct' 

module SimpleForm::ActionViewExtensions::Builder 
    def simple_fields_for_with_hash_support(*args, &block) 
    if args[0] && !args[1] 
     field = object.send(args[0]) 
     args << OpenStruct.new(field) if field.respond_to?(:has_key?) 
    end 
    simple_fields_for_without_hash_support(*args, &block) 
    end 
    alias simple_fields_for_without_hash_support simple_fields_for 
    alias simple_fields_for simple_fields_for_with_hash_support 
end 

E ora posso usare la mia soluzione ingenua originale senza speciale codice della vista.

+0

+1 per "f.simple_fields_for: fields, OpenStruct.new (@ page.fields) do | ff |". Ho distrutto il mio cervello più di un'ora per capire perché non stava recuperando i valori correttamente fino a quando ho aggiunto il bit OpenStruct. – gk0r

+1

È fantastico. Una nota aggiunta per gli utenti con parametri forti: è necessario definire ciascun campo aggiunto in modo esplicito. Ad esempio, 'params.require (: page) .permit (: fields => [: address,: found])' –

+0

Thx per la soluzione, funziona perfettamente, con una eccezione: non so, come aggiungere la convalida errori in '@ page.fields'. –

3

Utilizzare OpenStruct. Funziona in questo modo:

require 'ostruct' 

struct = OStruct.new("address" => "8 finance street, hong kong", "founded" => "1973") 
struct.address # => 8 
struct.founded # => "1973" 
+0

che va bene per il "esigibilità" (mi ricordo utilizzando un 'CallableHash' indietro nella day'). Ma la mia domanda specifica riguarda SimpleForm, davvero. Voglio una soluzione pulita. –

1

ecco una soluzione si potrebbe facilmente adattarsi al tuo problema:

https://gist.github.com/2157877

Mantiene la forma super-pulito e mantiene il comportamento normale di un modello attivo (niente aggiungere nel controller).

Cheers!

1

Se solo ho trovato questo post prima non avrei perso tre giorni su questo problema.

non ero in grado di commentare l'answear così solo per aggiungere, se qualcuno cerca di fields_for una matrice Mongo di hash (has_many simili) inoltre sarà necessario fornire l'oggetto radice OpenStruct con un "#{key}_attributes=" (in questo caso fields_attributes =) metodo in modo che fields_for identifichi che è una relazione has_many.

speriamo vi sia utile a qualcuno;)