Ruby on Rails
HowtoUsareSchemiLegacy (Version #2)

Stavo lavorando per mettere un’interfaccia Rails su una vecchia applicazione. Il problema è che molte delle assunzioni fatte da Rails non esistevano nello schema esistente.
set_table_name ‘modulgruppen’

Ci sono un certo numero di tecniche che ci possono aiutare a risolvere questo problema:

  • Configurare environment.rb per fare in modo che non cerchi i nomi delle tabelle al plurale
  • Utilizzando set_table_name per i nomi tabelle che non rispettano la convenzione di rails
  • Utilizzando set_primary_key per quelle tabella le cui chiavi primarie non si chiamano id
  • Utilizzando le viste per i dati in sola lettura
  • Utilizzando le regole (rules) PostgreSQL per permettere gli aggiornamenti sulle viste per i dati modificabili
  • Utilizzando find_by_sql per le interrogazioni arbitrarie complesse o per le tabelle senza chiave primaria
  • Utilizzando before_validate_on_create per le chiavi primarie che non si autogenerano.
  • Generando accessori agli attributi senza i prefissi di colonna

Sono indicati in primo luogo un breve esempio per ogni tecnica, seguito da un esempio carino di utilizzo reale da (Seraphim) che mostra molti di queste tecniche in uso.

Configurare environment.rb per fare in modo che non cerchi i nomi delle tabelle al plurale

Aprite config/environment.rb e scorrete verso il basso il commento fino a “Include your application configuration below”. Aggiungete la linea

ActiveRecord::Base.pluralize_table_names = false

Questo vi permetterà di utilizzare il generatore di scripts se non avete utilizzato dei nomi plurali per i nomi tabelle.

Utilizzando set_table_name per i nomi tabelle che non rispettano la convenzione di rails

Utilizzando il “set_table_name " potete fare in modo che un oggetto ”http://wiki.rubyonrails.com/rails/pages/ActiveRecord" class="existingWikiWord">ActiveRecord si riferisca a qualsiasi tabella voi vogliate.

class Entity < ActiveRecord::Base set_table_name “entity” end

Utilizzando set_primary_key per quelle tabella le cui chiavi primarie non si chiamano id

Se il vostro database utilizza nomi differenti per le sue colonne a chiave primaria, potete chiamare il “set_primary_key” per definire qualsiasi colonna voi vogliate.

class Entity < ActiveRecord::Base set_primary_key “entity_id” end

Utilizzando le viste per i dati in sola lettura

Se avete delle tabelle sul database che assomigliato a questo

create table macchine (macchina_id serial primary key,costruttore_id int, modello_id int); create table costruttori (costruttore_id serial primary key , costruttore_nome text); create table modelli (modello_id serial primary key, modello_name text);

e siete piuttosto sicuri di avere i valori direttamente nell’oggetto macchina, potete scrivere una vista come questa

<pre> -- una vista per descrivere una macchina su rails:-) create view rail_macchine as select macchina_id as id, * from macchine natural join costruttori natural join modelli; </pre>

Allo scopo di lettura, rail_macchine ora dovrebbe agire come un un normale oggetto rails che include il nome del costruttore e del modello.

Utilizzando le regole (rules) PostgreSQL per permettere gli aggiornamenti sulle viste per i dati modificabili

Il sistema “rule” di PostgreSQL vi permette di creare le viste aggiornabili [www.postgresql.org]

Guardare HowtoUsareVistePostgresComeTabelle per istruzioni dettagliate

Utilizzando find_by_sql per le interrogazioni arbitrarie complesse o per le tabelle senza chiave primaria

Se le vostre tabella non hanno delle chiavi primarie logiche potete sempre riservarvi di utilizzare find_by_sql per eseguire delle interrogazioni arbitrarie complesse che non richiedono da nessuna parte una chiave primaria.

<pre> Post.find_by_sql ["SELECT * FROM posts WHERE author = ? AND created > ?", author_id, start_date] </pre>

Utilizzando before_validate_on_create per le chiavi primarie che non si autogenerano.

