Skip to content

[WIP] [OpenAPI]: Fix blueprinter registry key normalization#340

Draft
Abishekcs wants to merge 3 commits into
rage-rb:mainfrom
Abishekcs:fix/blueprinter-registry-key-normalization
Draft

[WIP] [OpenAPI]: Fix blueprinter registry key normalization#340
Abishekcs wants to merge 3 commits into
rage-rb:mainfrom
Abishekcs:fix/blueprinter-registry-key-normalization

Conversation

@Abishekcs

@Abishekcs Abishekcs commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

WIP

What this PR does ?

Fix circular reference handling when blueprints association are parsed under different views This PR fixes a bug in how the OpenAPI schema registry handles circular references between Blueprinter classes. Before this, the schema registry only used the class name as the key. So a blueprint referenced under one view could get its registry entry overwritten (or its circular-reference placeholder silently vanished) by a write for the same class under a different view.

For example:

class ProjectBlueprint < Blueprinter::Base
  fields :name
  view :normal do
    association :users, blueprint: UserBlueprint
  end
end

class UserBlueprint < Blueprinter::Base
  fields :email
  association :projects, blueprint: ProjectBlueprint
  view :extended do
    association :all_projects, blueprint: ProjectBlueprint, view: :normal
  end
end

Parsing UserBlueprint(view: :extended) reaches ProjectBlueprint twice: once via projects (default view, no association back to UserBlueprint), and once via all_projects (view: :normal, which does associate back to UserBlueprint, closing the circular reference). Previously both writes shared the registry key ProjectBlueprint, so the placeholder written for the circular view could be overwritten by the unrelated write from the other view.

Now the key includes the view, defaulting to :default when none is given. So an association declared with view: :something actually builds and registers against that view instead of always falling back to :default.

…ith view options

Before this, the schema registry only used the class name as the key.So if the same blueprint showed up twice with different views (once as a plain resource, once as an association with view: :extended), both wrote to the same spot and one would overwrite the other.

For example:

  class ProjectBlueprint < Blueprinter::Base
    fields :name
    view :normal do
      association :users, blueprint: UserBlueprint
    end
  end

  class UserBlueprint < Blueprinter::Base
    fields :email
    association :projects, blueprint: ProjectBlueprint
    view :extended do
      association :all_projects, blueprint: ProjectBlueprint, view: :normal
    end
  end

Parsing UserBlueprint(view: :extended) reaches ProjectBlueprint twice: once via "projects" (default view, no association back to UserBlueprint), and once via "all_projects" (view: :normal, which does associate back to UserBlueprint, closing the circular reference). Previously both writes shared the registry key "ProjectBlueprint", so the placeholder written for the circular view could be overwritten by the unrelated write from the other view.

Now the key includes the view, defaulting to :default when none is given. Also passes the view options down into build_schema and extract_associations, so an association declared with view: :something actually builds and registers against that view instead of always falling back to :default.
@Abishekcs

Copy link
Copy Markdown
Contributor Author

This PR adds support for associations that explicitly specify a view: option for their blueprint. It also adds serializer_options to the schema registry without this, if two associations reference the same blueprint but only one of them specifies a view, they would collide in the registry under the same key, even though they should resolve to different schemas.

@Abishekcs Abishekcs changed the title [OpenAPI]: Fix blueprinter registry key normalization [WIP] [OpenAPI]: Fix blueprinter registry key normalization Jun 30, 2026
@Abishekcs

Copy link
Copy Markdown
Contributor Author

@rsamoilov should we support explicitly specifying a view: for a blueprint association? Right now it always builds against the target's default view, even if view: is passed.

   association :all_projects, blueprint: ProjectBlueprint, view: :normal

@Abishekcs

Copy link
Copy Markdown
Contributor Author

In case we decide to support it. Then we have to handle the case where in circular association both the association have view explicitly mentioned.

Example: # @response UserBlueprint(view: :extended)

class ProjectBlueprint < Blueprinter::Base
  fields :name
  view :normal do
    association :users, blueprint: UserBlueprint, view: :extra_information
  end
end

class UserBlueprint < Blueprinter::Base
  fields :email
  view :extended do
    association :all_projects, blueprint: ProjectBlueprint, view: :normal
  end
  
  view :extra_information do
    field :address
  end
end

@rsamoilov

Copy link
Copy Markdown
Member

@rsamoilov should we support explicitly specifying a view: for a blueprint association? Right now it always builds against the target's default view, even if view: is passed.

   association :all_projects, blueprint: ProjectBlueprint, view: :normal

I'd say yes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants