6

Ich versuche, einen Hash der Optionen in einem einzelnen DB-Feld zu speichern. Das Formular ist in der Lage, die Daten in der DB zu speichern, aber nicht in der Lage, es wieder zu erhalten, wenn ich es bearbeite (z. B. sind alle anderen Felder mit Ausnahme der Felder wp_options bereits ausgefüllt).Verwenden von Rails Form Helpers mit serialisierten benutzerdefinierten Klassen

class Profile < ActiveRecord::Base 
serialize :wp_options 
end 

Dies ist meine eigene Klasse:

class WP_Options 
attr_accessor :wp_name, :wp_desc, :wp_limit 
end 

In meiner Form:

<%= form_for(@profile, :remote => true) do |f| %> 
... 
    <%= f.fields_for :wp_options do |wp_options| %> 
     <%= wp_options.text_field :wp_name %> 
    <% end %> 
... 

In meinem Controller:

@profile = Profile.new(:wp_options => WP_Options.new) 

In meiner DB Spalte 'wp_options':

--- !map:ActiveSupport::HashWithIndifferentAccess 
wp_name: Test 

Jeder Rat würde wirklich geschätzt werden.

Antwort

10

Eigentlich ist es einfach. Sie müssen die Klasse mit reader Methoden verwenden. Sie können es auf verschiedene Arten erstellen, aber am einfachsten ist es, die Klasse OpenStruct zu verwenden (beachten Sie, dass Felder, die sich in der OpenStruct-Instanz befinden, keine Methoden sehen können ... diese Klasse kann die Methoden nicht neu definieren).

In dem Formular sollten Sie hinzufügen:

<%= f.fields_for :wp_options, @profile.wp_options do |wp_options| %> 

Statt @profile (wenn Sie die dynamische Variable) Sie f.object.wp_options verwenden können.

Und zum Modell Profile sollten Sie wp_options Methode hinzufügen.

def wp_options 
    OpenStruct.new(self.attributes['wp_options']) 
end 

In diesem Fall wird es nur funktionieren, wenn Ihre serialisierte wp_options eine Hash-Klasse ist.

Hoffe, dass hilft.

PS. Ich benutzte die gleiche Technik, aber weil ich type Hash-Schlüssel hatte, konnte OpenStruct es nicht erstellen, also verwendete ich einfache Struct-Klasse. Ich hatte data Säule:

def data 
    keys = current_data.keys 
    data = attributes[:data] 
    Struct.new(*keys).new(*keys.map { |k| data[k] }) 
end 

Etwas weniger trivial, aber trotzdem den gleichen Ansatz (vor, dass ich Sonderklasse geschaffen, aber jetzt weiß ich, dass Struct ist der bessere Weg dieser Art Zeug zur Schaffung Mehr. Ideen finden Sie hier: How do I use hash keys as methods on a class?)

+0

Ich brauchte mein Äquivalent von wp_options, um als Hash zu bleiben, damit ich über seine Einträge iterieren konnte. Also habe ich keine Änderungen am Modell vorgenommen und das 'OpenStruct.new' in das Formular wie folgt eingefügt: <% = f.fields_for: wp_options, OpenStruct.new (@ profile.wp_options) do | wp_options | %> Vielleicht hat es die Ansicht in die Modellimplementierung spähen, aber alles, was es weiß, ist, dass wp_options ein Hash ist, anstelle eines Objekts mit attr Methoden. – Turadg

1

Für 3.0.5 diejenigen mit Dmitry-Lösung, die auf Schienen (nicht sicher prev/next Versionen vor so versuchen), fügen

require 'ostruct' 

auf Ihre environment.rb Datei um OpenStruct inc. zu haben lud.

Wenn Sie mit JSON zu serialisieren, in Ihrem Modell hinzufügen (oh und ich bin ziemlich neu zu RoR, so zögern Sie nicht, zu prüfen und schlagen Sie eine bessere, "funktionierende" Lösung dann) (meine Variablennamen geändert, um die obigen Beispiel) entsprechen:

before_save :json_serialize 
after_save :json_deserialize 
after_find :json_deserialize 

def json_serialize 
    self.wp_options = ActiveSupport::JSON.encode(self.attributes['wp_options']) 
end 

def json_deserialize 
    unless (self.attributes['wp_options'].nil?) 
    self.wp_options = ActiveSupport::JSON.decode(self.attributes['wp_options'].to_s) 
    end 
end 

ein letzter Punkt: ich bin ehrlich gesagt nicht sicher, warum es in self.wp_options und nicht self.attributes [ 'wp_options gespeichert werden muss Wenn jemand erklären könnte, wäre es cool.

0

Ich stieß auf das gleiche Problem. Meine Lösung war die folgende:

  1. Definieren Sie eine Methode in der Helfer:

    def wp_options_text_field(profile, wp_options, name) 
        wp_options.text_field name, :value => profile.wp_options[name] 
    end 
    
  2. Ihrer Ansicht:

    <%= form_for(@profile, :remote => true) do |f| %> 
    ... 
    <%= f.fields_for :wp_options do |wp_options| %> 
        <%= wp_options_text_field :wp_name %> 
    <% end %> 
    ... 
    

Das einzige Problem hier ist, dass man‘ Sie müssen Methoden für jede Hilfsmethode definieren, die Sie verwenden. In meinem Fall hatte ich nur 2 Methoden und es war nicht schmerzhaft.

Verwandte Themen