¡No espero que un modelo con NULL como clave foránea pertenezca a algo!Active Record has_many genera sql con clave foránea IS NULL
Tengo la siguiente aplicación de rieles, hormigas de modelado y hormigas (inspiradas en Jozef).
$ rails -v
Rails 3.2.8
$ rails new ant_hill
$ cd ant_hill
Crea los modelos hormiguero y hormigas. Una hormiga puede pertenecer a un hormiguero y un hormiguero puede tener muchas hormigas.
$ rails generate model AntHill name:string
$ rails generate model Ant name:string ant_hill_id:integer
$ vim app/models/ant.rb
$ cat app/models/ant.rb
class Ant < ActiveRecord::Base
belongs_to :ant_hill
end
$ vim app/models/ant_hill.rb
$ cat app/models/ant_hill.rb
class AntHill < ActiveRecord::Base
has_many :ants
end
$ rake db:migrate
== CreateAntHills: migrating =================================================
-- create_table(:ant_hills)
-> 0.0013s
== CreateAntHills: migrated (0.0016s) ========================================
== CreateAnts: migrating =====================================================
-- create_table(:ants)
-> 0.0035s
== CreateAnts: migrated (0.0037s) ============================================
Ejecute el siguiente código en una consola.
$ rails c
Loading development environment (Rails 3.2.8)
Crear un par de hormigas, persistieron, que no pertenece a ningún hormiguero.
1.9.2-p290 :001 > Ant.create! name: "August"
=> #<Ant id: 1, name: "August", ant_hill_id: nil, created_at: "2012-09-27 12:01:06", updated_at: "2012-09-27 12:01:06">
1.9.2-p290 :002 > Ant.create! name: "Bertil"
=> #<Ant id: 2, name: "Bertil", ant_hill_id: nil, created_at: "2012-09-27 12:01:13", updated_at: "2012-09-27 12:01:13">
Ahora ejemplifica un hormiguero, pero no lo guardes todavía.
1.9.2-p290 :003 > ant_hill = AntHill.new name: "Storkullen"
=> #<AntHill id: nil, name: "Storkullen", created_at: nil, updated_at: nil>
Espero que este hormiguero no tenga ninguna hormiga y no lo hace.
1.9.2-p290 :004 > ant_hill.ants
=> []
Todavía espero que el hormiguero no tenga ninguna hormiga pero ahora tiene dos.
1.9.2-p290 :005 > ant_hill.ants.count
(0.1ms) SELECT COUNT(*) FROM "ants" WHERE "ants"."ant_hill_id" IS NULL
=> 2
Igual en este caso, nunca debe generar una consulta que contenga "IS NULL" al tratar con claves externas. Quiero decir que "belongs_to NULL" no puede pertenecer a nada, ¿verdad?
1.9.2-p290 :006 > ant_hill.ants.all
Ant Load (0.4ms) SELECT "ants".* FROM "ants" WHERE "ants"."ant_hill_id" IS NULL
=> [#<Ant id: 1, name: "August", ant_hill_id: nil, created_at: "2012-09-27 12:01:06", updated_at: "2012-09-27 12:01:06">, #<Ant id: 2, name: "Bertil", ant_hill_id: nil, created_at: "2012-09-27 12:01:13", updated_at: "2012-09-27 12:01:13">]
Después de que se conserva, se comporta como se esperaba.
1.9.2-p290 :007 > ant_hill.save!
=> true
1.9.2-p290 :008 > ant_hill.ants.count
(0.4ms) SELECT COUNT(*) FROM "ants" WHERE "ants"."ant_hill_id" = 1
=> 0
1.9.2-p290 :009 > ant_hill.ants.all
Ant Load (0.4ms) SELECT "ants".* FROM "ants" WHERE "ants"."ant_hill_id" = 1
=> []
¿Alguna idea? ¿Es este el comportamiento esperado?
No puedo hacer que se requiera ant_hill_id en este caso porque mi aplicación permite hormigas que no pertenecen a ningún hormiguero. – ludde
usando '.size' debería funcionar en su caso – PinnyM
Para ser claros, ya estoy trabajando en torno a este problema en mi aplicación y reconozco que hay muchas maneras de evitar esto. Simplemente no creo que sea el comportamiento esperado.Cuando algo tiene una clave externa NULL, eso significa que no pertenece a nada. Supongo que podría argumentar que un hormiguero no salvado no es nada desde la perspectiva de la base de datos, pero realmente no. – ludde