2011-12-28 3 views
6

Quello che voglio dire, la costruzione di questo in qualche modo con Rails 3.1: UMLCome gestire condizioni xor, rail, chiavi esterne e un database SQLite?

Se A ha impostato un ID per b_id, non dovrebbe essere possibile impostare un ID per c_id. E sicuramente anche viceversa.

Vorrei poterlo fare a livello di database da una migrazione (controllare il vincolo?). È in qualche modo possibile? Oppure è più economico farlo nel modello con le convalide?

Il mio ambiente:

  • Rubino 1.9.3
  • Rails 3.1.3
  • SQLite 3.7.3

risposta

2

È possibile raggiungere questo obiettivo attraverso le associazioni polimorfiche, ma nemmeno lo schema ha vinto' t assomiglia esattamente a quello che hai, puoi raggiungere lo stesso obiettivo, avere un articolo A appartenere allo B o allo C ma mai a entrambi.

Si può leggere di più qui: http://guides.rubyonrails.org/association_basics.html#polymorphic-associations

Nell'esempio riportato su quel link, A è la loro Picture e Employee e Proudct sei il tuo B e C:

(copiato da fonte linkato sopra):

class Picture < ActiveRecord::Base 
    belongs_to :imageable, :polymorphic => true 
end 

class Employee < ActiveRecord::Base 
    has_many :pictures, :as => :imageable 
end 

class Product < ActiveRecord::Base 
    has_many :pictures, :as => :imageable 
end 
+0

Grazie per la risposta! In combinazione con la risposta di @ Frederick, otterrò una soluzione completa alle mie domande. – Robin

+1

Sarei d'accordo di più con la risposta di @ mynameiscoffey. Avere solo una colonna per la chiave esterna nella tabella 'A', quindi abbiamo' imageable_id' e 'imageable_type' nella tabella A –

0

Scriverò sicuramente convalide per questo: è più semplice fornire buoni messaggi di errore a un utente da una convalida. Vorrei anche eseguire il backup con un vincolo di database. Sembra che i limiti di controllo possano effettivamente fare il lavoro.

Rails non ha supporto per questo che potrei trovare quindi è necessario creare la tabella con sql raw. Dovrai inoltre modificare lo schema di dump dello schema su :sql poiché le rotaie non saranno in grado di produrre uno schema.rb che lo descriva effettivamente.

Ho scritto questa migrazione

class CreateFoos < ActiveRecord::Migration 
    def change 

    execute <<SQL 
     CREATE TABLE foos (
     id INTEGER PRIMARY KEY, 
     x_id INTEGER, 
     y_id INTEGER, 
     constraint xorit check((x_id OR y_id) AND NOT(x_id AND y_id)) 
    ) 
SQL 
    end 
end 

Poi nella console rotaie

Foo.create(:x_id => 1, :y_id => 1) #=> SQLite3::ConstraintException 

Come è possibile creare una riga con né insieme né x_id y_id. Si potrebbe cambiare questo cambiando il vincolo,

(x_id IS NOT NULL OR y_id IS NOT NULL) AND (x_id IS NULL OR y_id IS NULL) 

sembrava funzionare per me

+0

Grazie per la risposta! In combinazione con la risposta di @ mynameiscoffey, otterrò una soluzione completa alle mie domande. – Robin