Search code examples
ruby-on-railsrubyrails-postgresqlpostgres-ext

Rails string array and PostgreSQL


I have a Rails model named Container with a column named products. It is a string array as supported by Postgres and the 'postgres_ext' gem.

The relevant portion of the GEMFILE is:

gem 'rails', '3.2.9'
gem 'pg'
gem 'postgres_ext'
gem 'activerecord-postgres-hstore', git: 'git://github.com/engageis/activerecord-postgres-hstore.git'

The relevant portion of the migration is:

 t.string :products, array: true

I am writing a public method in my Container model which adds products to this array. The method looks like this:

 attr_accessible :products

 def add_to_products(product)

  if products.blank? || products.size == 0 ## product array is either uninstantiated or blank
    products = [product.id]
  else  

    unless products.include? product.id
      products << product.id
    end
  end
end

These are the results in irb/console:

pry(main)> c = Container.first
=> #<Container id: "2765cc19-98f8-4e42-a1be-538788424ec7", name:....
pry(main)> p = Product.first
=> #<Product id: "319a25ae-87fe-4769-a9de-1a8e0db9e84f", name: ....
pry(main)> c.add_to_products(product)
pry(main)> c.products
=> nil
pry(main)> c.products= [] << "319a25ae-87fe-4769-a9de-1a8e0db9e84f"
pry(main)> c.products
=> ["319a25ae-87fe-4769-a9de-1a8e0db9e84f"]

I am scratching my head to figure out what's wrong in the add_to_products method. Can someone throw some light on this weird situation? Why is the value not being set when I pass it through this method?


Solution

  • This issue is actually arising out of the use of <<. Rails does not track in place modifications of attributes (see this issue). I outline in the usage notes that you want to avoid the << operator when using arrays, as rails will not see this change, it will actually cause issues with default values.

    This can also be seen by checking the products_changed? state. It will be false when you use <<.