Duda sobre eliminación de un registro c on registros asocia


#1

Buenas, me ha surgido una duda:

Si tengo una tabla Personas y otra perros que está asociada a persona.

Creo una persona: Id: 1 nombre: luis
Creo un perro para esa persona: id : 1 nombre: perrito persona_id: 1

Borro persona y salta una excepción de sql

Mi pregunta es: ¿Hay algún método ya implementado en rails para que
valide
que la persona no tenga perros asociados?

Gracias


#2

Acabo de hacer la misma pregunta que tu en el mismo minuto :slight_smile:


#3

On Feb 23, 2007, at 2:19 PM, Luis V. wrote:

Buenas, me ha surgido una duda:

Si tengo una tabla Personas y otra perros que está asociada a persona.

Creo una persona: Id: 1 nombre: luis
Creo un perro para esa persona: id : 1 nombre: perrito persona_id: 1

La regla es:

Cada vez que tus dedos tecleen has_many|has_one, te ha de saltar un
trigger en la cabeza que te haga tomar una decision sobre la
opcion :dependent.

– fxn


#4

Aprovecho el hilo para preguntar …
no hay un :dependent => :reject ?
La verdad que consulte la api y solo veo :destroy, :delete_all o
:nullify

Silvio

El día 23/02/07, Xavier N. removed_email_address@domain.invalid escribió:


#5

Lo acaban de responder en otro mail … esto me pasa por leer de atras
para
adelante.
Silvio

El día 23/02/07, Silvio Q. removed_email_address@domain.invalid escribió:


#6

On Feb 23, 2007, at 5:12 PM, Silvio Q. wrote:

Aprovecho el hilo para preguntar …
no hay un :dependent => :reject ?

Con http://www.redhillconsulting.com.au/
rails_plugins.html#foreign_key_associations las migrations normales
crean foreign keys transparentemente en aquellas bases de datos que
las soportan. Nosotros lo usamos en todos los proyectos.

– fxn


#7

Hola,

Precisamente he estado peleándome con los tres plugins de redhill
estos dias (versiones para rails 1.1.6):

redhillonrails_core
foreign_key_associations
foreign_key_migrations

Dada la siguiente migración:

class AddForeignKeys < ActiveRecord::Migration
def self.up

add_column :systems, :zone_id, :string

add_column :ips, :zone_id, :string
add_column :ips, :mac_id, :string
add_column :macs, :system_id, :string
add_column :macs, :port_id, :string
add_column :ports, :system_id, :string

=begin
add_foreign_key :systems, :zone_id, :zones, :id, :on_delete =>
:set_null, :on_update => :cascade
add_foreign_key :ips, :zone_id, :zones, :id, :on_delete => :set_null,
:on_update => :cascade
add_foreign_key :ips, :mac_id, :macs, :id, :on_delete => :set_null,
:on_update => :cascade
add_foreign_key :macs, :system_id, :systems, :id, :on_delete =>
:set_null, :on_update => :cascade
add_foreign_key :macs, :port_id, :ports_id, :id, :on_delete =>
:set_null, :on_update => :cascade
add_foreign_key :ports, :system_id, :systems, :id, :on_delete =>
:set_null, :on_update => :cascade
=end
end

def self.down
remove_column :systems, :zone_id
remove_column :ips, :zone_id
remove_column :ips, :mac_id
remove_column :macs, :system_id
remove_column :macs, :port_id
remove_column :ports, :system_id
end
end

Me falla al intentar establecer la FK (añade bien la columna
previamente):

$ rake migrate
(in /home/brainstorm/uni/PFC/rubynac/railsnac)
== AddForeignKeys: migrating

– add_column(:systems, :zone_id, :string)
rake aborted!
Mysql::Error: Can’t create table
‘./railsnac_development/#sql-3632_2c.frm’ (errno: 150): ALTER TABLE
systems ADD FOREIGN KEY (zone_id) REFERENCES zones (id)

(See full trace by running task with --trace)

(En este punto, en la BBDD se ha creado zone_id… la migration no
deberia hacer rollback si ha fallado en un punto intermedio :-? (en la
primera instrucción en este caso))

Yo creo que el schema.db está “correcto” :-S:

ActiveRecord::Schema.define(:version => 6) do

create_table “ips”, :force => true do |t|
t.column “ip”, :string
end

