Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #9870 (new defect)

Opened 1 year ago

Last modified 1 year ago

[PATCH] Invalid attribute types should not be accepted from the command line

Reported by: Ionex Interactive Assigned to: core
Priority: normal Milestone:
Component: ActiveRecord Version: 1.2.3
Severity: minor Keywords: migration nil object int integer
Cc:

Description

Summary

I recently was working on adding a migration to an existing table that I'd created as a model (via script/generate). Though it was coded right, the syntax was correct, etc., I received this error:


-- add_column(:users, :industry_id, :int) rake aborted! You have a nil object when you didn't expect it! You might have expected an instance of Array. The error occurred while evaluating nil.[]


I later discovered through some googling and some work that :int won't work for migrations generated through script/generate migration, but it will work for script/generate/model.

Another Way to Explain It

I started off by creating my user object:


[user@host]# script/generate model user


Of course the user model was generated. I then populated the user module, using data types like :int, for example.

(Excerpt)


class CreateUsers < ActiveRecord::Migration

def self.up

create_table "users", :force => true do |t|

# ...

t.column :num_ratings, :int

t.column :total_stars, :int

# ...

end

end

def self.down

drop_table "users"

end

end


rake db:migrate did this absolutely fine. Note specifically the use of :int, NOT :integer.

Later in the development process, I decided I wanted to add a foreign key to this user, called "industry_id" that would reference the ID of the industry in which the user worked. So naturally, I did:


[user@host]# script/generate migration add_industry_to_user


Now this is where things get interesting. My migration source looked like this:


class AddIndustryToUser < ActiveRecord::Migration

def self.up

add_column :users, :industry_id, :int

# Foreign Key

execute("alter table users add constraint fk_user_industry foreign key(industry_id) references industries(id)")

end

def self.down

# Remove the FK

#execute("alter table users drop foreign key fk_user_industry")

remove_column :users, :industry_id

end

end


But, running rake db:migrate gave me no love. In fact, it beat me like a red-headed step-child:


-- add_column(:users, :industry_id, :int) rake aborted! You have a nil object when you didn't expect it! You might have expected an instance of Array. The error occurred while evaluating nil.[]


Through some googling, I discovered that :int is NOT mapped for a standard migration, but only for migrations generated through script/generate model. You have to use the full-out :integer.

I know of at least this discrepancy, but there could be more. As I'm pretty new to rails, I don't know how to look for those (nor do I really want to - I just want to get this app developed!), so I figured it best to let you guys know.

DISCLAIMER: I'm new to rails. I did check the existing ticket pages and saw nothing aptly named that sounded like this issue, so I'm submitting a new ticket. This is NOT an un-fixable problem that you have to diagnose, it's just a developer oversight (easy to happen on such a large project) that should be easily fixable, in theory.

Attachments

helpful_error_messages_when_invalid_attributes_are_passed_on_the_command_line.diff (1.5 kB) - added by danger on 11/10/07 19:31:59.
helpful errors printed to the command line when using invalid attributes

Change History

10/15/07 21:42:20 changed by danger

I can't imagine any reason why we shouldn't accept :int and :integer interchangeably - especially if we already accept them each in some places.

10/18/07 15:47:40 changed by david

  • milestone deleted.

The bug is allowing :int during the migration. We should be using :integer every where.

10/18/07 19:08:24 changed by danger

schema_definitions.rb:258 has a rescue at the end of the line - this seems to be what allows the :int to get passed straight through to the SQL.

10/19/07 09:48:23 changed by Ionex Interactive

Hey all -

I recently just found another issue along the same lines. In my initial migration for a model (user again, in this case) I used the datatype :blob for binary data in the DB. Of course rake db:migrate worked fine. Later on, I decided to play with that field, doing a self.down on a new migration. This migration was generated using script/generate migration NOT "model". I tried the following:

add_column :users, :picture, :blob

But no luck. It gave me another nil object. Changing it to :binary works though.

So for the record: :int - works with model migrations, must use :integer for other migrations :blob - works with model migrations, must use :binary for other migrations

11/10/07 18:30:26 changed by danger

So it seems to be that any bad column type passed inside a create_table block will get pushed right out to the database adapter.

$ ./script/generate model some_model name:wackadoo body:splurgify

# creates:
  def self.up
    create_table :some_models do |t|
      t.wackadoo :name
      t.splurgify :body
      # the above lines hit method_missing on a TableDefinition instance
    end
  end

# If we were to use the older format:
  def self.up
    create_table :some_models do |t|
      t.column :name, :wackadoo
      t.column :body, :splurgify
      # the above lines will make it all the way into a SQL call to the database.  It will barf out with an invalid query
    end
  end

It seems we need some kind of valid key checking right as we read from the command line.

11/10/07 19:31:59 changed by danger

  • attachment helpful_error_messages_when_invalid_attributes_are_passed_on_the_command_line.diff added.

helpful errors printed to the command line when using invalid attributes

11/10/07 19:33:23 changed by danger

  • summary changed from Migrations: :integer works, :int doesn't - datatype discrepancy to [PATCH] Invalid attribute types should not be accepted from the command line.

david: how about this? I've created a patch that intercepts bogus attribute types on the command line before any confusion ensues.