Search code examples
ruby-on-railsrubyactiverecordhstore

Why ActiveRecord::Store.store_acessor doesn't reflect on the resulting SQL when querying


Consider this class:

class UsersMigration < ActiveRecord::Migration[5.2]
  def change
    create_table(:users) do |t|
      t.hstore  :settings
    end
  end
end

class User < ActiveRecord::Base
  store_accessor :settings, :privileges, :colors
end

When doing this Query:

User.where(privileges: 'Admin')

It results in this error: ActiveRecord::StatementInvalid (PG::UndefinedColumn: ERROR: column users.privileges does not exist) and is right because the column is actually settings

In order to make the query we have to do this:

User.where("settings->'privileges' = 'Admin'")

If the model already has explicit serialization to an hstore column why the first query doesn't result in the following SQL:

SELECT  "user".* FROM "users" WHERE (settings->'privileges' = 'Admin')

Solution

  • ActiveRecord is not built to actually care about the contents of hstore, json or array columns. AR is built around the relational model with tables and columns. Columns on the table correspond to attributes in the model.

    Hstore, json and array types are relatively new database features and not definitely not polyglot. The implementation varies per database. In ActiveRecord the support for these columns is actually provided by the database driver and not the framework itself.

    store_accessor just creates a getter/setter and sets up dirty tracking for the attribute in the model. It does not "explicitly tell" AR that specific keys are present in a hstore column - remember AR does not care about the contents of a hstore column.

    In fact I would say that if your are using it this way its a very telling sign that you have fallen victim to the JSON/hstore anti-pattern.