active-hash / active_hash

A readonly ActiveRecord-esque base class that lets you use a hash, a Yaml file or a custom file as the datasource
MIT License
1.2k stars 179 forks source link

The has_many :through Association does not get record #239

Closed ghost closed 9 months ago

ghost commented 2 years ago

Steps to reproduce

Run below code.

# frozen_string_literal: true

require 'bundler/inline'

gemfile(true) do
  source 'https://rubygems.org'

  git_source(:github) { |repo| "https://github.com/#{repo}.git" }

  gem 'activerecord', '~> 6.1.6'
  gem 'active_hash', '~> 3.2.1'

  gem 'sqlite3'
end

require 'active_record'
require 'active_hash'

require 'minitest/autorun'
require 'logger'

ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
ActiveRecord::Base.logger = Logger.new(STDOUT)

ActiveRecord::Schema.define do
  create_table :appointments, force: true do |t|
    t.references :physician
    t.references :patient
  end

  create_table :patients, force: true do |t|
  end
end

class Physician < ActiveHash::Base
  include ActiveHash::Associations

  has_many :appointments
  has_many :patients, through: :appointments

  self.data = [
    {:id => 1, :name => "ikeda"},
    {:id => 2, :name => "sato"}
  ]
end

class Appointment < ActiveRecord::Base
  extend ActiveHash::Associations::ActiveRecordExtensions

  belongs_to :physician
  belongs_to :patient
end

class Patient < ActiveRecord::Base
  extend ActiveHash::Associations::ActiveRecordExtensions

  has_many :appointments
  has_many :physicians, through: :appointments
end

class TestAssociation < Minitest::Test
  def test_association
    physician = Physician.first
    patient = Patient.create!
    Appointment.create!(physician: physician, patient: patient)

    assert_equal [physician], patient.appointments.flat_map(&:physician) # works
    assert_equal [physician], patient.physicians # error
  end
end

Expected behavior

The script above should produce no errors, and get physician.

Actual behavior

NoMethodError: undefined method `relation_delegate_class' for Physician:Class

System configuration

Ruby version: 2.7.4 ActiveHash version: 3.1.0

updated: Ruby version: 3.0.6 ActiveHash version: 3.2.1

updated by @kbrock to bring up to current version of ruby, rails, and active hash

NYDrewReynolds commented 2 years ago

@taki Have you found any workaround for this yet? Running into this issue as well

ghost commented 2 years ago

@NYDrewReynolds Unfortunately, I have not yet.

kbrock commented 9 months ago

Edited the question to bring it to current versions of the code base.

Probably easier to debug if you comment out gem "active_hash" and just run with ruby -Ilib reproducer.rb.


It looks like the :through association is not properly retuning this class because it is not an ActiveRecord::Base.

At first I thought this was related to the 7.x code that prevents you from creating an association with a non AR model. But this issue has been here since rails 5.2 (maybe before) so it is unrelated.

Tried adding a few methods to quickly get through the error, but it looks pretty deep. Anyone have any thoughts on this?

flavorjones commented 9 months ago

I think this issue is similar to the one fixed in #272 / #267. Looking.

kbrock commented 9 months ago

Something was so elegant about the compute_class code fix.

agree that we want to avoid monkey patches... just sayin'

ghost commented 9 months ago

Thank you very much.