rails / globalid

Identify app models with a URI

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Single app with multiple databases?

opened this issue · comments

My app switches to a different database based on subdomain using:

  Mongoid.override_database("timeline_#{subdomain}_production")

So when the globalid is generated, it looks something like:

gid://timeline/User/55230a4278616e6fbc010000

This does not help because this ID is meaningless without knowing what the subdomain or the database name is. I am looking for something like:

gid://timeline/database_name/User/55230a4278616e6fbc010000

So that ActiveJob or whatever is responsible for finding the record knows where to actually look for it.

Any ideas/suggestions?

P.S. this is related to this issue: rails/activejob#112

one option you have is to pass the database name as GID parameter. In your model:

class User
  def to_global_id(options = {})
    options[:database] = current_database
    super(options)
  end
end

and in an initializer setup a locator for your applications

GlobalID::Locator.use :template do |gid|
  Mongoid.override_database gid.params[:database]
  gid.model_class.find(gid.model_id)
end

What @cristianbica said is the right direction to go in. Also we try to keep the issue tracker for bugs only. Please try Stack Overflow for help where a wider community can help you. Thanks 😁

Thank you, this worked beautifully:

# in config/initializers/global_id.rb
GlobalID::Locator.use :timeline do |gid|
  database_switcher = DatabaseSwitcher.new
  database_switcher.switch_to gid.params[:timeline_name]
  gid.model_class.find(gid.model_id)
end
# in my model
    include GlobalID::Identification # For activejob (delayed emailing, etc)

    def to_global_id(options = {})
      options[:timeline_name] = timeline_name
      super(options)
    end

I had an issue where ActionText::Attachable introduces the use of:

def attachable_sgid
  to_sgid(expires_in: nil, for: LOCATOR_NAME).to_s
end

I've already overridden to_global_id with something like this:

module DomainHashGlobalId
  extend ActiveSupport::Concern

  def to_global_id(options = {})
    options[:domain_hash] = SiteSetting[:entity].domain_hash
    super(options)
  end
end
ActiveSupport.on_load :active_storage_record do
  include DomainHashGlobalId
end

Unfortunately to_signed_global_id (to_sgid) doesn't seem to use to_global_id to get its non-secure value and I have to override it also in my concern with:

  def to_signed_global_id(options = {})
    options[:domain_hash] = SiteSetting[:entity].domain_hash
    super(options)
  end

I've had a pretty thorough look through the code and can't see why these two methods would behave differently since the Signed version of the class inherits of the standard GlobalID class. So strange :)

Actually, the more I look at it, the two methods are first class and one doesn't depend on the other. Makes overriding them a bit more nuanced! :)

Turns out one needs to also redefine the aliases for them to point to our new methods:

module DomainHashGlobalId
  extend ActiveSupport::Concern

  def to_global_id(options = {})
    options[:domain_hash] = SiteSetting[:entity].domain_hash
    super(options)
  end
  alias to_gid to_global_id

  def to_signed_global_id(options = {})
    options[:domain_hash] = SiteSetting[:entity].domain_hash
    super(options)
  end
  alias to_sgid to_signed_global_id
end

ActionText::Attachable uses to_sgid specifically:

https://github.com/rails/rails/blob/9ab33753b6bab1809fc73d35b98a5c1d0c96ba1b/actiontext/lib/action_text/attachable.rb#L43