has_many nightmare

Ian Moody wrote in post #1110472:

Can someone tell me I'm not going mad.

We have a very large rails app, with lots of things like:

# Link model belongs_to :product belongs_to :content belongs_to :member belongs_to :boat

# Product model has_many :links, :foreign_key => :product_id

# Content model has_many :links, :foreign_key => :content_id

# Test Product.new.links.all

If we run this test on Rails 3.0 we get:

SELECT `links`.* FROM `links` WHERE (`links`.product_id = NULL)

If we run this test on Rails 3.2 we get:

SELECT `links`.* FROM `links` WHERE `links`.`product_id` IS NULL

Notice the VERY BIG change in how Rails check for NULL (it may not look like a big change, but it is).

In the first case (3.0) we get NO records, as you would expect on a new record, and as everything in our code assumes.

In the second case (3.2) we get ALL RECORDS that have an empty product_id field.

This is very interesting. The 3.2 version "feels" more correct to me, but I haven't fully thought it through.

This is obviously quite a change.

We use our 'links' table to store many kinds of relationships between objects in our system.

So for a link between a 'Member' and a 'Boat', the product_id field would be blank and just the member_id and boat_id would be filled in.

Under rails 3.0 this all works fine.

Under rails 3.2, EVERY SINGLE use of has_many / has_many :through now returns ALL unrelated records for every query on a new record, simply because of the change in NULL checking.

ps. caps used for highlighting, not shouting.

Does anyone know if this is expected behaviour?

My guess is that the change wasn't arbitrary. I'm pretty sure the change was made for a reason that made sense to the core team at the time.

That being said, unless I'm missing something really obvious I would have used a polymorphic association here:

class Link < ActiveRecord::Base   belongs_to :linkable, :polymorphic => true end

class Product < ActiveRecord::Base   has_many :links, :as => :linkable end

class Content < ActiveRecord::Base   has_many :links, :as => :linkable end