Сериализованное хэш-поле и простая форма - PullRequest
11 голосов
/ 08 марта 2012

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

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

Значение fields будет зависеть от категории.Но в качестве примера:

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

25 голосов
/ 13 февраля 2013

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

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

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

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

Но это не заполняло форму должным образом. Решение nicholaides об обёртывании хеша в структуру сработало для меня:

- 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 с моим представлением, я создал обезьянький патч для 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

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

3 голосов
/ 08 марта 2012

Использование OpenStruct .Это работает так:

require 'ostruct'

struct = OStruct.new("address" => "8 finance street, hong kong", "founded" => "1973")
struct.address # => 8
struct.founded # => "1973"
1 голос
/ 02 мая 2014

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

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

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

1 голос
/ 22 марта 2012

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

https://gist.github.com/2157877

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

Ура!

...