Lighthouse has a new layout. Prefer the old one? Return to the old layout, and switch back any time from the link at the top of each page.

This project is archived and is in readonly mode.

has_many :dependent => :delete_all throws exception on models in modules

#2627

If a model that is declared inside a module is associated via a has_many to another model in the same module, and :dependent is set to :delete_all or :nullify, an exception is thrown stating that "(Module) is not missing Constant (class)"

This is because the method that sets up the before_destroy handler just uses a text representation of the model name instead of the actual model class. The example I've been using is this:

class Astronomy::SolarSystem < ActiveRecord::Base
  has_many :planets, :dependent => :delete_all
end
The before destroy handler ends up making a call to Planet.delete_all instead of Astronomy::Planet.delete_all. I am attaching a patch with a test case that show this (and a similar flaw with :dependent => :nullify) and a solution to the problem.

I discovered this bug in rails 2.1 and it is still present in edge rails. The patch is meant to be applied to edge.

As an aside, I don't really like my particular solution because of its reliance on 'eval.' I think it would be a better idea to change the dependent_conditions to be parameterized instead of a string that needs to be double-evaled, but I'm not sure that will play well will every database backend. If it's ok to change that conditions clause to a parameterized query, let me know and I'll update the patch.

Reported by Brian Samson · May 9th, 2009 @ 07:03 AM

State: committed
Milestone: 2.3.6
Assigned to: Jeremy Kemper Jeremy Kemper
Importance: none

Activity

  1. Geoff Coffey
  2. CancelProfileIsBroken
    CancelProfileIsBroken
    • Tag changed from active_record, dependent, has_many, module to active_record, bugmash, dependent, has_many, module

    August 6th, 2009 @ 02:34 PM

  3. Dan Pickett
    Dan Pickett

    +1 verified

    this applies cleanly to master with a few whitespace warnings

    test suite passes

    note that it does add a few models

    August 8th, 2009 @ 11:21 PM

  4. Brian Samson
    Brian Samson

    This bug still exists as far as I can tell. I updated this patch to apply cleanly to edge, if somebody could double-check that for me quick I'd appreciate it.

    October 12th, 2009 @ 08:14 PM

  5. Rizwan Reza
    Rizwan Reza

    -1 fail

    The patch fails when testing sqlite3 adapter but passes on MySQL. I've checked on the master branch.

    October 14th, 2009 @ 04:26 PM

  6. Brian Samson
    Brian Samson

    Good catch, Rizwan.

    I was using double quotes in the eval which threw off sqlite's quoting. I changed it to %() which should work unless you know of a database that uses unmatched parentheses as a way to quote column names :)

    If you have the time, it would be cool if you could retest, but I checked on sqlite3 and mysql and the tests all pass now.

    October 14th, 2009 @ 10:48 PM

  7. Rizwan Reza
    Rizwan Reza
    • Tag changed from active_record, bugmash, dependent, has_many, module to active_record, bugmash, dependent, has_many, module, review

    +1 verified

    The patch applies cleanly and passes tests all tests.

    November 3rd, 2009 @ 04:17 PM

  8. Andrew White
    Andrew White

    Actually, isn't this another instance of this bug: #2283 Unnecessary exception raised in AS::Dependencies.load_missing_constant

    Wouldn't it be better to fix the actual problem rather than patching around it all over the place in ActiveRecord?

    November 3rd, 2009 @ 05:10 PM

  9. Rizwan Reza
    Rizwan Reza
    • Tag changed from active_record, bugmash, dependent, has_many, module, review to active_record, dependent, has_many, module, review

    February 12th, 2010 @ 12:46 PM

  10. Brian Samson
    Brian Samson

    I think that perhaps Andrew's patch would fix this problem, but it looks like that has been pushed off to 3.0. Basically my patch just makes this behavior ask for Mod::Class instead of just Class, which I think it should be doing anyway.

    Is there any way we can get this patch put in to 2.3.6?

    March 30th, 2010 @ 05:54 PM

  11. Andrew White
    Andrew White
    • Tag changed from active_record, dependent, has_many, module, review to active_record, dependent, has_many, module, patch, review
    • Assigned user set to Yehuda Katz (wycats)

    My patch for compute_type from 2283 is a necessary fix but some other changes are required as well. The attached patch provides those fixes and tests. The dependency callbacks were as you pointed out hardcoded, so I just defer the class lookup until the callback is executed. The patch is for master but I can do a backport once it's been accepted.

    I did try and use existing schema and fixtures but it broke too many tests.

    March 31st, 2010 @ 07:50 AM

  12. Jeremy Kemper
    Jeremy Kemper
    • State changed from new to open
    • Assigned user changed from Yehuda Katz (wycats) to Jeremy Kemper
    • Milestone changed from 2.x to 2.3.6

    Thanks Andrew! I get two errors with the patch:

      1) Error:
    test_nested_models_should_not_raise_exception_when_using_delete_all_dependency_on_association(ModulesTest):
    ArgumentError: Shop is not missing constant Product!
    
    
    2) Error: test_nested_models_should_not_raise_exception_when_using_nullify_dependency_on_association(ModulesTest): ArgumentError: Shop is not missing constant Variant!

    April 3rd, 2010 @ 03:52 PM

  13. Andrew White
    Andrew White

    Jeremy, that's because the compute type fix from from 2283 is needed. Carl's recent commit makes my patch on this ticket redundant, though it still needs backporting to 2-3-stable.

    I'll move the tests from here to the patches for master and 2-3-stable on 2283 and I'll add a patch here for master to test Carl's commit and then backport the commit and test to 2-3-stable and add it here also. Is this okay?

    April 3rd, 2010 @ 05:00 PM

  14. Jeremy Kemper
    Jeremy Kemper

    Ah, I missed that dependency. That sounds great; thanks Andrew!

    April 3rd, 2010 @ 09:12 PM

  15. Andrew White
    Andrew White

    Patch for master adding tests for preventing regression.

    April 4th, 2010 @ 01:30 AM

  16. Andrew White
    Andrew White

    Patch for 2-3-stable backporting changes from Carl's commits and adding tests from patch above

    April 4th, 2010 @ 01:32 AM

  17. Andrew White
    Andrew White

    Updated backport patch - the previous patch didn't send the right class to the dependent_conditions method.

    April 4th, 2010 @ 07:06 AM

  18. Repository
  19. Repository
  20. CDD Developers
    CDD Developers

    The patch that was applied to the 2.3 branch introduced a regression bug when declaring a polymorphic association on a STI model hierarchy.

    Making up a simple example:

    class FileAssociation < ActiveRecord:Base
    belongs_to :associated_record, :polymorphic => true end

    class Message < ActiveRecord:Base
    has_many :file_associations, :as => :associated_record, :dependent => :delete_all end

    class Mail < Message
    end

    some_mail = Mail.first
    some_mail.file_associations.first # => some file associations
    some_mail.file_associations.associated_record_type # => "Message"

    some_mail.destroy # => does not destroy the file associations since the generated SQL checks for associated_record_type = 'Mail'

    The attached patch fixes the previous commit by using the base_class of the model class. (The fix is only intended to fix the regression and does not handle the larger issue involving STI and polymorphic associations as described in #2756 [patch] The polymorphic type field should be subclass name instead of base cl... that would require a different fix)

    April 19th, 2010 @ 11:31 PM