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.

create and find_or_create_by behaves differently on model with no :id column

#4203
$ rails -v
Rails 2.3.5
$ rails tour
$ cd tour
$ script/generate model country code:string name:string --skip-timestamps

    class CreateCountries < ActiveRecord::Migration
      def self.up
        create_table :countries, :id => false do |t|
          t.string :code
          t.string :name
        end
      end

      def self.down
        drop_table :countries
      end
    end

$ rake db:migrate   
$ script/console
Loading development environment (Rails 2.3.5)
>> Country.create(:code => 'ZW', :name => 'Zimbabwe')
=> #<Country code: "ZW", name: "Zimbabwe">

define a primary key in country.rb:

class Country < ActiveRecord::Base
  set_primary_key :code
end
back to console:
>> reload!
Reloading...
=> true
>> Country.find_or_create_by_code('X1')
=> #<Country code: "X1", name: nil>
>> Country.create(:code => 'X2')
=> #<Country code: 2, name: nil>
>> Country.all
=> [#<Country code: "ZW", name: "Zimbabwe">, #<Country code: nil, name: nil>, #<Country code: "X1", name: nil>]
After "set_primary_key" is defined, Country.create no longer works. The :code field (primary key) of newly created records is a nil. find_or_create_by_code still works.

Reported by Horace Ho · March 17th, 2010 @ 09:01 AM

State: new
Milestone: none
Assigned to: nobody
Importance: none

Activity

  1. Alexey Nayden
    Alexey Nayden
    • Tag changed from :id primary_key to :id primary_key, 2.3.5, active_record

    January 13th, 2011 @ 01:26 AM

  2. Alexey Nayden
    Alexey Nayden
    • Tag changed from :id primary_key, 2.3.5, active_record to :id primary_key, 2.3.5, active_record, invalid

    @Horace actually AR always marks primary key column as attr_protected, so you're unable to mass-assign it with hash in #create. If you try to activate logging to stdout ActiveRecord::Base.logger = Logger.new(STDOUT) you'll get an error message regarding mass-assignment protected attribute. So in your case you're trying to create a record without PK column set to any value. And due to your database inconsistency in that example (i.e. PK insn't NOT NULL and UNIQUE as it always should), DB allows you to create such invalid record. If you set DB constraints for PK, you'd get an error — all correct.

    That's it.

    January 14th, 2011 @ 12:10 AM

  3. Alexey Nayden
    Alexey Nayden

    And, of course, your example is obviously fixed with "c = Country.new; c.code = 'X2'; c.save"

    January 14th, 2011 @ 12:11 AM

  4. bingbing