rails / globalid

Identify app models with a URI

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Manually specifying GID classes

avokhmin opened this issue · comments

Sometimes might want to explicitly declare which class to use for a given class, instead of letting GID infer it.

For example:

class Post
  def self.gid_class
    Post.name
  end
end

class Post::Foo < Post
end

class Post::Bar < Post
end

and 

module URI
  class GID < Generic

    class << self

      def create(app, model, params = nil)
        model_name = model.try(:gid_class) || model.class.name
        build app: app, model_name: model_name, model_id: model.id, params: params
      end

    end
  end
end

The main usage case is GID + ActiveJob. For example, if update a type of record, all old Jobs will be failed, because they will not be able to find a record by old URL.

So, any ideas how to resolve it, or better to implement something like this?
PS: Solution by https://github.com/elabs/pundit/tree/v1.0.1#manually-specifying-policy-classes

Perhaps there's a better way to make GIobal ID work with STI models. Can you share your job class or something like it that demonstrates the type changes? 😁

For example:

class Item < ActiveRecord::Base
end

# Public: STI Item subclass corresponding to "text" item type.
class Item::Text < Item
end

# Public: STI Item subclass corresponding to "photo" item type.
class Item::Photo < Item
end

item = Item::Text.create(name: 'foo')
item.to_global_id.to_s
=> "gid://app/Item::Text/123"

UpdateBarJob.set(wait_until: 15.minutes.from_now).perform_later(item)

item = item.becomes(Item::Photo)
item.update(image_id: 'baz')
item.to_global_id.to_s
=> "gid://app/Item::Photo/123"

15 minutes later: UpdateBarJob - will do nothing because GID will not be able to find a record.

Thanks! This strikes me as very odd though. In my book the STI type is unlikely to change and the becomes feels like advanced usage to me. Therefore I worry about introducing this behavior, and recommend you try a custom app locator.

Custom app locators effectively let you change how a lookup is done. This could be a starting point:

class Item < ActiveRecord::Base
  def to_global_id(**params)
    super(params.merge(type: type))
  end
end

# config/initializers/global_id.rb

GlobalID::Locator.use :your_app do |gid|
  if gid.params[:type].present?
    gid.model_class.becomes(gid.params[:type]).find(gid.model_id)
  else
    gid.model_class.find(gid.model_id)
  end
end

Haven't tested or tried it at all, so have at it 😄

Thanks @kaspth for help!