1
votes

I've got a table that includes a column named "valid". This has caused a problem after updating to Rails 2. ActiveRecord is expecting "def valid?" to do validation, not return a boolean value from the database.

How do I work around this problem? Is renaming the column my only option?

4

4 Answers

2
votes

As documented elsewhere, there are things you can do, but I'm going to suggest that they're probably going to be more trouble in the long run than biting the bullet and renaming the column.

If your database is not open to other apps, that is - otherwise you're just going to suffer to some extent whatever you do...

Why rename? One of the greatest benefits that we get from Rails is convention over configuration. The "magic", if you will. (Some say that it's actually a bad thing, but go with me one this). If you retain a column named "valid", then nyou're making your models inconsistent: this one needs to work differently from the others and that's bad. Or you could monkey-patch ActiveRecord::Base perhaps, so then all your models work the same but your app no longer follows convention.

From personal experience: I created a column named "user_id" which ActiveRecord, by convention, considered a foreign key (as it does anything ending in "_id"). I coded around it, which I now think was a mistake. Another item on the to-do list...

It's not necessarily wrong to go against Rails conventions: there are plenty of places where you can do so and they're well-documented. On the ActiveRecord side, many are specifically designed to reduce difficulty in connecting to legacy database schemas, for example. Take a good look at the pros and cons, as you're obviously doing, and weigh up your options.

2
votes

I can prevent the crash by adding the following to my model, but it's not entirely satisfactory:

class << self
  def instance_method_already_implemented?(method_name)
    return true if method_name == 'valid?'
    super
  end
end
0
votes

Do you need to see the column in your model? If not, overriding ActiveRecord::Base.columns will do the trick...

def self.columns
  super.delete_if {|c| c.name == 'valid' }
end
0
votes

You can access the attribute through the [] notation:

row[:valid] = "foo"

You'll get the DangerousAttributeError if you try to initialize an object like this:

row = MyModel.new :valid => "foo"

To prevent that, you can define an attribute setter for valid, like this:

def valid=(x)
  self[:valid] = x
end

The valid? method will still be for row validation. You could define a different question method, like val? to get at the boolean, like this:

def val?
  query_attribute('valid')
end

Now you can use row.val? to test the boolean