从具有简单形式的散列动态创建输入
Creating inputs dynamically from a hash with simple form
我有一个 Configuration
模型,它在 JSONB 列中存储 settings
。
# Stores site wide configuration settings
# This is used in conjunction with PaperTrail to make each change traceable
class Configuration < ActiveRecord::Base
has_paper_trail
validates_uniqueness_of :name
after_initialize :default_values if :new_record?
private
def default_values
self.settings = {
site_title: 'Portfolio Site'
}
end
end
模型设置了某些默认属性,例如site_title
。我想使用设置哈希在我的表单中动态创建输入。我试过:
= simple_form_for(@configuration) do |f|
= f.input :name
= simple_fields_for :settings do
- @configuration.settings.each do |k,v|
= f.input k
= f.submit
这给出 undefined method 'site_title'
因为它不是模型属性。我可以在指定键和值绑定时使用 simple_forms input
方法吗?
看起来您不能将 simple_form
用于非属性输入。不过这会起作用:
= simple_form_for(@configuration) do |f|
= f.input :name
- @configuration.settings.each do |k,v|
= text_field_tag "configurations[settings][#{k}]", v
= f.submit
您可能会扩展默认设置的值,以包含您希望通过 array
呈现的输入类型。
它实际上就像为散列创建一个代理对象或装饰器一样简单——它就像一个模型。
class SettingsDecorator
INPUT_TYPES = {
some_number: :integer
}
# @see http://api.rubyonrails.org/classes/ActiveModel/Naming.html
MODEL_NAME = ActiveModel::Name.new(self.class, nil, 'settings')
# @see http://api.rubyonrails.org/classes/ActiveModel/Naming.html
def model_name
MODEL_NAME
end
def initialize(hash)
@object = hash.symbolize_keys
end
def method_missing(method, *args, &block)
if @object.key? method
@object[method]
elsif @object.respond_to? method
@object.send(method, *args, &block)
end
end
def has_attribute? attr
@object.key? attr
end
def input_type? key
INPUT_TYPES[key]
end
end
简单表单尝试查找每个输入的列,但如果对象不响应 column_for_attribute
.
,则会优雅地回退到 :text
然后我可以像这样使用它:
= simple_form_for(@configuration) do |f|
= f.input :name
- settings = SettingsDecorator.new(@configuration.settings)
= simple_fields_for settings do |sf|
- settings.keys.each do |key|
= sf.input key, as: settings.input_type?(key)
= f.submit
我有一个 Configuration
模型,它在 JSONB 列中存储 settings
。
# Stores site wide configuration settings
# This is used in conjunction with PaperTrail to make each change traceable
class Configuration < ActiveRecord::Base
has_paper_trail
validates_uniqueness_of :name
after_initialize :default_values if :new_record?
private
def default_values
self.settings = {
site_title: 'Portfolio Site'
}
end
end
模型设置了某些默认属性,例如site_title
。我想使用设置哈希在我的表单中动态创建输入。我试过:
= simple_form_for(@configuration) do |f|
= f.input :name
= simple_fields_for :settings do
- @configuration.settings.each do |k,v|
= f.input k
= f.submit
这给出 undefined method 'site_title'
因为它不是模型属性。我可以在指定键和值绑定时使用 simple_forms input
方法吗?
看起来您不能将 simple_form
用于非属性输入。不过这会起作用:
= simple_form_for(@configuration) do |f|
= f.input :name
- @configuration.settings.each do |k,v|
= text_field_tag "configurations[settings][#{k}]", v
= f.submit
您可能会扩展默认设置的值,以包含您希望通过 array
呈现的输入类型。
它实际上就像为散列创建一个代理对象或装饰器一样简单——它就像一个模型。
class SettingsDecorator
INPUT_TYPES = {
some_number: :integer
}
# @see http://api.rubyonrails.org/classes/ActiveModel/Naming.html
MODEL_NAME = ActiveModel::Name.new(self.class, nil, 'settings')
# @see http://api.rubyonrails.org/classes/ActiveModel/Naming.html
def model_name
MODEL_NAME
end
def initialize(hash)
@object = hash.symbolize_keys
end
def method_missing(method, *args, &block)
if @object.key? method
@object[method]
elsif @object.respond_to? method
@object.send(method, *args, &block)
end
end
def has_attribute? attr
@object.key? attr
end
def input_type? key
INPUT_TYPES[key]
end
end
简单表单尝试查找每个输入的列,但如果对象不响应 column_for_attribute
.
:text
然后我可以像这样使用它:
= simple_form_for(@configuration) do |f|
= f.input :name
- settings = SettingsDecorator.new(@configuration.settings)
= simple_fields_for settings do |sf|
- settings.keys.each do |key|
= sf.input key, as: settings.input_type?(key)
= f.submit