create_table “macs”, :force => true do |t|
t.column “mac”, :string
t.column “oid”, :string
end

create_table “ports”, :force => true do |t|
t.column “location”, :string
t.column “portid”, :string
end

create_table “systems”, :force => true do |t|
t.column “oid”, :string
t.column “username”, :string
end

create_table “zones”, :force => true do |t|
t.column “oid”, :string
t.column “name”, :string
t.column “active”, :string
t.column “hostmaster”, :string
t.column “serial”, :string
t.column “serial_date”, :string
t.column “type”, :string
end
end

Alguna idea de pq falla ? Parte de --trace al hacer migrate:

usr/lib/ruby/gems/1.8/gems/activerecord-1.14.4/lib/active_record/connection_adapters/abstract_adapter.rb:120:in
log' /usr/lib/ruby/gems/1.8/gems/activerecord-1.14.4/lib/active_record/connection_adapters/mysql_adapter.rb:184:inexecute’
/home/brainstorm/uni/PFC/rubynac/railsnac/config/…/vendor/plugins/redhillonrails_core/lib/red_hill_consulting/core.rb:56:in
add_foreign_key' /home/brainstorm/uni/PFC/rubynac/railsnac/config/../vendor/plugins/foreign_key_migrations/lib/red_hill_consulting/foreign_key_migrations.rb:30:inadd_column’
/usr/lib/ruby/gems/1.8/gems/activerecord-1.14.4/lib/active_record/migration.rb:273:in
send' /usr/lib/ruby/gems/1.8/gems/activerecord-1.14.4/lib/active_record/migration.rb:273:inmethod_missing’
/usr/lib/ruby/gems/1.8/gems/activerecord-1.14.4/lib/active_record/migration.rb:257:in
say_with_time' /usr/lib/ruby/1.8/benchmark.rb:293:inmeasure’
/usr/lib/ruby/gems/1.8/gems/activerecord-1.14.4/lib/active_record/migration.rb:257:in
say_with_time' /usr/lib/ruby/gems/1.8/gems/activerecord-1.14.4/lib/active_record/migration.rb:271:inmethod_missing’
./db/migrate//007_add_foreign_keys.rb:4:in real_up' /usr/lib/ruby/gems/1.8/gems/activerecord-1.14.4/lib/active_record/migration.rb:210:insend’

Saludos & thx !


#8

On Feb 24, 2007, at 1:40 PM, brainstorm wrote:

‘./railsnac_development/#sql-3632_2c.frm’ (errno: 150): ALTER TABLE
systems ADD FOREIGN KEY (zone_id) REFERENCES zones (id)

La tabla zones existe en el momento de ejecutar esa migration?

– fxn


#9

On Feb 24, 2007, at 2:42 PM, brainstorm wrote:

Si, existe con todas las columnas creadas (comprobado con phpmyadmin).

Es muy raro, te es posible tirar para atras el esquema y volver a
ejecutar db:migrate desde un punto en el que sabes que esta consistente?

– fxn


#10

No, hago “rake migrate VERSION=6” (esquema justo anterior) y se queda
igual (porque no ha conseguido migrar a 7 (AddForeignKeys))
completamente.

Tengo que ir a la DB, y borrar manualmente “zone_id” de “systems”. Sino:

$ rake migrate
(in /home/brainstorm/uni/PFC/rubynac/railsnac)
== AddForeignKeys: migrating

– add_column(:systems, :zone_id, :string)
rake aborted!
Mysql::Error: Duplicate column name ‘zone_id’: ALTER TABLE systems ADD
zone_id varchar(255)

Lo dicho: no me hace rollback al fallar la migración :frowning:


#11

Por cierto, en los modelos tengo:

class Zone < ActiveRecord::Base
has_many :ips, :dependent => true
has_many :systems, :dependent => true
end

class System < ActiveRecord::Base
has_many :macs, :dependent => true
has_many :ports, :dependent => true # Multihoming
has_many :ips, :dependent => true # IP aliasing
(…)

Siguiendo la el consejo de Xavier sobre los “dependent”…


#12

Si, existe con todas las columnas creadas (comprobado con phpmyadmin).


#13

On Feb 24, 2007, at 4:03 PM, brainstorm wrote:

