За допомогою Rails серіалізуйте для збереження хешу до бази даних


135

Я намагаюся зберегти ідентифікатори хеш-картографії на ряді спроб у моїй програмі rails. Моя міграція до бази даних для розміщення цього нового стовпця:

class AddMultiWrongToUser < ActiveRecord::Migration
  def self.up
    add_column :users, :multi_wrong, :string
  end

  def self.down
    remove_column :users, :multi_wrong
  end
end

У своїй моделі я:

class User < ActiveRecord::Base 
 serialize :multi_wrong, Hash
end

Але коли я використовую консоль рейки для перевірки цього, виконуючи такі дії:

user = User.create()
user.multi_wrong = {"test"=>"123"}
user.save

Вихід помилковий. Що тут не так?


4
Чи є щось у користувальницьких помилок після спроби зберегти запис?
Martijn

1
Надалі ви можете скористатися методом вибуху (збережіть!), Щоб зібрати виняток та відобразити повідомлення про помилку.
лейшман

Найкращою відповіддю зараз користується стовпець JSON stackoverflow.com/a/21397522/1536309
Блер Андерсон

Відповіді:


174

Тип стовпця неправильний. Ви повинні використовувати Text замість String. Тому ваша міграція повинна бути:

 def self.up
   add_column :users, :multi_wrong, :text
 end

Тоді Rails належним чином перетворить його в YAML для вас (і виконає належну серіалізацію). Поля рядків мають обмежений розмір і матимуть лише особливо малі значення.


1
@ BenjaminTan, що є причиною цього, чому я не можу зберігати хеш у "рядкових" типах даних.
Lohith MV

8
Тому що в базі даних String має фіксовану довжину 255 (я думаю). Але якби ви серіалізували хеш порівняльного розміру, це легко перевищить довжину. Той самий випадок і для масивів. Текст передбачає набагато більшу довжину.
Бенджамін Тан Вей Хао

72

ОНОВЛЕНО:

Точна реалізація буде залежати від вашої бази даних, але PostgreSQL тепер jsonі jsonbстовпці , які можуть спочатку зберігати дані хеш / об'єкт і дозволяють запит до JSON з ActiveRecord !

змінити міграцію, і ти закінчиш.

class Migration0001
  def change
    add_column :users, :location_data, :json, default: {}
  end
end

ОРИГІНАЛ:

Детальніше: rails docs && apidock

Переконайтеся, що ваш стовпець є, :textа ні:string

Міграція:

$ rails g migration add_location_data_to_users location_data:text

має створити:

class Migration0001
  def change
    add_column :users, :location_data, :text
  end
end

Ваш клас виглядатиме так:

class User < ActiveRecord::Base
  serialize :location_data
end

Доступні дії:

b = User.new
b.location_data = [1,2,{foot: 3, bart: "noodles"}]
b.save

Більше дивовижних ?!

використовувати postgresql hstore

class AddHstore < ActiveRecord::Migration  
  def up
    enable_extension :hstore
  end

  def down
    disable_extension :hstore
  end
end 

class Migration0001
  def change
    add_column :users, :location_data, :hstore
  end
end

За допомогою hstore ви можете встановити атрибути на серіалізоване поле

class User < ActiveRecord::Base  
  # setup hstore
  store_accessor :location_data, :city, :state
end

2
Воістину приголомшливий! Дякую!
Олександр Горг

18

Rails 4 має нову функцію під назвою Store , тому ви можете легко використовувати її для вирішення вашої проблеми. Ви можете визначити для нього аксесуар, і рекомендується оголосити стовпець бази даних, який використовується для серіалізованого магазину, як текст, щоб було багато місця. Оригінальний приклад:

class User < ActiveRecord::Base
  store :settings, accessors: [ :color, :homepage ], coder: JSON
end

u = User.new(color: 'black', homepage: '37signals.com')
u.color                          # Accessor stored attribute
u.settings[:country] = 'Denmark' # Any attribute, even if not specified with an accessor

# There is no difference between strings and symbols for accessing custom attributes
u.settings[:country]  # => 'Denmark'
u.settings['country'] # => 'Denmark'
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.