Quantcast
Channel: Active questions tagged ruby - Stack Overflow
Viewing all articles
Browse latest Browse all 4616

Can't find the cause of a has many through association error

$
0
0

I'm building a token provisioning API that enforces quotas. When I try to create a Token, I keep getting the following error, and I cannot figure out why:

ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection: Cannot modify association 'Token#limits' because the source reflection class 'Limit'is associated to 'Resource' via :has_many.

I have distilled this down to an MVP Rails 7.1.3.4 app on Ruby 3.3.3.

# db/schema.rbActiveRecord::Schema[7.1].define(version: 2024_06_28_175444) do  create_table "limits", force: :cascade do |t|    t.integer "plan_id", null: false    t.integer "resource_id", null: false    t.integer "budget", null: false    t.index ["plan_id"], name: "index_limits_on_plan_id"    t.index ["resource_id"], name: "index_limits_on_resource_id"  end  create_table "plans", force: :cascade do |t|    t.string "name", null: false  end  create_table "resources", force: :cascade do |t|    t.string "name", null: false  end  create_table "subscriptions", force: :cascade do |t|    t.integer "plan_id", null: false    t.index ["plan_id"], name: "index_subscriptions_on_plan_id"  end  create_table "tokens", force: :cascade do |t|    t.integer "subscription_id", null: false    t.integer "resource_id", null: false    t.index ["resource_id"], name: "index_tokens_on_resource_id"    t.index ["subscription_id"], name: "index_tokens_on_subscription_id"  endend
class Plan < ApplicationRecord; endclass Resource < ApplicationRecord  has_many :limitsendclass Limit < ApplicationRecord  belongs_to :plan  belongs_to :resourceendclass Subscription < ApplicationRecord  belongs_to :planendclass Token < ApplicationRecord  belongs_to :subscription  belongs_to :resource  has_one :plan, through: :subscription  has_many :limits, ->(token) { where(plan: token.plan) }, through: :resource  validate :limits_apply  private  def limits_apply    errors.add(:limits, "no limits apply to this token") unless limits.length > 0  endend
# tests/token_test.rbrequire 'test_helper'class TokenTest < ActiveSupport::TestCase  setup do    @resource = Resource.create name: 'Widget'    @plan = Plan.create name: 'Bronze'    @subscription = Subscription.create plan: @plan    @limit = Limit.create plan: @plan, resource: @resource, budget: 5  end  test '.create!' do    assert_nothing_raised do      Token.create!(resource: @resource, subscription: @subscription)    end  endend
$ rails testRunning 1 tests in a single process (parallelization threshold is 50)Run options: --seed 49750# Running:EError:TokenTest#test_.create!:ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection: Cannot modify association 'Token#limits' because the source reflection class 'Limit'is associated to 'Resource' via :has_many.    test/models/token_test.rb:13:in `block (2 levels) in <class:TokenTest>'    test/models/token_test.rb:12:in `block in <class:TokenTest>'bin/rails test test/models/token_test.rb:11Finished in 0.043282s, 23.1043 runs/s, 0.0000 assertions/s.1 runs, 0 assertions, 0 failures, 1 errors, 0 skips

This issue arises only when the :quotas relation on the Token model is loaded before save. If I change the :quotas relation to a plain instance method, the issue disappears:

class Token < ApplicationRecord  # ...  # has_many :limits, ->(token) { where(plan: token.plan) }, through: :resource  def limits    resource.limits.where(plan: plan)  end  # ...end
$ rails testRunning 1 tests in a single process (parallelization threshold is 50)Run options: --seed 56588# Running:.Finished in 0.049800s, 20.0803 runs/s, 20.0803 assertions/s.1 runs, 1 assertions, 0 failures, 0 errors, 0 skips

What am I missing in regards to my association definitions to make this work?


Viewing all articles
Browse latest Browse all 4616

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>