ruby-on-railsactiverecordhstoresti

Can I use ActiveRecord relationships with fields from an Hstore?


Can I tie a model to another through active record belongs_to using a field from an hstore hash? I'll elaborate:

I have a User model that gets subclassed via STI on one of its fields to many different other User models based on permissions:

class User < ActiveRecord::Base
  self.inheritance_column = :role
  #other definitions and validations
end

Here's one such submodel, the nightclub_boss model, meant for administrative users for my app:

class NightclubBoss < User
  belongs_to :nightclub     #the boss record has a nightclub_id
  has_one :rp_boss          #rp_boss should have a nightclub_boss_id
  has_one :captain          #captain should have a nightclub_boss_id
end

The idea here is to expand the User model with info such as:

-User hierarchy (which user reports to who; get a list of who is under who as needed through the ORM)
-User origin (which user belongs to whatever other models are in the app)

So what I came up with, to avoid having a sparse User table and also to avoid making lots of partial little SQL tables, is to create an hstore field on the User model called "hierarchy" and map it to different attributes on the User model which should get populated if and only if the User in question needs to store hierarchy information (that is, on a role-dependent-basis; nightclub_boss should not have the same hierarchy information as other models in my app):

class AddHstore < ActiveRecord::Migration
  def self.up
    enable_extension "hstore"
  end

  def self.down
    disable_extension "hstore"
  end
end

class AddHierarchyToUser < ActiveRecord::Migration
  def change
    add_column :users, :hierarchy, :hstore
    add_index :users, :hierarchy, using: :gin
  end
end

Ran

rake db:migrate

And then I added hstore_accesssor to my model:

Gemfile:

gem "hstore_accessor"

User model:

class User < ActiveRecord::Base
  self.inheritance_column = :role
  hstore_accessor :hierarchy, nightclub_id: :integer
  #other validations and definitions...
end

Everything is good so far, testing with hardcoded data:

[1] pry(main)> NightclubBoss.find(99)
  NightclubBoss Load (1.3ms)  SELECT  "users".* FROM "users" WHERE "users"."role" IN ('NightclubBoss') AND "users"."id" = $1 LIMIT 1  [["id", 99]]
=> #<NightclubBoss:0x000000070bbb00
 id: 99,
 #...all other fields...
 role: "NightclubBoss",
 hierarchy: {"nightclub_id"=>"1"}>

[2] pry(main)> NightclubBoss.find(99).nightclub_id
  NightclubBoss Load (0.7ms)  SELECT  "users".* FROM "users" WHERE "users"."role" IN ('NightclubBoss') AND "users"."id" = $1 LIMIT 1  [["id", 99]]
=> 1

So you'd expect rails to pull the corresponding Nightclub.find(1) that's bound to this model when calling "NightclubBoss.nightclub", right? Well, it doesn't happen:

[3] pry(main)> NightclubBoss.find(99).nightclub
  NightclubBoss Load (0.7ms)  SELECT  "users".* FROM "users" WHERE "users"."role" IN ('NightclubBoss') AND "users"."id" = $1 LIMIT 1  [["id", 99]]
=> nil

I've tried all sorts of things to try to figure this out and I haven't found the answer yet, is there anyone who can help?

As a workaround I realize I can do:

Nightclub.find(NightclubBoss.find(99).nightclub_id)

And I get the query just fine. But I think this can be improved, you'd expect to be able to do NightclubBoss.find(99).nightclub

I think this may also be a very bad practice to follow. If there's a better way to model the kind of information that I need, please let me know, I'll appreciate your advice. Thanks!


Solution

  • I found overnight that Postgres has a similar data type called Jsonb, which also does a similar thing to hstore in the sense that you store a hash in a field in the relational database.

    Apparently it is not currently possible due to a limitation in ActiveRecord to make this match. It constrains matches to relational database fields only:

    PostgreSQL jsonb field in ActiveRecord belongs_to association

    Personally, I'm satisfied with that answer so I'll close this thread if nobody has more info, and I'll modify my schema to not depend on hash fields.

    Wonder if support could be patched?