This project is archived and is in readonly mode.

#3939 ✓committed
trevor

'type' field not filled when created from hierarchy

Reported by trevor | February 12th, 2010 @ 05:51 AM | in 3.x

this is a test case, so the has_many / belongs_to logic is off.

behavior i'm seeing is the 'type' field is automatically filled in with 'create', but not when called from a nested model. (in this example there's only one 'Second', but there should be two.)

% cat db/migrate/001_create_entries.rb 
class CreateEntries < ActiveRecord::Migration
  def self.up
    create_table :entries do |t|
      t.string :type
      t.integer :parent_id
      t.timestamps
    end
  end
end

% cat app/models/first.rb 
class First < ActiveRecord::Base
  set_table_name 'entries'
  default_scope :conditions => {:type => 'First'}
  has_many :seconds, :foreign_key => :parent_id
end

% cat app/models/second.rb 
class Second < ActiveRecord::Base
  set_table_name 'entries'
  default_scope :conditions => {:type => 'Second'}
end

% rc
Loading development environment (Rails 3.0.0.beta)
irb(main):001:0> a = First.create
=> #<First id: 1, type: "First", parent_id: nil, created_at: "2010-02-12 05:40:34", updated_at: "2010-02-12 05:40:34">
irb(main):002:0> a.seconds
=> []
irb(main):003:0> a.seconds.create
=> #<Second id: 2, type: nil, parent_id: 1, created_at: "2010-02-12 05:40:44", updated_at: "2010-02-12 05:40:44">
irb(main):004:0> a.seconds
=> [#<Second id: 2, type: nil, parent_id: 1, created_at: "2010-02-12 05:40:44", updated_at: "2010-02-12 05:40:44">]
irb(main):005:0> b = Second.create
=> #<Second id: 3, type: "Second", parent_id: nil, created_at: "2010-02-12 05:40:59", updated_at: "2010-02-12 05:40:59">
irb(main):006:0> Second.all
=> [#<Second id: 3, type: "Second", parent_id: nil, created_at: "2010-02-12 05:40:59", updated_at: "2010-02-12 05:40:59">]

Comments and changes to this ticket

  • Ryan Bigg

    Ryan Bigg May 25th, 2010 @ 12:48 PM

    • State changed from “new” to “open”

    What happens if you set self.inheritance_column nil at the top of the Second model? type is a protected field.

  • Neeraj Singh

    Neeraj Singh August 13th, 2010 @ 02:42 AM

    • Assigned user set to “Neeraj Singh”
    • Tag set to rails 3, activerecord
    • Importance changed from “” to “Low”

    @trevor can you check if the attached patch fixes your problem.

  • Neeraj Singh

    Neeraj Singh August 15th, 2010 @ 04:07 PM

    • Milestone set to 3.x
    • Assigned user changed from “Neeraj Singh” to “José Valim”
    • Tag changed from rails 3, activerecord to rails 3, activerecord, patch

    I discussed this ticket briefly with Mr. Valim. Assigning it to him.

  • José Valim

    José Valim August 15th, 2010 @ 08:41 PM

    Let's wait Trevor confirm if the patch really fixed the bug for him before applying it.

  • trevor

    trevor August 16th, 2010 @ 05:11 PM

    applied the patch, but still seeing the type being set to 'nil'.

    irb(main):003:0> a.seconds.create
    => #<Second id: 2, type: nil, parent_id: 1, created_at: "2010-08-16 16:02:32", updated_at: "2010-08-16 16:02:32">
    irb(main):004:0> a.seconds
    => [#<Second id: 2, type: nil, parent_id: 1, created_at: "2010-08-16 16:02:32", updated_at: "2010-08-16 16:02:32">]
    

    per Ryan - setting self.inheritance_column = nil in the Second model has no effect.

  • Neeraj Singh

    Neeraj Singh August 17th, 2010 @ 06:05 PM

    Checked again and works for me.

    Here is what I did

    • checkout rails master
    • applied patch
    • execute First.lab
    class CreateEntries < ActiveRecord::Migration
      def self.up
        create_table :entries do |t|
          t.string :type
          t.integer :parent_id
          t.timestamps
        end
      end
    end
    
    class Second < ActiveRecord::Base
      set_table_name 'entries'
      default_scope :conditions => {:type => 'Second'}
    end
    
    class First < ActiveRecord::Base
      set_table_name 'entries'
      default_scope :conditions => {:type => 'First'}
      has_many :seconds, :foreign_key => :parent_id
    
      def self.lab
        a = First.create
        puts a.inspect
    
        b = Second.create
        puts b.inspect
    
        b1 = a.seconds.create
        puts b1.inspect 
      end
    
    end
    
    
    $ rails runner First.lab
    #<First id: 19, type: "First", parent_id: nil, created_at: "2010-08-17 16:55:03", updated_at: "2010-08-17 16:55:03">
    #<Second id: 20, type: "Second", parent_id: nil, created_at: "2010-08-17 16:55:03", updated_at: "2010-08-17 16:55:03">
    #<Second id: 21, type: "Second", parent_id: 19, created_at: "2010-08-17 16:55:03", updated_at: "2010-08-17 16:55:03">
    
  • trevor

    trevor August 17th, 2010 @ 06:25 PM

    this is interesting. note that i monkey-patched RC, this is the behavior that i'm seeing - please see if you can reproduce. it works correctly as soon as there's a Second type existing in the database, but not before.

    % rake db:drop; rake db:migrate
    
    % rc
    Loading development environment (Rails 3.0.0.rc)
    irb(main):001:0> a = First.create
    => #<First id: 1, type: "First", parent_id: nil, created_at: "2010-08-17 17:19:31", updated_at: "2010-08-17 17:19:31">
    irb(main):002:0> a.seconds.create
    => #<Second id: 2, type: nil, parent_id: 1, created_at: "2010-08-17 17:19:36", updated_at: "2010-08-17 17:19:36">
    irb(main):003:0> Second.create
    => #<Second id: 3, type: "Second", parent_id: nil, created_at: "2010-08-17 17:19:45", updated_at: "2010-08-17 17:19:45">
    irb(main):004:0> a.seconds.create
    => #<Second id: 4, type: "Second", parent_id: 1, created_at: "2010-08-17 17:19:59", updated_at: "2010-08-17 17:19:59">
    irb(main):005:0> a.seconds
    => [#<Second id: 4, type: "Second", parent_id: 1, created_at: "2010-08-17 17:19:59", updated_at: "2010-08-17 17:19:59">, #<Second id: 2, type: nil, parent_id: 1, created_at: "2010-08-17 17:19:36", updated_at: "2010-08-17 17:19:36">]
    irb(main):006:0> exit
    
    % rc
    Loading development environment (Rails 3.0.0.rc)
    irb(main):001:0> a = First.create
    => #<First id: 5, type: "First", parent_id: nil, created_at: "2010-08-17 17:20:23", updated_at: "2010-08-17 17:20:23">
    irb(main):002:0> a.seconds.create
    => #<Second id: 6, type: "Second", parent_id: 5, created_at: "2010-08-17 17:20:29", updated_at: "2010-08-17 17:20:29">
    irb(main):003:0>
    
  • Neeraj Singh

    Neeraj Singh August 17th, 2010 @ 08:00 PM

    @Trevor Will it be possible for you to try the patch on rails edge instead of your monkey-patched version of RC. A lot has changed since RC.

  • trevor

    trevor August 18th, 2010 @ 08:09 PM

    trying patch with edge now, still seeing issue, try switching b1 with b in your example on a clean database.

    ## First-bug.lab
    
    class Second < ActiveRecord::Base
      set_table_name 'entries'
      default_scope :conditions => {:type => 'Second'}
    end
    
    class First < ActiveRecord::Base
      set_table_name 'entries'
      default_scope :conditions => {:type => 'First'}
      has_many :seconds, :foreign_key => :parent_id
    end
    
    def lab
      a = First.create
      puts a.inspect
    
      b1 = a.seconds.create
      puts b1.inspect
    
      b = Second.create
      puts b.inspect
    end
    
    lab
    

    bug apparent when database is fresh, goes away when a 'Second' type exists -

    % rake db:drop; rake db:migrate
    
    % rails runner First-bug.lab
    #<First id: 1, type: "First", parent_id: nil, created_at: "2010-08-18 19:01:11", updated_at: "2010-08-18 19:01:11">
    #<Second id: 2, type: nil, parent_id: 1, created_at: "2010-08-18 19:01:11", updated_at: "2010-08-18 19:01:11">
    #<Second id: 3, type: "Second", parent_id: nil, created_at: "2010-08-18 19:01:11", updated_at: "2010-08-18 19:01:11">
    
    % rails runner First-bug.lab
    #<First id: 4, type: "First", parent_id: nil, created_at: "2010-08-18 19:01:25", updated_at: "2010-08-18 19:01:25">
    #<Second id: 5, type: "Second", parent_id: 4, created_at: "2010-08-18 19:01:25", updated_at: "2010-08-18 19:01:25">
    #<Second id: 6, type: "Second", parent_id: nil, created_at: "2010-08-18 19:01:25", updated_at: "2010-08-18 19:01:25">
    
    % rake db:drop; rake db:migrate
    
    % rails runner First-bug.lab
    #<First id: 1, type: "First", parent_id: nil, created_at: "2010-08-18 19:03:17", updated_at: "2010-08-18 19:03:17">
    #<Second id: 2, type: nil, parent_id: 1, created_at: "2010-08-18 19:03:17", updated_at: "2010-08-18 19:03:17">
    #<Second id: 3, type: "Second", parent_id: nil, created_at: "2010-08-18 19:03:17", updated_at: "2010-08-18 19:03:17">
    
  • Neeraj Singh

    Neeraj Singh August 19th, 2010 @ 11:12 AM

    I just did rake db:drop; rake db:migrate and everything works for me.

  • trevor

    trevor August 19th, 2010 @ 04:52 PM

    did you switch the creation order as well?

    here's how i'm reproducing the issue, with CreateEntries as the migration. the issue is apparent with B.lab

    ### A.lab
    
    class Second < ActiveRecord::Base
      set_table_name 'entries'
      default_scope :conditions => {:type => 'Second'}
    end
    
    class First < ActiveRecord::Base
      set_table_name 'entries'
      default_scope :conditions => {:type => 'First'}
      has_many :seconds, :foreign_key => :parent_id
    end
    
    def lab
      a = First.create
      puts a.inspect
    
      b = Second.create
      puts b.inspect
    
      child = a.seconds.create
      puts child.inspect
    end
    
    lab
    puts '---again---'
    lab
    
    ### B.lab
    class Second < ActiveRecord::Base
      set_table_name 'entries'
      default_scope :conditions => {:type => 'Second'}
    end
    
    class First < ActiveRecord::Base
      set_table_name 'entries'
      default_scope :conditions => {:type => 'First'}
      has_many :seconds, :foreign_key => :parent_id
    end
    
    def lab
      a = First.create
      puts a.inspect
    
      child = a.seconds.create
      puts child.inspect
    
      b = Second.create
      puts b.inspect
    end
    
    lab
    puts '---again---'
    lab
    

    running with edge and patch

    B.lab demonstrates if a child is created before a database entry of that child's type has yet to exist, it's type is set to nil.

    % rake db:drop; rake db:migrate; rails runner A.lab
    #<First id: 1, type: "First", parent_id: nil, created_at: "2010-08-19 15:30:47", updated_at: "2010-08-19 15:30:47">
    #<Second id: 2, type: "Second", parent_id: nil, created_at: "2010-08-19 15:30:47", updated_at: "2010-08-19 15:30:47">
    #<Second id: 3, type: "Second", parent_id: 1, created_at: "2010-08-19 15:30:47", updated_at: "2010-08-19 15:30:47">
    ---again---
    #<First id: 4, type: "First", parent_id: nil, created_at: "2010-08-19 15:30:47", updated_at: "2010-08-19 15:30:47">
    #<Second id: 5, type: "Second", parent_id: nil, created_at: "2010-08-19 15:30:47", updated_at: "2010-08-19 15:30:47">
    #<Second id: 6, type: "Second", parent_id: 4, created_at: "2010-08-19 15:30:47", updated_at: "2010-08-19 15:30:47">
    
    % rake db:drop; rake db:migrate; rails runner B.lab
    #<First id: 1, type: "First", parent_id: nil, created_at: "2010-08-19 15:31:49", updated_at: "2010-08-19 15:31:49">
    #<Second id: 2, type: nil, parent_id: 1, created_at: "2010-08-19 15:31:49", updated_at: "2010-08-19 15:31:49">
    #<Second id: 3, type: "Second", parent_id: nil, created_at: "2010-08-19 15:31:49", updated_at: "2010-08-19 15:31:49">
    ---again---
    #<First id: 4, type: "First", parent_id: nil, created_at: "2010-08-19 15:31:49", updated_at: "2010-08-19 15:31:49">
    #<Second id: 5, type: "Second", parent_id: 4, created_at: "2010-08-19 15:31:49", updated_at: "2010-08-19 15:31:49">
    #<Second id: 6, type: "Second", parent_id: nil, created_at: "2010-08-19 15:31:49", updated_at: "2010-08-19 15:31:49">
    

    running unpatched 3.0RC

    comparison to show what the patch has fixed.

    % rake db:drop; rake db:migrate; rails runner A.lab
    #<First id: 1, type: "First", parent_id: nil, created_at: "2010-08-19 15:38:37", updated_at: "2010-08-19 15:38:37">
    #<Second id: 2, type: "Second", parent_id: nil, created_at: "2010-08-19 15:38:37", updated_at: "2010-08-19 15:38:37">
    #<Second id: 3, type: nil, parent_id: 1, created_at: "2010-08-19 15:38:37", updated_at: "2010-08-19 15:38:37">
    ---again---
    #<First id: 4, type: "First", parent_id: nil, created_at: "2010-08-19 15:38:37", updated_at: "2010-08-19 15:38:37">
    #<Second id: 5, type: "Second", parent_id: nil, created_at: "2010-08-19 15:38:37", updated_at: "2010-08-19 15:38:37">
    #<Second id: 6, type: nil, parent_id: 4, created_at: "2010-08-19 15:38:37", updated_at: "2010-08-19 15:38:37">
    
    % rake db:drop; rake db:migrate; rails runner B.lab
    #<First id: 1, type: "First", parent_id: nil, created_at: "2010-08-19 15:41:41", updated_at: "2010-08-19 15:41:41">
    #<Second id: 2, type: nil, parent_id: 1, created_at: "2010-08-19 15:41:41", updated_at: "2010-08-19 15:41:41">
    #<Second id: 3, type: "Second", parent_id: nil, created_at: "2010-08-19 15:41:41", updated_at: "2010-08-19 15:41:41">
    ---again---
    #<First id: 4, type: "First", parent_id: nil, created_at: "2010-08-19 15:41:41", updated_at: "2010-08-19 15:41:41">
    #<Second id: 5, type: nil, parent_id: 4, created_at: "2010-08-19 15:41:41", updated_at: "2010-08-19 15:41:41">
    #<Second id: 6, type: "Second", parent_id: nil, created_at: "2010-08-19 15:41:41", updated_at: "2010-08-19 15:41:41">
    

    if B.lab works fine for you on a clean database, then it may be specific to my system. it'd be good if we could reproduce it in the tests so it may be noticed by others.

    % ruby -v
    ruby 1.9.2p0 (2010-08-18 revision 29036) [x86_64-darwin10.4.0]
    % sqlite3 --version
    3.7.0.1
    % gem list sqlite3
    
    *** LOCAL GEMS ***
    
    sqlite3-ruby (1.3.1)
    
  • Neeraj Singh

    Neeraj Singh August 19th, 2010 @ 05:11 PM

    I am able to reproduce it. Thanks for your patience.

    The reason why in B.lab you are getting 'type' as nil is class 'Second' is not loaded.

    Everything works if class Second is loaded.

    It is a known issue and it is documented. I tried to look for the documentation but am not able to find it here. Will add the link later when I find it.

    Once again for Rails to work properly if STI is being used then all the STI classes should be pre loaded. This is an issue in development mode only. It will never happen in production.

    Do notice that without the patch if you have class 'Second' loaded then alos I was getting nil.

  • trevor

    trevor August 19th, 2010 @ 05:24 PM

    okay, i'm good then. thanks for the patch and all your effort!

    out of curiosity, how could i pre load the class in development?

    for example i would have thought doing something like Second.new would take care of it -

    def lab
      a = First.create
      puts a.inspect
    
      x = Second.new
      puts x
    
      child = a.seconds.create
      puts child.inspect
    
      b = Second.create
      puts b.inspect
    end
    
    #<First id: 1, type: "First", parent_id: nil, created_at: "2010-08-19 16:21:49", updated_at: "2010-08-19 16:21:49">
    #<Second:0x000001025f8428>
    #<Second id: 2, type: nil, parent_id: 1, created_at: "2010-08-19 16:21:49", updated_at: "2010-08-19 16:21:49">
    #<Second id: 3, type: "Second", parent_id: nil, created_at: "2010-08-19 16:21:49", updated_at: "2010-08-19 16:21:49">
    ---again---
    #<First id: 4, type: "First", parent_id: nil, created_at: "2010-08-19 16:21:49", updated_at: "2010-08-19 16:21:49">
    #<Second:0x00000102570050>
    #<Second id: 5, type: "Second", parent_id: 4, created_at: "2010-08-19 16:21:49", updated_at: "2010-08-19 16:21:49">
    #<Second id: 6, type: "Second", parent_id: nil, created_at: "2010-08-19 16:21:49", updated_at: "2010-08-19 16:21:49">
    
  • trevor

    trevor August 19th, 2010 @ 05:26 PM

    ... and i meant that as -

    #<First id: 1, type: "First", parent_id: nil, created_at: "2010-08-19 16:24:48", updated_at: "2010-08-19 16:24:48">
    #<Second id: nil, type: "Second", parent_id: nil, created_at: nil, updated_at: nil>
    #<Second id: 2, type: nil, parent_id: 1, created_at: "2010-08-19 16:24:48", updated_at: "2010-08-19 16:24:48">
    #<Second id: 3, type: "Second", parent_id: nil, created_at: "2010-08-19 16:24:48", updated_at: "2010-08-19 16:24:48">
    ---again---
    #<First id: 4, type: "First", parent_id: nil, created_at: "2010-08-19 16:24:48", updated_at: "2010-08-19 16:24:48">
    #<Second id: nil, type: "Second", parent_id: nil, created_at: nil, updated_at: nil>
    #<Second id: 5, type: "Second", parent_id: 4, created_at: "2010-08-19 16:24:48", updated_at: "2010-08-19 16:24:48">
    #<Second id: 6, type: "Second", parent_id: nil, created_at: "2010-08-19 16:24:48", updated_at: "2010-08-19 16:24:48">
    
  • Neeraj Singh

    Neeraj Singh August 19th, 2010 @ 06:11 PM

    This is case where First and Second use 'type' but they are not subclass of any other model. For this case I would have just do

    Class First
    Second #loading Second for STI purpose
    end

    class Second
    First #loading First for STI purpose
    end

    If they were subclases of another model called say 'Ranking' Then you could have used Ranking.descendants.each {|r| r }

  • trevor

    trevor August 19th, 2010 @ 06:30 PM

    just tried that a few different ways and couldn't get it to take - weird bug.

  • José Valim

    José Valim August 19th, 2010 @ 06:31 PM

    • State changed from “open” to “invalid”

    Confirm. In order for STI to work, all clases should be loaded before hand and I believe this is properly documented.

  • Neeraj Singh

    Neeraj Singh August 19th, 2010 @ 06:34 PM

    • State changed from “invalid” to “open”

    Setting the status to open.

    The patch is still valid and the patch works for Trevor. It was not working only when he was not loading Second before hand.

    :-)

  • Neeraj Singh

    Neeraj Singh August 19th, 2010 @ 06:35 PM

    Without the patch post.comments.create will create the new comment record without the default scope applied for Comment.

  • trevor

    trevor August 19th, 2010 @ 06:38 PM

    +1 agreed - patch works and fixes issue. small edge case related bug with STI.

  • trevor

    trevor August 24th, 2010 @ 04:40 AM

    can this patch be added to 3.0 final?

  • José Valim

    José Valim August 24th, 2010 @ 04:43 AM

    • State changed from “open” to “committed”

    It was already applied. A typo in the commit message did not allow it to be reported back it here:

    http://github.com/rails/rails/commit/2e455429427a4078d2888cc39305f9...

Create your profile

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

<h2 style="font-size: 14px">Tickets have moved to Github</h2>

The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>

Attachments

Pages