#485 ✓resolved
Bobby Calderwood

"has n, :through..." does not allow saving of model

Reported by Bobby Calderwood | July 26th, 2008 @ 06:56 PM

class Taggable

include DataMapper::Resource

property :id, Integer, :serial => true

has n, :taggings

has n, :tags, :through => :taggings


class Tagging

include DataMapper::Resource

property :id, Integer, :serial => true

belongs_to :taggable

belongs_to :tag


class Tag

include DataMapper::Resource

property :id, Integer, :serial => true

has n, :taggings

has n, :taggables, :through => :taggings


taggable = Taggable.new



Trying to access the remote association and then saving raises this strange error:

DataMapper::Associations::ImmutableAssociationError: You can not modify this assocation

from /Library/Ruby/Gems/1.8/gems/dm-core-0.9.3/lib/dm-core/associations/one_to_many.rb:247:in `assert_mutable'

from /Library/Ruby/Gems/1.8/gems/dm-core-0.9.3/lib/dm-core/associations/one_to_many.rb:199:in `save'

from /Library/Ruby/Gems/1.8/gems/dm-core-0.9.3/lib/dm-core/resource.rb:272:in `hookable__save_nan_before_advised'

from /Library/Ruby/Gems/1.8/gems/dm-core-0.9.3/lib/dm-core/resource.rb:272:in `each'

from /Library/Ruby/Gems/1.8/gems/dm-core-0.9.3/lib/dm-core/resource.rb:272:in `hookable__save_nan_before_advised'

from /Library/Ruby/Gems/1.8/gems/extlib-0.9.3/lib/extlib/hook.rb:294:in `save!'

from /Library/Ruby/Gems/1.8/gems/extlib-0.9.3/lib/extlib/hook.rb:292:in `catch'

from /Library/Ruby/Gems/1.8/gems/extlib-0.9.3/lib/extlib/hook.rb:292:in `save!'

from /Library/Ruby/Gems/1.8/gems/dm-validations-0.9.3/lib/dm-validations.rb:44:in `save'

from (irb):39

Comments and changes to this ticket

  • nicholaides

    nicholaides August 24th, 2008 @ 02:52 PM

    I just ran into this bug, too. Looks like the logic in OneToMany#assert_mutable (http://github.com/sam/dm-core/tr...) needs to account for :through associations.

  • Kyle Drake

    Kyle Drake November 10th, 2008 @ 06:38 PM

    Is anybody looking into this? This is still a problem.

    The first error in this script highlights the problem as well:


  • Vladimir Lushnikov

    Vladimir Lushnikov November 14th, 2008 @ 08:04 AM

    I am curious - why is this not working?

  • kristian

    kristian November 17th, 2008 @ 01:41 PM

    a workaround is

    class Tag
      include DataMapper::Resource
      property :id, Serial
      has n, :taggings
      has n, :tags, :through => :taggings, :mutable => true

    adding this :mutable option.

    I think the opposite default for the mutable option would be a better choice. see the patch to see where to fix it (or apply the patch)

  • José Valim

    José Valim November 22nd, 2008 @ 12:33 PM

    The patch sent has the line:

    @mutable = options.delete(:mutable) || true

    That will always return true. You should something like:

    @mutable = options[:mutable] ? options.delete(:mutable) : true

    Regards, José Valim.

  • Jonathan Stott (namelessjon)

    Jonathan Stott (namelessjon) November 30th, 2008 @ 09:22 AM

    • State changed from “new” to “hold”
    • Assigned user cleared.

    I'm not sure this is an issue.

    The through resource may well be some complex item which cannot be created from defaults. On the other hand, if it can, allowing that to happen is a good thing,

  • Dan Kubb (dkubb)

    Dan Kubb (dkubb) December 4th, 2008 @ 03:14 AM

    • State changed from “hold” to “confirmed”

    I can confirm that has n, :through still exhibits this behavior.

    However, this is by design until we can work out the cases when the join record can be automatically created vs where it cannot.

    If the join record only contains references to both sides of the association, then no problem. If it contains reference AND properties with default values, also no problem. However, in the case where it references both sides AND has a property without a default, we'd still need to throw an exception because it will be impossible for DM to fill in the missing information when creating the join record.

    We just need to codify this so that :through associations can be modified in certain situations. This work will be ongoing in the dkubb/dm-core fork over the next couple of months.

  • Dan Kubb (dkubb)

    Dan Kubb (dkubb) January 7th, 2009 @ 04:26 PM

    • Assigned user set to “Dan Kubb (dkubb)”
  • Dan Kubb (dkubb)

    Dan Kubb (dkubb) January 7th, 2009 @ 04:33 PM

    • State changed from “confirmed” to “accepted”
  • Marcin Kulik

    Marcin Kulik January 8th, 2009 @ 05:22 AM

    @José Valim


    @@@ruby @mutable = options[:mutable] ? options.delete(:mutable) : true

    will also return true ALWAYS. options[:mutable] can return "nil" or "false", if it will return false condition will not be met and will choose "true".
    Better would be:
    @mutable = options.key?(:mutable) ? options.delete(:mutable) : true
  • Dan Kubb (dkubb)

    Dan Kubb (dkubb) May 28th, 2009 @ 03:27 AM

    • State changed from “accepted” to “resolved”

    I can confirm this issue is resolved in dm-core/next. Attached is a script to demonstrate the fix.

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.

New-ticket Create new ticket

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »