hzamani / acts_as_relation

Multi table Inheritance for rails
http://hzamani.github.com/acts_as_relation/
MIT License
180 stars 58 forks source link

Rails 3.0.9 method_missing endless loop? #2

Closed mepatterson closed 12 years ago

mepatterson commented 13 years ago

Given this example:

(assuming Product has a market_id and Pen has a color)

class Product < ActiveRecord::Base
  belongs_to :market  
end

class Pen < ActiveRecord::Base
  acts_as :product

  scope :by_market, lambda{|market_id|
    joins("JOIN products ON products.product_id = pens.id").where(["products.market_id = ?", market_id])
  }
end

if I run this in console:

  Pen.by_market(1).first.color

I get a 'stack level too deep' error.

If I do...

  p = Pen.by_market(1)
  p.color

... it works fine. But obviously we'd want the normal behavior to work as well.

As far as I can tell, it's getting stuck in an endless method_missing loop. Something to do with alias_method_chain's deprecation in Rails 3?

Any help would be much appreciated...

mepatterson commented 13 years ago

Ok, I sort of pinned this down. There's some sort of weird thing happening when it hits method_messing at the point where it's trying to do product.send(method). so i replaced it with

#{name}.classify.constantize.where("#{name}_id" => self.attributes['id']).send(method, *arg, &block)

which feels a bit hackish, but suddenly makes everything work as expected. haven't identified any real problems yet...

hzamani commented 13 years ago

Sorry for late reply. I don't got any problem (no 'stack level too deep' error) for this example! And I can't understand how respond_to?(:#{name}) ? #{name}.send(method, *arg, &block) : raise may solve any problem, can you explain more?

hzamani commented 13 years ago

closing was a mistake!

mepatterson commented 13 years ago

Yeah, so the method_missing gets stuck in an endless loop trying to call 'id' for 'product' object, which apparently hasn't been instantiated yet. My guess is that this is a Rails 3 thing (Rails 3.0.9 specifically for my tests), maybe something to do with performance changes around lazy loading? If you actually instantiate the 'product' first, via any sort of basic find(), everything is good, but if you try to do a chained scope:

Pen.by_market(1).first.color

... it gets stuck in that loop and dies with a stack too deep error. Adding the respond_to? seems to prod Rails into loading that association and then it all works fine. Very possible this is more of a problem in has_one than in your code, but it was 100% repeatable for us until I added that responds_to

fredriproad commented 13 years ago

I'm getting the same problem, only worse.

I copied/pasted the example code for Product and Pen, then tried a test like so:

require 'test_helper'

class PenTest < ActiveSupport::TestCase test "the truth" do p = Pen.new p.name = "BIC" p.price = 0.99 assert p.save end end

Which gets me:

1) Error: test_the_truth(PenTest): SystemStackError: stack level too deep /usr/local/lib/ruby/gems/1.9.1/gems/activerecord-3.0.9/lib/active_record/reflection.rb:261

1 tests, 0 assertions, 0 failures, 1 errors, 0 skips

Test run options: --seed 56498 rake aborted! Command failed with status (1): [/usr/local/bin/ruby -I"lib:test" "/usr/loc...]

I'm running Rails 3.0.9, Ruby 1.9, mysql2 gem.

Am I doing something wrong?

Thanks!

hzamani commented 13 years ago

Can you check it, with version 0.0.2?