[Qualcuno mi ha dato questo suggerimento, ma non l’ho ancora provato] ok ho visto questo in molti posti e nella documentazione delle API ma non riesco a farlo funzionare. Qualcuno può creare un esempio di codice reale e dirmi dove inserirlo (es. active record, controller, etc.)? Nello specifico, ho uno schema con una tabella(e) che utilizza l’algoritmo ‘select max(ID_COLUMN)+1 from LEGACY_TABLE’per ottenere l’ID successivo da utilizzare nella chiave primaria. Ho creato un metodo per fare ciò ma Rails sembra voler ottenere questo valore dalla sequence (che non esiste).

Risposta alla domanda qui di sopra (2005-02-03), guardare questa pagina: HowToUsareIDNonGeneratiDalDatabase?

Utilizzando le chiavi primarie composte

Rails non supporta nativamente le chiavi primarie composte (es. primary key(col1, col2)). Qualcuno vorrebbe cortesemente spiegarmi come fare a gestirle?

Le ragioni per utilizzare un chiave primaria composta possono essere:

  • L’utilizzo di uno schema che non è controllato dal programmatore
  • Tabelle in Join (Comprendo che Rails 1.1 ha qualche supporto nativo per questo)
  • Vari tipi di entità deboli
  • Attributi multi valore che avete bisogno di rendere indicizzati (questo è il mio caso; Ho una tabella di voci di tipo dizionario e una tabella word_forms in cui ogni riga mappa una parola all’id di una voce del dizionario. Non riesco a pensare ad una giustificazione per un id separato per ogni form di parola in questo caso. In maniera simile, qualsiasi applicazione in cui volete associare un numero arbitrario di “tags” con ogni riga di un’altra tabella benefecerebbe di una chiave primaria composta, perchè di nuovo, un campo id non servirebbe a nulla.
  • ed altre

Una possibile soluzione per utilizzare le chiavi primarie composte:

Aggiungere una colonna id alla tabella interessata. Fate in modo che questa colonna sia autoincrementante.

E usate set_primary_key ‘id’ sulla vostra classe active record. Nessun bisogno di cambiare la definizio del database. Aggiungere una colonna id dovrebbe ovviare il problema.

Generando accessori agli attributi senza i prefissi di colonna

un breve articolo su questo argomento, il cui codice è il seguente:


class << ActiveRecord::Base

  def set_column_prefix(prefix)
    column_names.each do |name|
      next if name == primary_key

      if name[/#{prefix}(.*)/e]
        a = $1

        define_method(a.to_sym) do
          read_attribute(name)
        end

        define_method("#{a}=".to_sym) do |value|
          write_attribute(name, value)
        end

      end
    end
  end
end

E viene utilizzato come:


class NewsSection < ActiveRecord::Base
  set_table_name 'nact_news_section'
  set_primary_key 'ns_id'
  set_column_prefix 'ns_'
end

Potete utilizzare questa tecnica per mappare qualsiasi tipo di fastidio sistematico nei nomi delle colonne.

Esempio di codice in applicazioni reali: Sistemare i modelli per allinearsi ai dati (Seraphim)

Di seguito è spiegato come sistemare i modelli.

Qui, alla casa di pubblicazione, abbiamo un database legacy che ho pensato di agganciare a Rails. La parte rilevante dello schema appare più o meno come questo (i nomi sono stati cambiati per proteggere il colpevole):

CREATE TABLE people ( p_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, p_Title VARCHAR, p_FirstName VARCHAR, p_LastName VARCHAR, …); CREATE TABLE bookentries ( BookID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, PersonID INT, BookText TEXT, …); CREATE TABLE books ( ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, BookName VARCHAR, …); CREATE TABLE office ( o_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, o_Title VARCHAR, o_Address TEXT, city_id INT, …); CREATE TABLE city ( city_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, city_name VARCHAR, …); CREATE TABLE peoplelink ( ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, p_ID INT, o_ID INT );

Stiamo collezionando delle registrazioni riguardo alle persone e in quale directory vanno e di quale tipo. Per ogni persona (person) in ogni libro(book), abbiamo bisogno di essere in grado di collezionare le informazioni di entrambi e dei loro uffici, e delle informazioni specifiche alle loro registrazioni nel libro.

Prima di iniziare a poterci preoccupare delle relazioni, dobbiamo definire prima alcuni principi base. In primo luogo Rails necessita di sapere come trovare i dati – gli dobbiamo dire i nomi tabelle e gli indici. Questo viene fatto sovrascrivendo i metodi \ActiveRecord::Base.table_name() e primary_key in questo modo:

class Office < ActiveRecord::Base
set_table_name “office”
set_primary_key “o_ID”
end

…e via dicendo per ognuna delle nostre quattro classi.

Fatto questo, possiamo iniziare a lavorare sulle relazioni.

Le relazioni da implementare sono le seguenti:

  • office appartengono a (belongs to) city
  • person hanno molti (has many) offices
  • office hanno molti (has many) people
  • person hanno molti (has many) books
  • book hanno molti (has many) people

Qui c’è come funziona in Rails. Abbiamo quattro modelli base, Person, Office, City e Book. La classe Person has_and_belongs_to_many (ha e appartiene a molti) Offices (Uffici), e has_and_belongs_to_many (ha e appartiene a molti) Books (Libri). la classe Office (Ufficio) belongs_to (appartiene a) a una City (Città), e la classe City (Città) has_many (ha molti) Offices (Uffici).
Iniziamo dal più semplice. Per dire che un Office appartiene a una classe City, facciamo:

belongs_to :city, :foreign_key=> “city_id”

in testa al file office.rb. La definizione :foreign_key @ dice ad \ActiveRecord di cercare il campo @city_id nella tabella mappata alla classe office. Per un caso, questo campo ha lo stesso nome che ActiveRecord si aspetterebbe di trovare
La relazione inversa è:

has_many :offices, :foreign_key => ‘city_id’

in testa al file city.rb. Ora, poichè questa è una relazione di tipo has_many, la definizione della :foreign_key dice ad \ActiveRecord di guardare nella tabella mappata ad office.

Le relazioni molti a molti non sono molto più complicate.

has_and_belongs_to_many :offices, :join_table => peoplelink’, \ :foreign_key => ‘p_ID’, :association_foreign_key => ‘o_ID’

Questo va dentro il file person.rb. La definizione della :foreign_key e della :association_foreign_key si riferiscono entrambe ai nomi campi all’interno della tabella peoplelink. Può risultare utile definire il contrario, ma non lo farò qui. Dovrebbe essere abbastanza ovvio.

Per renderlo chiaro, la relazione finale, tra people e books, è definita in questo modo:

has_and_belongs_to_many :books, :join_table => ‘bookentries’, \ :foreign_key => ‘PersonID’, :association_foreign_key => ‘BookID’

Che fa in modo che tutto abbia un senso, ma lo scaffold non leggerà le FK nello schema originale del database? Sono un pò confuso riguardo al punto d’entrata di un grande schema che ha già le proprie chiavi definite. Da qualche altra parte ho letto che si deve fisicamente definire un campo di connessione in una relazione uno a molti per fare in modo che scaffold funzioni. E’ questo il caso?

Qual’è il modo più semplice per forzare il downcasing degli attributi di un Modello per una tabella che ha i nomi dei propri campi definiti in maniera mista o tutti maiuscoli?

Ricevete degli errori di Segmentation Faults con i databases Legacy?

Questa era il mio problema. Rails funzionava perfettamente con un database “rails” ma quando ho provato a connetterlo con un database legacy si incrocchiava e bruciava. Dopo settimane di perdita di capelli ho fatto questo piccolo passo.

gem uninstall mysql

Ho poi installato gli ultimi bindings ruby-mysql da
qui
Questo ha risolto i problemi con mysql4.1+ che avevo.

Bath and Shower
Fragrance
Gift Sets
Hair Care
Makeup
Men’s Grooming
Shaving and Hair Removal
Skin Care
Tools and Accessories

Baby Apparel
Baby Bathing & Skin Care
Baby Bedding
Baby Car Seats
Baby Diapering
Baby Feeding
For Moms
Baby Furniture
Baby Gear
Baby Gifts
Baby Health & Baby Care
Nursery Décor
Potty Training
Baby Safety
Baby Strollers

Stavo lavorando per mettere un’interfaccia Rails su una vecchia applicazione. Il problema è che molte delle assunzioni fatte da Rails non esistevano nello schema esistente.
set_table_name ‘modulgruppen’

Ci sono un certo numero di tecniche che ci possono aiutare a risolvere questo problema:

  • Configurare environment.rb per fare in modo che non cerchi i nomi delle tabelle al plurale
  • Utilizzando set_table_name per i nomi tabelle che non rispettano la convenzione di rails
  • Utilizzando set_primary_key per quelle tabella le cui chiavi primarie non si chiamano id
  • Utilizzando le viste per i dati in sola lettura
  • Utilizzando le regole (rules) PostgreSQL per permettere gli aggiornamenti sulle viste per i dati modificabili
  • Utilizzando find_by_sql per le interrogazioni arbitrarie complesse o per le tabelle senza chiave primaria
  • Utilizzando before_validate_on_create per le chiavi primarie che non si autogenerano.
  • Generando accessori agli attributi senza i prefissi di colonna

Sono indicati in primo luogo un breve esempio per ogni tecnica, seguito da un esempio carino di utilizzo reale da (Seraphim) che mostra molti di queste tecniche in uso.

Configurare environment.rb per fare in modo che non cerchi i nomi delle tabelle al plurale

Aprite config/environment.rb e scorrete verso il basso il commento fino a “Include your application configuration below”. Aggiungete la linea

ActiveRecord::Base.pluralize_table_names = false

Questo vi permetterà di utilizzare il generatore di scripts se non avete utilizzato dei nomi plurali per i nomi tabelle.

Utilizzando set_table_name per i nomi tabelle che non rispettano la convenzione di rails

Utilizzando il “set_table_name " potete fare in modo che un oggetto ”http://wiki.rubyonrails.com/rails/pages/ActiveRecord" class="existingWikiWord">ActiveRecord si riferisca a qualsiasi tabella voi vogliate.

class Entity < ActiveRecord::Base set_table_name “entity” end

Utilizzando set_primary_key per quelle tabella le cui chiavi primarie non si chiamano id

Se il vostro database utilizza nomi differenti per le sue colonne a chiave primaria, potete chiamare il “set_primary_key” per definire qualsiasi colonna voi vogliate.

class Entity < ActiveRecord::Base set_primary_key “entity_id” end

Utilizzando le viste per i dati in sola lettura

Se avete delle tabelle sul database che assomigliato a questo

create table macchine (macchina_id serial primary key,costruttore_id int, modello_id int); create table costruttori (costruttore_id serial primary key , costruttore_nome text); create table modelli (modello_id serial primary key, modello_name text);

e siete piuttosto sicuri di avere i valori direttamente nell’oggetto macchina, potete scrivere una vista come questa

<pre> -- una vista per descrivere una macchina su rails:-) create view rail_macchine as select macchina_id as id, * from macchine natural join costruttori natural join modelli; </pre>

Allo scopo di lettura, rail_macchine ora dovrebbe agire come un un normale oggetto rails che include il nome del costruttore e del modello.

Utilizzando le regole (rules) PostgreSQL per permettere gli aggiornamenti sulle viste per i dati modificabili

Il sistema “rule” di PostgreSQL vi permette di creare le viste aggiornabili [www.postgresql.org]

Guardare HowtoUsareVistePostgresComeTabelle per istruzioni dettagliate

Utilizzando find_by_sql per le interrogazioni arbitrarie complesse o per le tabelle senza chiave primaria

Se le vostre tabella non hanno delle chiavi primarie logiche potete sempre riservarvi di utilizzare find_by_sql per eseguire delle interrogazioni arbitrarie complesse che non richiedono da nessuna parte una chiave primaria.

<pre> Post.find_by_sql ["SELECT * FROM posts WHERE author = ? AND created > ?", author_id, start_date] </pre>

Utilizzando before_validate_on_create per le chiavi primarie che non si autogenerano.

[Qualcuno mi ha dato questo suggerimento, ma non l’ho ancora provato] ok ho visto questo in molti posti e nella documentazione delle API ma non riesco a farlo funzionare. Qualcuno può creare un esempio di codice reale e dirmi dove inserirlo (es. active record, controller, etc.)? Nello specifico, ho uno schema con una tabella(e) che utilizza l’algoritmo ‘select max(ID_COLUMN)+1 from LEGACY_TABLE’per ottenere l’ID successivo da utilizzare nella chiave primaria. Ho creato un metodo per fare ciò ma Rails sembra voler ottenere questo valore dalla sequence (che non esiste).

Risposta alla domanda qui di sopra (2005-02-03), guardare questa pagina: HowToUsareIDNonGeneratiDalDatabase?

Utilizzando le chiavi primarie composte

Rails non supporta nativamente le chiavi primarie composte (es. primary key(col1, col2)). Qualcuno vorrebbe cortesemente spiegarmi come fare a gestirle?

Le ragioni per utilizzare un chiave primaria composta possono essere:

  • L’utilizzo di uno schema che non è controllato dal programmatore
  • Tabelle in Join (Comprendo che Rails 1.1 ha qualche supporto nativo per questo)
  • Vari tipi di entità deboli
  • Attributi multi valore che avete bisogno di rendere indicizzati (questo è il mio caso; Ho una tabella di voci di tipo dizionario e una tabella word_forms in cui ogni riga mappa una parola all’id di una voce del dizionario. Non riesco a pensare ad una giustificazione per un id separato per ogni form di parola in questo caso. In maniera simile, qualsiasi applicazione in cui volete associare un numero arbitrario di “tags” con ogni riga di un’altra tabella benefecerebbe di una chiave primaria composta, perchè di nuovo, un campo id non servirebbe a nulla.
  • ed altre

Una possibile soluzione per utilizzare le chiavi primarie composte:

Aggiungere una colonna id alla tabella interessata. Fate in modo che questa colonna sia autoincrementante.

E usate set_primary_key ‘id’ sulla vostra classe active record. Nessun bisogno di cambiare la definizio del database. Aggiungere una colonna id dovrebbe ovviare il problema.

Generando accessori agli attributi senza i prefissi di colonna

un breve articolo su questo argomento, il cui codice è il seguente:


class << ActiveRecord::Base

  def set_column_prefix(prefix)
    column_names.each do |name|
      next if name == primary_key

      if name[/#{prefix}(.*)/e]
        a = $1

        define_method(a.to_sym) do
          read_attribute(name)
        end

        define_method("#{a}=".to_sym) do |value|
          write_attribute(name, value)
        end

      end
    end
  end
end

E viene utilizzato come:


class NewsSection < ActiveRecord::Base
  set_table_name 'nact_news_section'
  set_primary_key 'ns_id'
  set_column_prefix 'ns_'
end

Potete utilizzare questa tecnica per mappare qualsiasi tipo di fastidio sistematico nei nomi delle colonne.

Esempio di codice in applicazioni reali: Sistemare i modelli per allinearsi ai dati (Seraphim)

Di seguito è spiegato come sistemare i modelli.

Qui, alla casa di pubblicazione, abbiamo un database legacy che ho pensato di agganciare a Rails. La parte rilevante dello schema appare più o meno come questo (i nomi sono stati cambiati per proteggere il colpevole):

CREATE TABLE people ( p_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, p_Title VARCHAR, p_FirstName VARCHAR, p_LastName VARCHAR, …); CREATE TABLE bookentries ( BookID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, PersonID INT, BookText TEXT, …); CREATE TABLE books ( ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, BookName VARCHAR, …); CREATE TABLE office ( o_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, o_Title VARCHAR, o_Address TEXT, city_id INT, …); CREATE TABLE city ( city_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, city_name VARCHAR, …); CREATE TABLE peoplelink ( ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, p_ID INT, o_ID INT );

Stiamo collezionando delle registrazioni riguardo alle persone e in quale directory vanno e di quale tipo. Per ogni persona (person) in ogni libro(book), abbiamo bisogno di essere in grado di collezionare le informazioni di entrambi e dei loro uffici, e delle informazioni specifiche alle loro registrazioni nel libro.

Prima di iniziare a poterci preoccupare delle relazioni, dobbiamo definire prima alcuni principi base. In primo luogo Rails necessita di sapere come trovare i dati – gli dobbiamo dire i nomi tabelle e gli indici. Questo viene fatto sovrascrivendo i metodi \ActiveRecord::Base.table_name() e primary_key in questo modo:

class Office < ActiveRecord::Base
set_table_name “office”
set_primary_key “o_ID”
end

…e via dicendo per ognuna delle nostre quattro classi.

Fatto questo, possiamo iniziare a lavorare sulle relazioni.

Le relazioni da implementare sono le seguenti:

  • office appartengono a (belongs to) city
  • person hanno molti (has many) offices
  • office hanno molti (has many) people
  • person hanno molti (has many) books
  • book hanno molti (has many) people

Qui c’è come funziona in Rails. Abbiamo quattro modelli base, Person, Office, City e Book. La classe Person has_and_belongs_to_many (ha e appartiene a molti) Offices (Uffici), e has_and_belongs_to_many (ha e appartiene a molti) Books (Libri). la classe Office (Ufficio) belongs_to (appartiene a) a una City (Città), e la classe City (Città) has_many (ha molti) Offices (Uffici).
Iniziamo dal più semplice. Per dire che un Office appartiene a una classe City, facciamo:

belongs_to :city, :foreign_key=> “city_id”

in testa al file office.rb. La definizione :foreign_key @ dice ad \ActiveRecord di cercare il campo @city_id nella tabella mappata alla classe office. Per un caso, questo campo ha lo stesso nome che ActiveRecord si aspetterebbe di trovare
La relazione inversa è:

has_many :offices, :foreign_key => ‘city_id’

in testa al file city.rb. Ora, poichè questa è una relazione di tipo has_many, la definizione della :foreign_key dice ad \ActiveRecord di guardare nella tabella mappata ad office.

Le relazioni molti a molti non sono molto più complicate.

has_and_belongs_to_many :offices, :join_table => peoplelink’, \ :foreign_key => ‘p_ID’, :association_foreign_key => ‘o_ID’

Questo va dentro il file person.rb. La definizione della :foreign_key e della :association_foreign_key si riferiscono entrambe ai nomi campi all’interno della tabella peoplelink. Può risultare utile definire il contrario, ma non lo farò qui. Dovrebbe essere abbastanza ovvio.

Per renderlo chiaro, la relazione finale, tra people e books, è definita in questo modo:

has_and_belongs_to_many :books, :join_table => ‘bookentries’, \ :foreign_key => ‘PersonID’, :association_foreign_key => ‘BookID’

Che fa in modo che tutto abbia un senso, ma lo scaffold non leggerà le FK nello schema originale del database? Sono un pò confuso riguardo al punto d’entrata di un grande schema che ha già le proprie chiavi definite. Da qualche altra parte ho letto che si deve fisicamente definire un campo di connessione in una relazione uno a molti per fare in modo che scaffold funzioni. E’ questo il caso?

Qual’è il modo più semplice per forzare il downcasing degli attributi di un Modello per una tabella che ha i nomi dei propri campi definiti in maniera mista o tutti maiuscoli?

Ricevete degli errori di Segmentation Faults con i databases Legacy?

Questa era il mio problema. Rails funzionava perfettamente con un database “rails” ma quando ho provato a connetterlo con un database legacy si incrocchiava e bruciava. Dopo settimane di perdita di capelli ho fatto questo piccolo passo.

gem uninstall mysql

Ho poi installato gli ultimi bindings ruby-mysql da
qui
Questo ha risolto i problemi con mysql4.1+ che avevo.

Bath and Shower
Fragrance
Gift Sets
Hair Care
Makeup
Men’s Grooming
Shaving and Hair Removal
Skin Care
Tools and Accessories

Baby Apparel
Baby Bathing & Skin Care
Baby Bedding
Baby Car Seats
Baby Diapering
Baby Feeding
For Moms
Baby Furniture
Baby Gear
Baby Gifts
Baby Health & Baby Care
Nursery Décor
Potty Training
Baby Safety
Baby Strollers