使用 simple_form 添加自定义 JSONB text_field 标签

Adding a custom JSONB text_field tag with simple_form

我的 Rails 应用程序的模型上有一个 JSONB 类型 options 列,我现在需要为每个表单手动提供 JSONB 嵌套参数。这就是为什么官方提出的解决方案 here 不是一个选项。

所以我可能想要这样的东西:

options[first_name], options[last_name]

一个实例,另一个完全不同的集合:

options[pet_dog], options[frank_sinatra]

我认为它可以很好地使用类似

的东西来实现
= f.text_field :options[pet_dog]

但它不起作用。

你是如何实现 jsonb 列的?您是否将此添加到模型中?

serialize :options, HashSerializer
store_accessor :options, :pet_dog, :pet_cat, :pet_cow

*请注意,HashSerializer 是一个 class 作为序列化程序的,它看起来像这样:

class HashSerializer
  def self.dump(hash)
    hash.to_json
  end

  def self.load(hash)
    (hash || {}).with_indifferent_access
  end
end

模型上这两行的作用是允许您对 json/jsonb 键使用访问器(getter 和 setter)。所以你可以这样做:

object = Model.new
object.pet_dog = 'Dog1'
object.pet_cat = 'Cat1'
object.options = {"pet_dog"=>"Dog1", "pet_cat"=>"Cat1"}

这又允许您将其用作表单字段:

f.text_field :pet_dog
f.text_field :pet_cat

不要忘记将 strong_params 方法中的属性列入白名单

您可以阅读南多·维埃拉 (Nando Vieira) 撰写的这篇综合 post 的更多内容: http://nandovieira.com/using-postgresql-and-jsonb-with-ruby-on-rails

另外,如果你想要快捷方式,这里有一个 gem: https://github.com/devmynd/jsonb_accessor

我的解决方案代码如下所示:

查看表单:

= f.simple_fields_for :options do |p|
  - @options.each do |o|
    = p.input o.name.to_sym, input_html: {value: o.default_value}

控制器

def new
  @options = Model.options
  ...
end

def create
  @job  = current_user.jobs.build(job_params)
end

...

def job_params
  params.require(:job_request).permit(
  ...
  options: get_options)
end

def get_options
  some_model.options.pluck(:name).map(&:to_sym)
end

可能这会对某人有所帮助。