Skip to content

has_many :through with polymorphic source and source_type not filtering by memberable_type (related to #205) #279

@apacosta

Description

@apacosta

Description

The fix in PR #206 (for #205) resolved the polymorphic type filtering when traversing from a polymorphic parent (e.g., Company → members → users). However, we're seeing the same issue in the reverse direction — traversing to a polymorphic target via source and source_type (e.g., User → members → projects).

Viewing User → Projects in Forest Admin joins members on memberable_id but omits WHERE memberable_type = 'Project', so records from all memberable types show up.

Environment

  • forest_admin_rails 1.24.x (also reproduced on 1.16.10)
  • Rails 7.x, Ruby 3.x, PostgreSQL

Reproduction

Schema

create_table "members" do |t|
  t.string "memberable_type", null: false
  t.bigint "memberable_id", null: false
  t.bigint "user_id", null: false
  t.timestamps
  t.index ["user_id", "memberable_type", "memberable_id"], unique: true
end

Models

class Member < ApplicationRecord
  belongs_to :user, inverse_of: :members
  belongs_to :memberable, polymorphic: true
end

class User < ApplicationRecord
  has_many :members, dependent: :destroy, inverse_of: :user

  # source_type filters by memberable_type — this is the broken direction
  has_many :projects,  through: :members, source: :memberable, source_type: "Project"
  has_many :teams,     through: :members, source: :memberable, source_type: "Team"
  has_many :companies, through: :members, source: :memberable, source_type: "Company"
end

class Project < ApplicationRecord
  has_many :members, as: :memberable, dependent: :destroy
  has_many :users, through: :members, source: :user  # ← this direction was fixed by #206
end

Data

user = User.create!(name: "Test User")
project = Project.create!(name: "My Project")
team = Team.create!(name: "My Team")

Member.create!(user: user, memberable: project)  # memberable_type = "Project"
Member.create!(user: user, memberable: team)      # memberable_type = "Team"

Expected

User → Projects tab shows 1 record (the project).

Rails generates the correct query:

SELECT "projects".* FROM "projects"
INNER JOIN "members" ON "members"."memberable_id" = "projects"."id"
                    AND "members"."memberable_type" = 'Project'
WHERE "members"."user_id" = 1

Actual

User → Projects tab shows incorrect results — the memberable_type = 'Project' condition is missing from the query, so records from all memberable types leak through.

Relationship to #205

#205 fixed the Polymorphic Parent → through → target direction (e.g., Company → members → users). This appears to be the inverse: Source → through → polymorphic target using source_type (e.g., User → members → projects). It looks like the source_type option on has_many :through isn't being picked up when Forest Admin builds the relationship query.

Happy to provide any additional details or help test a fix. Thanks for your time!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions