
[PATCH] all_valid? goes into infinite loop on self-referencing many-to-many associations
Reported by Balint Erdi | December 10th, 2008 @ 11:30 AM | in 1.0.0
I have a User resource and a Recommendation resource. A user can recommend many users and can be recommended by many users; a self-referential many-to-many relationship. See here in more detail:
If I am adding a recommendation that is not valid (e.g the user recommends himself), then calling all_valid? on a user object goes into an infinite loop. (also see the pastie)
I investigated the case and that's because when the recommendation of the user object is checked for validity, it has a @collection instance variable whose value is the recommendation itself, contained in a list, so it will recursively call the recursive_valid? function with the same values.
I am trying to put together a failing spec and eventually I may come up with a fix.
Comments and changes to this ticket
-
Balint Erdi December 12th, 2008 @ 09:36 AM
- Tag set to dm-validations, validations
Here goes the failing spec. If anyone could take a quick look at it and confirm that all_valid? was meant to be used this way and this is actually a bug it would be fine.
Otherwise I'll proceed and try to implement the actual fix.
-
Balint Erdi December 12th, 2008 @ 10:15 AM
- Title changed from all_valid? goes into infinite loop on self-referencing many-to-many associations to [PATCH] all_valid? goes into infinite loop on self-referencing many-to-many associations
See my patch that fixes the issue attached.
-
Dan Kubb (dkubb) January 8th, 2009 @ 05:13 AM
- State changed from unconfirmed to accepted
- Assigned user set to Dan Kubb (dkubb)
-
Dan Kubb (dkubb) June 7th, 2009 @ 04:01 AM
- State changed from accepted to unconfirmed
- Assigned user changed from Dan Kubb (dkubb) to Michael Klishin (antares)
-
Martin Gamsjaeger (snusnu) July 9th, 2009 @ 04:39 PM
- State changed from unconfirmed to confirmed
I extracted a standalone script from the pastie and adapted it to work with current next branch (I also had to put the validates_with_block call into Recommendation instead of User as shown in the pastie). As can be seen below, I can confirm that this is still an issue with 0.10.
require "rubygems" require "dm-core" require "dm-validations" DataMapper::Logger.new(STDOUT, :debug) DataMapper.setup(:default, "sqlite3::memory:") class User include DataMapper::Resource property :id, Serial has 0..n, :recommendations has 0..n, :recommendees, :through => :recommendations, :model => "User", :target_key => [:user_id] has 0..n, :recommended_by, :through => :recommendations, :model => "User", :target_key => [:recommendee_id], :via => :user end class Recommendation include DataMapper::Resource property :user_id, Integer, :key => true property :recommendee_id, Integer, :key => true belongs_to :user belongs_to :recommendee, 'User', :source_key => [:recommendee_id] validates_with_block :recommendee_id do if @recommendee_id == @user_id [false, "A user can not recommend himself"] else true end end end DataMapper.auto_migrate! u = User.create u = User.get(u.id) u.recommendations u.recommendations.create(:recommendee => u) u.valid? u.all_valid? rec = u.recommendations.first puts rec.instance_variables.map { |ivar| "ivar name: #{ivar} ivar: #{rec.t(ivar).inspect}" }.join("\n") # mungo:snippets snusnu$ ruby balint.rb # ~ (0.000349) SELECT sqlite_version(*) # ~ (0.000393) DROP TABLE IF EXISTS "users" # ~ (0.000066) DROP TABLE IF EXISTS "recommendations" # ~ (0.000061) PRAGMA table_info("users") # ~ (0.001083) CREATE TABLE "users" ("id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT) # ~ (0.000027) PRAGMA table_info("recommendations") # ~ (0.000601) CREATE TABLE "recommendations" ("user_id" INTEGER NOT NULL, "recommendee_id" INTEGER NOT NULL, PRIMARY KEY("user_id", "recommendee_id")) # ~ (0.000096) INSERT INTO "users" DEFAULT VALUES # ~ (0.000065) SELECT "id" FROM "users" WHERE "id" = 1 # /opt/local/lib/ruby/gems/1.8/gems/extlib-0.9.13/lib/extlib/lazy_array.rb:293:in `respond_to?': stack level too deep (SystemStackError) # from /opt/local/lib/ruby/gems/1.8/gems/dm-core-0.10.0/lib/dm-core/collection.rb:908:in `respond_to?' # from /opt/local/lib/ruby/gems/1.8/gems/dm-validations-0.10.0/lib/dm-validations.rb:108:in `recursive_valid?' # from /opt/local/lib/ruby/gems/1.8/gems/dm-validations-0.10.0/lib/dm-validations.rb:104:in `each' # from /opt/local/lib/ruby/gems/1.8/gems/dm-validations-0.10.0/lib/dm-validations.rb:104:in `recursive_valid?' # from /opt/local/lib/ruby/gems/1.8/gems/dm-validations-0.10.0/lib/dm-validations.rb:111:in `recursive_valid?' # from /opt/local/lib/ruby/gems/1.8/gems/extlib-0.9.13/lib/extlib/lazy_array.rb:458:in `each' # from /opt/local/lib/ruby/gems/1.8/gems/extlib-0.9.13/lib/extlib/lazy_array.rb:458:in `each' # from /opt/local/lib/ruby/gems/1.8/gems/dm-validations-0.10.0/lib/dm-validations.rb:109:in `recursive_valid?' # ... 4980 levels... # from /opt/local/lib/ruby/gems/1.8/gems/dm-validations-0.10.0/lib/dm-validations.rb:104:in `each' # from /opt/local/lib/ruby/gems/1.8/gems/dm-validations-0.10.0/lib/dm-validations.rb:104:in `recursive_valid?' # from /opt/local/lib/ruby/gems/1.8/gems/dm-validations-0.10.0/lib/dm-validations.rb:97:in `all_valid?' # from balint.rb:46 # mungo:snippets snusnu$
-
Martin Gamsjaeger (snusnu) July 9th, 2009 @ 07:45 PM
- Assigned user changed from Michael Klishin (antares) to Martin Gamsjaeger (snusnu)
- State changed from confirmed to accepted
- Milestone set to 0.10.0
-
Martin Gamsjaeger (snusnu) July 11th, 2009 @ 12:04 PM
I think we should look into this once the next branch supports self referential m:m. Since that is currently not possible, it makes more sense to wait till that's known to work?
-
Dan Kubb (dkubb) October 4th, 2009 @ 09:33 PM
- Milestone changed from 0.10.0 to 0.10.2
[project:id#20609 not-tagged:"0.10.0" milestone:id#51895 bulk edit command]
-
Dan Kubb (dkubb) October 4th, 2009 @ 09:39 PM
Resource#all_valid? is no longer part of dm-validations, since it duplicates functionality in Resource#valid? now, and the implementation is not as good.
I'm going to leave this ticket open so that we can verify that Resource#valid? does not have a similar issue with m:m.
-
Dan Kubb (dkubb) February 1st, 2010 @ 04:33 PM
- Milestone changed from 0.10.2 to 1.0.0
-
Martin Gamsjaeger (snusnu) March 30th, 2010 @ 05:35 PM
- State changed from accepted to resolved
- Assigned user cleared.
I think it's confusing to keep this ticket around while we don't even have the #all_valid? method anymore. I'm marking this resolved for now. If a problem crops up again, I'm almost sure that the potential reporter wouldn't "find" this ticket and instead would open up a new one anyway.
Please Sign in or create a free account to add a new ticket.
With your very own profile, you can contribute to projects, track your activity, watch tickets, receive and update tickets through your email and much more.
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile »