Array Attribute for Ruby Model

前端 未结 5 2110
情书的邮戳
情书的邮戳 2021-01-30 14:19

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         


        
相关标签:
5条回答
  • 2021-01-30 14:28

    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
    
    0 讨论(0)
  • 2021-01-30 14:38

    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:

    • If the array holds entity objects, it's probably better modeled as a has_many relationship.
    • If the array is really just an array of values such as numbers, then you might want to put each value in a separate field and use composed_of.
    • If you're going to be using a lot of array values that aren't has_manys, 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.

    0 讨论(0)
  • 2021-01-30 14:41

    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.

    0 讨论(0)
  • 2021-01-30 14:46

    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"] 
    
    0 讨论(0)
  • 2021-01-30 14:54

    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.

    0 讨论(0)
提交回复
热议问题