Support for alias_attribute with SQL aliasing?

I have an application where I have a lot of JSON-backed columns. I do a lot of this:

Leed::Match.select("data->'test_guid' as guid, data->'public_display_name' as name, last_synced_at")

Fine, whatever. I can DRY this up with a monkeypatch to QueryMethods and some scopes:

module ActiveRecord
  module QueryMethods
    def and_select(*fields)
      if(!select_values.any?)
        fields.unshift(arel_table[Arel.star])
      end
      select(*fields)
    end
  end
end
scope :with_guid, -> { and_select(Arel.sql("data->'test_guid'").as("guid")) }
scope :with_name, -> { and_select(Arel.sql("data->'public_display_name'").as("name")) }

And then call:

Leed::Match.with_guid.with_name.and_select(:last_synced_at)

Okay, still “fine”, but, we have alias_attribute from ActiveModel, where I can normally:

class Post < ApplicationRecord
  alias_attribute :subject, :title 
end

And ActiveRecord::QueryMethods respects those: rails/query_methods.rb at 7-0-stable · rails/rails · GitHub, rails/query_methods.rb at 7-0-stable · rails/rails · GitHub

Because of how they’re generated: rails/attribute_methods.rb at 7-0-stable · rails/rails · GitHub

However, because of how they’re generated, I obviously can’t:

alias_attribute :guid, Arel.sql("data->'test_guid'")

:frowning:

Would core accept a PR which, effectively (one way or another) allows for this? I don’t know if I’d want to match those methods, or if I’d want a completely separate:

class Leed::Match < ApplicationRecord
  as_alias_attribute :guid, Arel.sql("data->'test_guid'")
  as_alias_attribute :name, Arel.sql("data->'public_display_name'")
end

Whatever it is, I’d like to be able to:

Leed::Match.select(:guid)

and,

Leed::Match.where(guid: "1234")

:smiley:

At least, I think I do want to?

Whether or not it’s baked into alias_attribute — I don’t know. But I’ve always been surprised we don’t have a way to better handle SQL aliasing in ActiveRecord. Maybe I’ve missed something for the last 10 years. I don’t know.

2 Likes

Strong like. I had been thinking about something similar. My only call-out is that this should be integrated with ActiveRecord::Store.

+1 on wanting to see this happen! Can help out as well.

There are a couple obscure sample databases that I use for testing out The Brick gem that utilise column names which collide with Ruby method names – stuff such as class. I haven’t found any way to properly alias these, and want for the gem to be able to handle absolutely ANY database that comes along.

(The idea behind this gem is that it auto-creates models in RAM based on any source database – reads the INFORMATION_SCHEMA views to determine columns and foreign keys, and then builds proper has_many / belongs_to / any composite keys / etc.)