Сериализованное хэш-поле и простая форма


У меня есть следующее.

class Page < ActiveRecord::Base
  belongs_to :category
  serialize :fields
end
Значение

Будет зависеть от категории. Но в качестве примера;

{"address" => "8 finance street, hong kong",
 "founded" => "1973"}
В этом примере категория определила "address" и "founded" как пользовательские поля.

То, что я хочу сказать;

= simple_form_for(@page) do |f|
  = f.association :category
  - f.object.category.fields.each do |field|
    = f.input field.name
Но мне нужно сделать что-то волшебное, чтобы справиться с тем фактом, что @page.founded не является действительным

Вместо этого я должен смотреть на @page.fields["founded"].

Есть предложения?


Обновление:

У меня есть немного ближе

- 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]

Теперь нужно сделать эту сушилку (не хочу указывать название объекта).

Я посмотрю, смогу ли я написать приличное простое расширение формы для этого.
4 10

4 ответа:

Я столкнулся с подобной проблемой, пытаясь использовать simple_fields_for на типе хэш-поля Монгоидной модели. Монголоидная версия вашего примера, с которой я имел дело, выглядела так:

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

Моя ситуация может быть немного иной, так как я уже знаю хэш-ключи, которые я ищу заранее, и просто необходим simple_fields_for для работы с хэш-полем. Наивный метод (basic fields_for usage), который я использовал, выглядел так:

= simple_form_for(@page) do |f|
  = f.simple_fields_for :fields do |ff|
    = ff.input :address
    = ff.input :founded
Но это не заполняло форму должным образом. у николайдеса решение обертывания хэша в структуру сработало для меня:
- 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

Чтобы избежать необходимости смешивать материал OpenStruct в моем представлении, я создал monkey patch для simple_form, чтобы автоматически обернуть хэш-типы В OpenStruct и поместить его в инициализатор:

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

И теперь я могу использовать свое оригинальное наивное решение без специального кода представления.

ИспользуйтеOpenStruct . Это работает следующим образом:

require 'ostruct'

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

Вот решение, которое вы можете легко адаптировать к вашей проблеме:

Https://gist.github.com/2157877

Сохраняет форму супер-чистой и сохраняет нормальное поведение активной модели (ничего добавить в контроллер).

Ура !

Если бы только я нашел этот пост раньше, я бы не пропустил три дня по этому вопросу.

Я не смог прокомментировать answear, поэтому просто добавить, если кто-то пытается fields_for массив mongo хэшей (has_many like) дополнительно вам нужно будет предоставить корневой объект OpenStruct с "#{key}_attributes=" (в этом случае fields_attributes=) метод, так что fields_for будет идентифицировать это отношение has_many.

Надеюсь, это кому-то поможет;)