如何使用Ruby on Rails将元素添加到序列化字段的数组中

时间:2019-03-22 17:40:30

标签: mysql ruby-on-rails json serialization

我在MySQL数据库中有一个定义为query_data的字段调用text

在我的模型中,我将此字段定义为serialize :query_data, JSON

我想要保存和检索的JSON格式如下:

{:items => [
  {:id => 1},
  {:id => 2},
  {:id => 3}
]}

我有一个包含对象数组的集合(在这种情况下,称为items)。

我想知道,添加或删除项目的最佳方法是什么。

例如:从我的物品列表中删除{:id => 2}并在其中添加`{:id => 4}

3 个答案:

答案 0 :(得分:1)

Ruby on Rails有一些不错的方法可以在JSON和Ruby之间无缝移动。

import funcy


funcy.flatten([[[[1, 1], 1], 2], 3]) # returns generator
funcy.lflatten([[[[1, 1], 1], 2], 3]) # returns list

thing = {:items => [ {:id => 1}, {:id => 2}, {:id => 3} ]} thing.to_json # "{\"items\":[{\"id\":1},{\"id\":2},{\"id\":3}]}" 本质上是串行器中正在发生的事情。如果您希望他们回到Ruby,只需执行以下操作:

thing.to_json

现在我们可以轻松地在两者之间切换,让我们只使用Ruby语法来处理添加和删除键。

@items = @thing.query_data
JSON.parse(@items) # "items"=>[{"id"=>1}, {"id"=>2}, {"id"=>3}]}

答案 1 :(得分:0)

第一个:要序列化的第二个参数应该是您存储在字段中的对象的类。您应该改为使用serialize :query_data, Hash

除此之外,对于序列化数据的使用,实际上还没有任何公认的最佳实践。实际上,这很大程度上取决于您的数据结构。您可能还会问:“从哈希中添加或删除项目的最佳方法是什么?”

但是,由于这是一个哈希,因此您应确保牢记dirty attributes。如果您要执行以下操作:

items = my_model.query_data[:items]
items.reject! {|item| item[:id] == 2}
items += {id: 4}

然后模型将不知道query_data已更改,应该在保存时进行更新。

my_model.changed?
# => false
my_model.save
# Won't actually save changes to db.

为避免这种情况,您可以:

A)确保仅直接设置my_model.query_data

B)更改该字段后,显式调用my_model.query_data_will_change!,以便在保存时对其进行正确的更新。

答案 2 :(得分:0)

基于@veridian-dynamics(感谢您的帮助!)这就是我所做的。

型号:

class MyModel < ApplicationRecord
  serialize :item_data, JSON
end

控制器:

class ItemController  < ApplicationController
  before_action :authenticate_user!

  def add_item
    begin

      mymodel = MyModel.find_or_create_by(id: param[:model_id])

      if mymodel .item_data.blank?
        item = {:items => []}
      else
        item = mymodel.item_data.deep_symbolize_keys
      end

      bookmark_exist = item[:items].any? {|i| i[:id] == params[:id]}
      if !bookmark_exist
        item[:items] = item[:items ].append({id: params[:id]})   # adding a new item
      end

      mymodel.item_data = item
      mymodel.save

      return render :json => item, :status=> 200    

    rescue Exception => e
      return render :json =>{:errors=>e.message}, :status=> 400
      puts "ERROR: #{e.message}"
    end
  end

  def delete_item
    begin

      mymodel = MyModel.find_by(id: params[:model_id])
      if mymodel.present? && mymodel.item_data.present?
        item = mymodel.item_data.deep_symbolize_keys

        item[:items] = (item[:items].select { |itm| itm[:id] != params[:id] })   # remove an item
        mymodel.item_data =  item    
        mymodel.save

        return render :json => item, :status=> 200    
      end
    rescue Exception => e
      return render :json =>{:errors=>e.message}, :status=> 400
      puts "ERROR: #{e.message}"
    end
  end

end