【问题标题】:How to add an element into an array of a Serialize Field using Ruby on Rails如何使用 Ruby on Rails 将元素添加到序列化字段的数组中
【发布时间】:2019-08-13 18:21:39
【问题描述】:

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

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

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

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

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

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

例如:从我的项目列表中删除 {:id => 2} 并将 `{:id => 4} 添加到它

【问题讨论】:

    标签: mysql ruby-on-rails json serialization


    【解决方案1】:

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

    thing = {:items => [
      {:id => 1},
      {:id => 2},
      {:id => 3}
    ]}
    thing.to_json # "{\"items\":[{\"id\":1},{\"id\":2},{\"id\":3}]}"
    

    thing.to_json 本质上是序列化程序中发生的事情。如果你想让他们回到 Ruby,你可以这样做:

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

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

    thing = {:items => [
      {:id => 1},
      {:id => 2},
      {:id => 3}
    ]}
    thing[:items] = thing[:items].append({:id => 4})   # adding a new item
    thing[:items] = thing[:items].select { |item| item[:id] != 2 } # removing an item
    

    【讨论】:

      【解决方案2】:

      第一:序列化的第二个参数应该是你在字段中存储的对象的类。你应该改用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!,以便在保存时正确更新。

      【讨论】:

        【解决方案3】:

        基于@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
        

        【讨论】:

          猜你喜欢
          • 2022-01-11
          • 2012-06-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-03-01
          • 2012-08-09
          • 1970-01-01
          相关资源
          最近更新 更多