Сериализованное поле Hash и простая форма
У меня есть следующее.
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"]
.
Любые предложения?
Update:
У меня немного ближе
- 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]
Теперь нужно сделать этот DRYer (не хотите указывать имя объекта).
Я посмотрю, могу ли я написать для этого простое расширение простой формы.
Ответы
Ответ 1
Я столкнулся с аналогичной проблемой, пытаясь использовать simple_fields_for
в типе поля Hash модели 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
И теперь я могу использовать свое первоначальное наивное решение без специального кода просмотра.
Ответ 2
Используйте OpenStruct. Он работает следующим образом:
require 'ostruct'
struct = OStruct.new("address" => "8 finance street, hong kong", "founded" => "1973")
struct.address # => 8
struct.founded # => "1973"
Ответ 3
Вот решение, которое вы могли бы легко адаптировать к своей проблеме:
https://gist.github.com/2157877
Сохраняет форму сверхчистой и сохраняет нормальное поведение активной модели (ничего не добавить в контроллер).
Приветствия!
Ответ 4
Если бы я только нашел этот пост раньше, я бы не пропустил три дня по этому вопросу.
Мне не удалось прокомментировать ответ, поэтому просто добавьте, если кто-то пытается fields_for
массива хангов mongo (has_many like) дополнительно вам нужно будет предоставить корневой объект OpenStruct с помощью "#{key}_attributes="
(в этот случай fields_attributes =), поэтому fields_for
будет идентифицировать это отношение has_many.
Надеюсь, это поможет кому-то;)