Как добавить элемент в массив поля Serialize, используя Ruby on Rails - PullRequest
0 голосов
/ 22 марта 2019

У меня есть вызов поля query_data, определенный как text в моей базе данных MySQL.

В моей модели я определил это поле как serialize :query_data, JSON.

Формат JSON, который я хотел бы сохранить и получить, выглядит следующим образом:

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

У меня есть коллекция (в этом случае, называемая items), которая содержит массив объектов.

Мне было интересно, как лучше всего добавить или удалить элемент.

Пример: удалить {:id => 2} из моего списка предметов и добавить к нему `{: id => 4}

Ответы [ 3 ]

1 голос
/ 22 марта 2019

В 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
0 голосов
/ 26 марта 2019

База на @ veridian-dynamic (спасибо за вашу помощь!) Вот что я сделал.

Модель:

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
0 голосов
/ 22 марта 2019

Первый: второй аргумент для сериализации должен быть классом объекта, который вы храните в поле. Вы должны иметь serialize :query_data, Hash вместо.

Кроме того, на самом деле не существует каких-либо передовых методов работы с сериализованными данными. Это действительно слишком сильно зависит от структуры ваших данных. Вы также можете спросить: «Каков наилучший способ добавить или удалить элемент из хэша?»

Но так как это хеш, вы должны помнить грязные атрибуты . Если бы вы сделали что-то вроде:

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.

Чтобы избежать этого, вы можете:

А) Убедитесь, что вы только когда-либо устанавливали my_model.query_data напрямую

B) Явно позвоните my_model.query_data_will_change! после изменения этого поля, чтобы оно было должным образом обновлено при сохранении.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...