Атрибут массива для модели Ruby - PullRequest
28 голосов
/ 11 ноября 2011

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

class CreateArches < ActiveRecord::Migration
  def change
    create_table :arches do |t|
      t.string :name
      t.array :thearray
      t.timestamps
    end
  end
end

, чтобы при вызове .thearray для экземпляра Arch я получал массив, в который я мог бы добавлять новые элементы.

ruby-1.9.2-p290 :006 > arc = Arch.new
ruby-1.9.2-p290 :007 > arc.thearray
 => [] 

Ответы [ 4 ]

48 голосов
/ 11 ноября 2011

Создать модель с текстовым полем

> rails g model Arches thearray:text
  invoke  active_record
  create    db/migrate/20111111174052_create_arches.rb
  create    app/models/arches.rb
  invoke    test_unit
  create      test/unit/arches_test.rb
  create      test/fixtures/arches.yml
> rake db:migrate
==  CreateArches: migrating ===================================================
-- create_table(:arches)
   -> 0.0012s
==  CreateArches: migrated (0.0013s) ==========================================

отредактируйте вашу модель, чтобы поле сериализовалось в массив

class Arches < ActiveRecord::Base
  serialize :thearray,Array
end

проверить это

ruby-1.8.7-p299 :001 > a = Arches.new
 => #<Arches id: nil, thearray: [], created_at: nil, updated_at: nil> 
ruby-1.8.7-p299 :002 > a.thearray
 => [] 
ruby-1.8.7-p299 :003 > a.thearray << "test"
 => ["test"] 
10 голосов
/ 11 ноября 2011

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

  • Если массив содержит объекты сущностей, он, вероятно, лучше смоделируется как отношение has_many.
  • Если массив на самом деле является просто массивом значений, таких каккак числа, тогда вы можете поместить каждое значение в отдельное поле и использовать composed_of.
  • Если вы собираетесь использовать множество значений массива, которые не являются has_many s, выможет захотеть исследовать БД, которая на самом деле поддерживает поля массива.PostgreSQL делает это (и поля массива поддерживаются в переходах с Rails 4), но вы можете использовать базу данных, отличную от SQL, например MongoDB, или постоянство объектов, такое как MagLev , как предполагается, обеспечивает.

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

6 голосов
/ 11 ноября 2011

Миграция:

t.text :thearray, :default => [].to_yaml

В модели используется serialize :

class MyModel
  serialize :thearray, Array
  ...
end

Как говорит Марнен в своем ответе, было бы хорошо узнать, какого родаЕсли вы хотите сохранить информацию в этом массиве, сериализованный атрибут может оказаться не лучшим вариантом.

[Предупреждение Мартена Вельдтюса] Будьте осторожны при изменении сериализованного массива.Если вы измените его напрямую следующим образом:

my_model.thearray = [1,2,3]

Это работает нормально, но если вы сделаете это:

my_model.thearray << 4

, тогда ActiveRecord не обнаружит, что значение thearray изменилось.Чтобы сообщить AR об этом изменении, вам нужно сделать следующее:

my_model.thearray_will_change!
my_model.thearray << 4
0 голосов
/ 29 января 2019

Если вы используете Postgres, вы можете использовать его Массив :

Миграция:

add_column :model, :attribute, :text, array: true, default: []

А затем просто используйте его как массив:

model.attribute # []
model.attribute = ["d"] #["d"]
model.attribute << "e" # ["d", "e"]

Этот подход был упомянут Марненом, но я думаю, что пример будет полезен здесь.

...