Rails技巧:如何获取动态JSON字段

126 阅读2分钟

Rails技巧:如何获取动态JSON字段

最近我有机会在一个需要与JSON数组交互的软件上工作。正如你可能知道的那样,在ActiveRecord中使用原生JSON列,就像使用 store_accessor.例如,假设我们要定义一个新的列json_object ,必须遵循这个JSON结构。

{
  "name": "juan perez",
  "age": 69
}

通过以下方式使用store_accessor

store_accessor :json_object, :name, :age

你将为这两个字段定义访问器,最后将这些字段保存为JSON格式的特定列。没有什么真正的花哨。

但是......如果我们需要存储和编辑这样的东西呢。

[
  "value1",
  "value2",
  "value3"
]

这让事情有了一些变化。

那么解决方案是什么呢?

ActiveModel来拯救

在这个Rails应用程序的例子中,有两个关键来解决这个问题,第一个这段代码

# frozen_string_literal: true
class Tag
  include ActiveModel::Model

  attr_accessor :name

  validates :name, length: { maximum: 5, allow_blank: true }

  def marked_for_destruction?
    false
  end
end

上面的类定义了直接存储在JSON列中的单个元素(在我们上面的例子中,任何一个"value1","value2""value3" )。

注意这是一个简单的Ruby类,其中包括 ActiveModel::Model,这样我们就可以添加验证器并允许我们它作为父模型的一部分使用。

谜题的第二部分下面的关注点包含在定义有这个JSON数组列的表的模型中)。

这个问题的重要部分如下

validates :tags, associated: true

def tags
  @tags ||= add_missing_values(build_from_column)
end

def tags_attributes=(attributes)
  write_attribute(:json_tags, attributes.values)
end
  • validates 允许我们明显地确保嵌套的对象是有效的,如果它们不是有效的,它允许我们正确地渲染视图。error validation
  • tags 方法允许我们使用 fields_for
  <%= form.fields_for :tags, include_id: false do |form_tags| %>
    <li>
      <%= form_tags.label :name %>
      <%= form_tags.text_field :name %>
    </li>
  <% end %>
  • 最后,tags_attributes= 方法作为提交表单时的设置器。

有了这个方法,你可以将一个数组的值存储到JSON列中。对这个Rails应用程序的一个很好的改进是加入cocoon,允许添加(和删除)任何数量的动态字段,而不是我们目前定义的硬编码。