Skip to content
This repository has been archived by the owner on Mar 30, 2022. It is now read-only.

Polymorphic join query returns wrong result #390

Open
dariusf opened this issue Jul 26, 2015 · 0 comments
Open

Polymorphic join query returns wrong result #390

dariusf opened this issue Jul 26, 2015 · 0 comments

Comments

@dariusf
Copy link

dariusf commented Jul 26, 2015

A bit of context:

Our system tracks users' achievements. These may have other achievements as conditions (to track prerequisites). A resource which has_many conditions is called a conditional.

There are several different types of condition and conditional, so the associations are polymorphic in both directions (using active_record-acts_as). This is managed via the conditions table.

# Schema
create_table "achievements", force: :cascade do |t|
  t.string "title"
end

create_table "conditions", force: :cascade do |t|
  t.integer "actable_id"
  t.string  "actable_type"
  t.integer "conditional_id"
  t.string  "conditional_type"
end

create_table "achievement_conditions", force: :cascade do |t|
  t.integer "achievement_id"
end
# Models
class Achievement < ActiveRecord::Base
  has_many :conditions, -> { includes :actable },
           class_name: Condition.name, as: :conditional, dependent: :destroy
end

class Condition < ActiveRecord::Base
  actable
  belongs_to :conditional, polymorphic: true
end

class AchievementCondition < ActiveRecord::Base
  acts_as :condition, class_name: Condition.name
  belongs_to :achievement, class_name: Achievement.name

  default_scope { includes(:achievement) }
end

With this setup, if achievement 2 has achievement 1 as a condition, Achievement.find(2).conditions.first.actable.achievement would return achievement 1.

The bug happens with the following query, which we use to find all achievemnt conditions of a given achievement (2 in this case):

AchievementCondition.joins { condition.conditional(Achievement) }.where { condition.conditional.id == 2 }.map(&:achievement).first

It should return achievement 1, but returns achievement 2. The following fixes the problem, however reloading every object is prohibitively expensive:

a = AchievementCondition.joins { condition.conditional(Achievement) }.where { condition.conditional.id == 2 }.first
a.reload.achievement # correct result

Would anyone have insight into why this happens and if it can be fixed?

There's a minimal Rails project here with the models and schema set up. The problem is also described in Coursemology/coursemology2#443.

Apologies for the exposition. This is an obscure case and I wasn't sure how to frame it more briefly, or come up with a smaller example.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant