我在MySQL数据库中有一个定义为query_data
的字段调用text
。
在我的模型中,我将此字段定义为serialize :query_data, JSON
。
我想要保存和检索的JSON格式如下:
{:items => [
{:id => 1},
{:id => 2},
{:id => 3}
]}
我有一个包含对象数组的集合(在这种情况下,称为items
)。
我想知道,添加或删除项目的最佳方法是什么。
例如:从我的物品列表中删除{:id => 2}
并在其中添加`{:id => 4}
答案 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