Is it possible to create an attribute for a class that is an array? I tried reading this but I didn\'t get much out of it. I want to do something like this:
clas
Migration:
t.text :thearray, :default => [].to_yaml
In the model use serialize:
class MyModel
serialize :thearray, Array
...
end
As Marnen says in his answer, it would be good to know what kind of info you want to store in that array, a serialized attribute may not be the best option.
[Marten Veldthuis' warning] Be careful about changing the serialized array. If you change it directly like this:
my_model.thearray = [1,2,3]
That works fine, but if you do this:
my_model.thearray << 4
Then ActiveRecord won't detect that the value of thearray has changed. To tell AR about that change, you need to do this:
my_model.thearray_will_change!
my_model.thearray << 4
While you can use a serialized array as tokland suggested, this is rarely a good idea in a relational database. You have three superior alternatives:
has_many
relationship.composed_of
.has_many
s, you might want to investigate a DB that actually supports array fields. PostgreSQL does this (and array fields are supported in Rails 4 migrations), but you might want to use either a non-SQL database like MongoDB or object persistence such as MagLev is supposed to provide.If you can describe your use case -- that is, what data you've got in the array -- we can try to help figure out what the best course of action is.
Rails 6+
In Rails 6 (and to a lesser degree Rails 5) you can use the Attribute API which will allow you to create a typed, "virtual"/non-db backed column and even a default attribute. For example:
attribute :categories, :jsonb, array: true, default: [{ foo: 'bar' }, { fizz: 'buzz' }]
Which results in:
Example.new
#<Example:0x00007fccda7920f8> {
"id" => nil,
"created_at" => nil,
"updated_at" => nil,
"categories" => [
[0] {
"foo" => "bar"
},
[1] {
"fizz" => "buzz"
}
]
}
Note that you can use any type, but if it's not already available, you'll have to register it. In the above case, I use PostgeSQL
as the database and which has already registered :jsonb
as a type.
Create a model with a text field
> 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) ==========================================
edit your model to make the field serialized to an array
class Arches < ActiveRecord::Base
serialize :thearray,Array
end
test it out
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"]
If using Postgres, you can use its Array feature:
Migration:
add_column :model, :attribute, :text, array: true, default: []
And then just use it like an array:
model.attribute # []
model.attribute = ["d"] #["d"]
model.attribute << "e" # ["d", "e"]
This approach was mentioned by Marnen but I believe an example would be helpful here.