Skip to content

Bug: Arel.sql in update_all becomes a literal value inside MultiTenant.with #278

@pkmuldoon

Description

@pkmuldoon

Affected versions / refs

  • Gem: activerecord-multi-tenant
  • Commit tested for Rails 7.2 support: 0ac43aa
  • Rails 8 work is also affected (see Support rails 8.0.0)
  • Note: latest release (2.4.0) still declares support only up to Rails 7.0, so people may be pinning to these commits.

Summary

When calling relation.update_all with an assignment that uses Arel.sql(column_name) to reference another column, it works correctly outside a tenant block.

Inside MultiTenant.with(...), the Arel.sql value is coerced to a literal (e.g. 1 for booleans), so every row gets the same constant instead of the column value.

Expected behavior

Arel.sql("active") should be treated as a SQL expression and compiled as:

UPDATE "users" SET "user_valid" = "users"."active", "active" = ?  [["active", 0]]
WHERE "users"."practice_id" = 1;

Actual behavior

Within MultiTenant.with, the assignment is type-cast/quoted as a literal:

UPDATE "users"
SET "user_valid" = 1, "active" = 0
WHERE "users"."id" IN (
  SELECT "users"."id" FROM "users" WHERE "users"."practice_id" = 1
) AND "users"."practice_id" = 1;

Reproduction

Schema

# users: id, practice_id:bigint, user_valid:boolean, active:boolean, timestamps
class User < ApplicationRecord
  multi_tenant :practice
end

Repo script:

users = User.all

# Baseline: OUTSIDE tenant
users.update_all(user_valid: Arel.sql("active"), active: false)
# => UPDATE "users" SET "user_valid" = (active), "active" = 0

practice = Practice.first
MultiTenant.with(practice) do
  users = User.all
  users.update_all(user_valid: Arel.sql("active"), active: false)
end
# => UPDATE "users" SET "user_valid" = 1, "active" = 0 ...

Why this likely happens

Active Record normally treats Arel::Nodes::SqlLiteral as “don’t quote/type-cast this.”
Inside the gem’s tenant scoping path, update_all seems to flow through a code path that type-casts the update hash, converting the Arel.sql(...) node into a bound literal.

Environment

  • Rails: 7.2.x (also visible with Rails 8 prerelease)
  • DB: PostgreSQL (likely adapter-agnostic)
  • activerecord-multi-tenant: GitHub ref 0ac43aa

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