No, hago “rake migrate VERSION=6” (esquema justo anterior) y se queda
igual (porque no ha conseguido migrar a 7 (AddForeignKeys))
completamente.

OK, el siguiente paso es reproducir esto con un ejemplo minimo.
Podrias por favor crear una aplicacion 1.1.6 nueva con dos migrations
minimas donde esto suceda y enviar esas migrations? Envia tambien por
favor la version del plugin.

– fxn


#14

Ok, he probado con:

self.transaction do
add_column :systems, :zone_id, :string
add_column :ips, :zone_id, :string
add_column :ips, :mac_id, :string
add_column :macs, :system_id, :string
add_column :macs, :port_id, :string
add_column :ports, :system_id, :string
end

Pero el efecto es el mismo (crea la columna zone_id en systems y no
hace rollback). Por lo que leo en la API:

“Also have in mind that exceptions thrown within a transaction block
will be propagated (after triggering the ROLLBACK)”

Por tanto entiendo que deberia hacer el rollback tanto si capturo la
excepción como si no :-(… podria ser problema del driver mysql ?
(uso gem ruby mysql 2.7).

Sin embargo, ahora mismo me preocupa bastante más el porqué no puede
establecer correctamente las FK, lo del rollback es un problema
“menor” en mi situación actual :-S

PD: Creo que no lo habia dicho hasta ahora: uso MySQL.

Gracias por la explicación :wink:


#15

Ok, me pongo a ello immediatamente.

Si por la versión del plugin te refieres a los de redhill son estas:

The latest Rails 1.1.6 version of the plugin is available from
svn://rubyforge.org/var/svn/redhillonrails/tags/release-1.1.6/vendor/plugins/foreign_key_migrations
svn://rubyforge.org/var/svn/redhillonrails/tags/release-1.1.6/vendor/plugins/foreign_key_associations
svn://rubyforge.org/var/svn/redhillonrails/tags/release-1.1.6/vendor/plugins/redhillonrails_core

El “plugin”/gema de mysql es 2.7 tal como comentaba en el mail anterior.


#16

On 2/24/07, brainstorm removed_email_address@domain.invalid wrote:

(En este punto, en la BBDD se ha creado zone_id… la migration no
deberia hacer rollback si ha fallado en un punto intermedio :-? (en la
primera instrucción en este caso))

No se que te puede estar pasando, pero preguntas sobre los rollback
cuando fallan las migration y según leí en algún lugar esto no es
posible en muchas bases de datos y Rails por lo tanto no lo hace.

En las BBDD hay dos tipos de comandos SQL, de definición de datos y de
manejo de datos, sólo los segundos pueden ser transaccionales en la
mayoría de BBDD modernas. Crear tablas, indices, añadir columnas,
etcéteras normalmente no pueden ser transaccionales en la mayoría de
BBDD.

No se si puedes rodear las lineas dentro del self.up y self.down por
bloques de transacción. Quizá si tu base de datos soporta
transacciones en ordenes de definición de datos te funcione.

De cualquier forma las migration están pensadas para no fallar en
producción. Si fallan en la base de datos de desarrollo no debería ser
importante (solo molesto). Por eso es muy importante probar las
migration muy bien durante el desarrollo, un fallo en producción puede
ser muy embarazoso.


#17

Oops, he encontrado un thread en la lista inglesa de un railero que le
pasa lo mismo, y al parecer nadie ve la solución :-/:

http://groups.google.com/group/rubyonrails-talk/tree/browse_frm/thread/714e6fb9d63a46ea/5435acaa27caa443?rnum=1&q=foreign+key+plugin&_done=%2Fgroup%2Frubyonrails-talk%2Fbrowse_frm%2Fthread%2F714e6fb9d63a46ea%2F5435acaa27caa443%3Ftvc%3D1%26q%3Dforeign%2Bkey%2Bplugin%26#doc_5435acaa27caa443

Xavier está en el thread también… me vienen unas cuantas preguntas:

Desde cuando usais este plugin ? En 1.1.6 os ha funcionado siempre ?
Siempre lo usais con create_table ? Alguna vez con add_column como es mi
caso ?

Gracias !


#18

He reproducido el error :-! Aqui tienes las migrations que he usado:

brainstorm@brainmachine ~/tmp/fk_killing_me $ cat db/migrate/00*
class CreateMacs < ActiveRecord::Migration
def self.up
create_table :macs do |t|
t.column :mac, :string
end
end

def self.down
drop_table :macs
end
end
class CreateIps < ActiveRecord::Migration
def self.up
create_table :ips do |t|
t.column :ip, :string
end
end

def self.down
drop_table :ips
end
end
class CreateZones < ActiveRecord::Migration
def self.up
create_table :zones do |t|
t.column :name, :string
end
end

def self.down
drop_table :zones
end
end
class AddForeignKeys < ActiveRecord::Migration
def self.up
add_column :macs, :ip_id, :string
end

def self.down
remove_column :macs, :ip_id
end
end

Y exactamente el mismo error:

brainstorm@brainmachine ~/tmp/fk_killing_me $ rake migrate --trace
(in /home/brainstorm/tmp/fk_killing_me)
** Invoke migrate (first_time)
** Invoke db:migrate (first_time)
** Invoke environment (first_time)
** Execute environment
** Execute db:migrate
== AddForeignKeys: migrating

– add_column(:macs, :ip_id, :string)
rake aborted!
Mysql::Error: Can’t create table
‘./fk_killing_me_development/#sql-3632_d0.frm’ (errno: 150): ALTER
TABLE macs ADD FOREIGN KEY (ip_id) REFERENCES ips (id)
/usr/lib/ruby/gems/1.8/gems/activerecord-1.14.4/lib/active_record/connection_adapters/abstract_adapter.rb:120:in
log' /usr/lib/ruby/gems/1.8/gems/activerecord-1.14.4/lib/active_record/connection_adapters/mysql_adapter.rb:184:inexecute’
/home/brainstorm/tmp/fk_killing_me/config/…/vendor/plugins/redhillonrails_core/lib/red_hill_consulting/core.rb:56:in
add_foreign_key' /home/brainstorm/tmp/fk_killing_me/config/../vendor/plugins/foreign_key_migrations/lib/red_hill_consulting/foreign_key_migrations.rb:30:inadd_column’
/usr/lib/ruby/gems/1.8/gems/activerecord-1.14.4/lib/active_record/migration.rb:273:in
send' /usr/lib/ruby/gems/1.8/gems/activerecord-1.14.4/lib/active_record/migration.rb:273:inmethod_missing’
/usr/lib/ruby/gems/1.8/gems/activerecord-1.14.4/lib/active_record/migration.rb:257:in
`say_with_time’

Modelos:

brainstorm@brainmachine ~/tmp/fk_killing_me $ cat app/models/*.rb
class Ip < ActiveRecord::Base
belongs_to :mac
belongs_to :zone
end
class Mac < ActiveRecord::Base
has_may :ips
end
class Zone < ActiveRecord::Base
has_many :ips
end

Gracias por la ayuda !


#19

De los mismos creadores de los plugins de las foreign keys (redhill):

svn://rubyforge.org/var/svn/redhillonrails/tags/release-1.1.6/vendor/plugins/transactional_migrations

“Transactional Migrations is a plugin that ensures your migration
scripts—both up and down—run within a transaction. When used in
conjunction with a database that supports transactional Data
Definition Language (DDL)—such as PostgreSQL—this ensures that if any
statement within your migration script fails, the entire script is
rolled-back.”

Lo he instalado pero … tampoco funciona: al hacer la migration no
hace el up de forma atómica ! :confused:

Hoy no es mi dia con rails :-S


#20

On Feb 24, 2007, at 5:02 PM, brainstorm wrote:

def self.down
def self.down
def self.down
drop_table :zones
end
end
class AddForeignKeys < ActiveRecord::Migration
def self.up
add_column :macs, :ip_id, :string
end

Ah, ya lo veo, es por el esquema. No tiene que ver ni el plugin ni
add_column.

La columna ip_id de la tabla MACS por convenio hace referencia a la
columna id de la tabla IPS, pero esa columna es un entero, no una
cadena. Si querias apuntar al campo ip entonces tendras que
investigar que constraints ha de cumplir una columna de tipo string
para que puedan apuntar FKs a ella, me extrañaria que asi
silvestremente funcione. Aqui dice alguna cosa:

http://dev.mysql.com/doc/refman/5.0/en/innodb-foreign-key-
constraints.html

– fxn