Skip to content

as: option in associations overrides expected struct class #701

@aaronmallen

Description

@aaronmallen

Context

When defining a belongs_to association with an as: option, the struct class returned by the association method is determined by the as: value rather than the target relation's struct class.

Current Behavior

class AuthAccessGrants < DB::Relation
  schema :auth_access_grants, infer: true do
    associations do
      belongs_to :oauth_client, foreign_key: :client_id, as: :client
    end
  end
end

class AuthClient < DB::Struct
  def active?
    active == true
  end
end

Expected: oauth_access_grant.client returns an AuthClient struct

Actual: oauth_access_grant.client returns a Client struct

This results in:

oauth_access_grant.client.active? #=> NoMethodError

Current Workaround

The only way to access custom methods defined on AuthClient is to create an empty wrapper class:

class Client < AuthClient
end

Discussion

The as: option behaves consistently with other ROM features (e.g., posts.as(:article).to_a returns Article structs), so this is technically expected behavior. However, when used in associations, this creates a surprising experience where:

  1. The association name (client) doesn't match the actual target (oauth_client)
  2. The returned struct class (Client) doesn't match either the association name or the target relation's struct class
  3. Custom methods defined on the expected struct class are not available

Potential Solutions

  • Add a separate option (e.g., as: for the method name, struct: for the struct class)
  • Allow as: to accept both a symbol and a hash (e.g., as: { method: :client, struct: :oauth_client })
  • Document this behavior more clearly as a caveat of using as: in associations

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions