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.

STI type not updatable

#5953

Imagine you have the following scenario:

@@@ class Employer < ActiveRecord::Base end

class Manager < Employer
end

employer = Employer.find(1) # => #
manager = employer.becomes(Manager) # => #
manager.save! # => #
Employer.find(1) # => #


The problem is in Persistence#update (https://github.com/rails/rails/blob/920660b19c5419c6df1c234a84e7fec71b169544/activerecord/lib/active_record/persistence.rb#L252). It calls Base#unscoped which calls Base#relation where type_condition is automatically applied. The resulting SQL statement is therefore UPDATE employers SET .... WHERE employers.id = 1 AND employers.type = 'Manager' and although #save! doesn't throw an error the record is not actually updated.


A test case is attached.

Reported by Dim · November 11th, 2010 @ 04:28 PM

State: stale
Milestone: none
Assigned to: nobody
Importance: Low

Activity

  1. Dim
    Dim

    Sorry about the previous formatting issues, here again:

    Imagine you have the following scenario:

    class Employer < ActiveRecord::Base
    end
    
    class Manager < Employer
    end
    
    employer = Employer.find(1)          # => #<Employer>
    manager  = employer.becomes(Manager) # => #<Manager>
    manager.save!                        # => #<Manager>
    Employer.find(1)                     # => #<Employer>
    

    The problem is in Persistence#update. It calls Base#unscoped which calls Base#relation where type_condition is automatically applied. The resulting SQL statement is therefore

    UPDATE employers SET .... WHERE employers.id = 1 AND employers.type = 'Manager'`
    

    and although #save! doesn't throw an error the record is not actually updated.

    A test case is attached.

    November 11th, 2010 @ 04:31 PM

  2. Neeraj Singh
    Neeraj Singh
    • Importance changed from to Low

    I don't know about becomes. Is it rails thing or your own implementation? If it is your implementation then can you post the method?

    November 11th, 2010 @ 04:52 PM

  3. Dim
  4. Repository
    Repository
    • State changed from new to resolved

    November 11th, 2010 @ 06:17 PM

  5. José Valim
  6. Andrew White
    Andrew White
    • State changed from resolved to new

    Looking at the docs it seems that becomes is more for temporarily mutating an instance so that it appears as its superclass for rendering purposes (partials, polymorphic routes, etc.). You're trying to use it the other way round - making a superclass become a subclass.

    There should be an official way of mutating an object to a different class and saving the change back to the database but I don't think becomes should be it.

    November 11th, 2010 @ 06:21 PM

  7. Dim
    Dim

    Not sure, I think becomes is already doing most of the job pretty well, but it's certainly incomplete.

    November 11th, 2010 @ 06:29 PM

  8. Santiago Pastorino
    Santiago Pastorino
    • State changed from new to open

    This issue has been automatically marked as stale because it has not been commented on for at least three months.

    The resources of the Rails core team are limited, and so we are asking for your help. If you can still reproduce this error on the 3-0-stable branch or on master, please reply with all of the information you have about it and add "[state:open]" to your comment. This will reopen the ticket for review. Likewise, if you feel that this is a very important feature for Rails to include, please reply with your explanation so we can consider it.

    Thank you for all your contributions, and we hope you will understand this step to focus our efforts where they are most helpful.

    February 11th, 2011 @ 07:18 PM

  9. Santiago Pastorino
    Santiago Pastorino
    • State changed from open to stale

    February 11th, 2011 @ 07:18 PM

  10. Mark Wilden
    Mark Wilden

    This may be stale, but it's still a problem. AFAICS, you can't update the type of an STI record.

    If a user changes an ArticleReference to a BookReference, I use #becomes on it, but then the update call tries to update a BookReference with that ID, and there isn't one. I think it's incorrect behavior to use the type column to find a single record - just the id should be used, as was apparently done in Rails < 3.

    My workaround is

    Reference.connection.execute "UPDATE `references` SET type = '#{@reference.type}' 
      WHERE id = '#{@reference.id}'"
    @reference.update_attributes params[:reference]
    

    April 18th, 2011 @ 02:01 AM

  11. victorcoder
    victorcoder

    What's the status of this issue, it should be fixed?

    Thanks.

    May 4th, 2011 @ 08:46 AM