Использование помощников форм Rails с сериализованными пользовательскими классами - PullRequest
6 голосов
/ 21 сентября 2010

Я пытаюсь сохранить хэш опций в одном поле БД.Форма может сохранять данные в БД, но не может получить их снова, когда я иду редактировать их (например, все остальные поля предварительно заполнены, кроме полей wp_options).

class Profile < ActiveRecord::Base  
 serialize :wp_options  
end

Это мой пользовательский класс:

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

В моей форме:

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

В моем контроллере:

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

В моей колонке БД «wp_options»:

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

Любой совет будет очень признателен.

Ответы [ 3 ]

11 голосов
/ 31 октября 2010

На самом деле это легко.Вам нужно использовать класс с reader методами.Вы можете создать его различными способами, но самый простой - использовать класс OpenStruct (обратите внимание, что он не сможет видеть поля, которые находятся в методах экземпляра OpenStruct ... этот класс не может переопределять методы).

В вашей форме вы должны добавить:

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

Вместо @profile (если у вас есть динамическая переменная) вы можете использовать f.object.wp_options.

И к модели Profile Вы должны добавить wp_options метод.

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

В этом случае он будет работать только в том случае, если ваши сериализованные wp_options являются классом Hash.

Надеюсь, что это поможет.PS.Я использовал ту же технику, но поскольку у меня было type хеш-ключей, OpenStruct не смог его создать, поэтому я использовал простой класс Struct.У меня был столбец data:

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

Немного менее тривиальный, но в любом случае тот же подход (до этого я создал специальный класс, но теперь я знаю, что Struct - лучший способ его создания.Добрые дела. Больше идей вы можете найти здесь: Как использовать хеш-ключи в качестве методов в классе? )

1 голос
/ 16 апреля 2011

Для тех, кто использует решение Дмитрия, на rails 3.0.5 (не уверен насчет предыдущих / следующих версий, поэтому попробуйте раньше), добавьте

require 'ostruct'

в файл environment.rb, чтобы включить OpenStruct.

Если вы собираетесь сериализовать с JSON, добавьте в свою модель (о, и я довольно новичок в RoR, поэтому, пожалуйста, не стесняйтесь исследовать и предложить лучшее, «работающее» решение, чем это)( мои имена переменных изменены, чтобы соответствовать приведенному выше примеру ):

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

В заключение: Я, честно говоря, не уверен, почему это должно быть сохраненов self.wp_options, а не в self.attributes ['wp_options'], если кто-то может объяснить это было бы здорово.

0 голосов
/ 30 июня 2011

Я столкнулся с той же проблемой.Мое решение было следующим:

  1. Определите метод в вашем помощнике:

    def wp_options_text_field(profile, wp_options, name)
      wp_options.text_field name, :value => profile.wp_options[name]
    end
    
  2. На ваш взгляд:

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

Единственная проблема здесь в том, что вам нужно определить методы для каждого вспомогательного метода, который вы будете использовать.В моем случае я использовал только 2 метода, и это не было больно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...