Relacje

Załóżmy, że tabele w mysql wyglądają tak:

tabela druzyny:

id
nazwa

tabela spotkanie:

id
gospodarz_id referense z druzyny(id)
przeciwnik_id referense z druzyny(id)

czy da się pobierać tylko z jednej tabeli druzyny gospodarza_id i przeniwnika_id tak żeby dało się to wyświetlić w widoku ?

pytam bo mi się to nie udaje.

A jak przeglądam tutki to zwykle wystepuje taki uklad, ze ten powyzszy przyklad wykladal by tak:

tabela gospodarz:

id
nazwa

tabela przeciwnik:

id
nazwa

tabela spotkanie:

id
przeciwnik_id
gospodarz_id

i to jest dla mnie sprawa jasna, tylko, że w tabelach gospodarz i przeciwnik to w zasadzie te same drużyny więc lepiej jakby była jednak tabela jak powyżej.

Jeżeli ktoś coś zrozumiał z tego to proszę o odpowiedź.

Jasne, nie ma problemu:

[code=ruby]class Team < ActiveRecord::Base
end

class Game < ActiveRecord::Base
belongs_to :home_team, :class_name :team, :foreign_key :home_team_id
belongs_to :away_team, :class_name :team, :foreign_key :away_team_id
end[/code]

przy tej klasie wywala syntax error

…chyba sobie wziąłem, że tak powiem za trudny projekt jak na początek

Hm, ano widzę błąd. Brakuje => (wydaje mi się że dopisywałem):

[code=ruby]class Team < ActiveRecord::Base
end

class Game < ActiveRecord::Base
belongs_to :home_team, :class_name :team, :foreign_key => :home_team_id
belongs_to :away_team, :class_name :team, :foreign_key => :away_team_id
end[/code]
Następnym razem wklej komunikat błędu.

Ja mam troszkę inne tabele, ale sytax error jest obecnie taki:

C:/instalki/INSTAN~1.0-W/rails_apps/rozgrywki/app/models/club.rb:7: syntax error, unexpected ':', expecting kEND belongs_to :gospodarz, :class_name :club, :foreign_key => gospodarz_id ^ C:/instalki/INSTAN~1.0-W/rails_apps/rozgrywki/app/models/club.rb:7: syntax error, unexpected tASSOC, expecting tCOLON2 or '[' or '.' belongs_to :gospodarz, :class_name :club, :foreign_key => gospodarz_id ^ C:/instalki/INSTAN~1.0-W/rails_apps/rozgrywki/app/models/club.rb:8: syntax error, unexpected ':', expecting kEND belongs_to :przeciwnik, :class_name :club, :foreign_key => przeciwnik_id ^ C:/instalki/INSTAN~1.0-W/rails_apps/rozgrywki/app/models/club.rb:8: syntax error, unexpected tASSOC, expecting tCOLON2 or '[' or '.' belongs_to :przeciwnik, :class_name :club, :foreign_key => przeciwnik_id

class Game < ActiveRecord::Base belongs_to :home_team, :class_name => :team, :foreign_key => :home_team_id belongs_to :away_team, :class_name => :team, :foreign_key => :away_team_id end

No widzisz, poprawiam kod w jednym miejscu, a zostawiam błąd w innym. Ale faktycznie, jeśli sam tego nie wyłapałeś po wklejeniu kod i zobaczeniu błędów interpretera, to skup się póki co może na samym Rubym. Szkoda nerwów sobie szarpać.

Tpl, poznaj może Rubiego i Railsy trochę lepiej - zwłaszcza dokumentację do ActiveRecord i relacji. Bo jeśli nie wyłapałeś od ręki błędów wręcz “ortograficznych” w kodzie Radarka (wysypiaj się, człowieku! :wink: ), to znaczy że trochę jeszcze za słabo z teorią :slight_smile:

Więc sprawa wygląda tak, że przygoda z ruby on rails zaczęła się tydzień temu, nie programowałem nigdy w samym rubym. Przerobiłem kilka tutoriali i na ich wzór chciałem coś sobie stworzyć, ale jeżeli wykracza coś poza to co jest w tutorialach głównie dla początkujących to są schody nie do przeskoczenia dla mnie. Poza tym wszystko w zasadzie co może pomóc początkującemu opiera się na na wersji railsów 1.x, (tak jak książka którą nabyłem: Ruby on rails od podstaw, Holznera). Więc w zasadzie nieźle się musiałem nagimnastykować, żeby coś zadziałało. Dla dla znających railsów - zmiany kosmetyczne, ale dla kogoś kto pierwszy raz ma z tym styczność przepaść :slight_smile:

http://api.rubyonrails.com – ActiveRecord::Associations::ClassMethods i jedziesz :slight_smile: Wystarczy :slight_smile:

[code]class Game < ActiveRecord::Base

belongs_to :club
belongs_to :gospodarz, :foreign_key => :gospodarz_id, :class_name =>“Club”
belongs_to :przeciwnik, :foreign_key => :przeciwnik_id, :class_name =>“Club”

belongs_to :sedziaglowny, :foreign_key => :sedziaglowny_id, :class_name =>“Sedzia”
belongs_to :asystent1, :foreign_key => :asystent1_id, :class_name =>“Sedzia”
belongs_to :asystent2, :foreign_key => :asystent2_id, :class_name =>“Sedzia”
end[/code]
w widoku index.html.erb:

[code]<% for game in @games %>

<%=h game.gospodarz.nazwa %> #śmiga <%=h game.sedziaglowny.nazwisko %> # wyskakuje blad typu The error occurred while evaluating nil.nazwisko ....[/code] w widoku show.html.erb wyświetla się wszystko ok.

i jakoś nie wiem jak temu zaradzić :frowning:

nil.nazwisko

Wywołujesz metodę “nazwisko” na obiekcie nil. Czyli game.sedziaglowny zwraca nil dla któregoś obiektu iteracji. Jeśli pozwalasz na taką możliwość (np mecz odbył się bez sędziego głównego bo dostał w łapę i zapomniał przyjść :wink: ) to musisz sprawdzić to w widoku. Jeśli nie dopuszczasz takiej możliwości to dodaj walidację tego atrybutu w klasie Game. Możesz także dodać obsługę klucza obcego (jeśli używasz mysql to pamiętaj że MyISAM nie obsługuje kluczy obcych).

A za mieszanie nazw polskich i angielskich jakbym mógł to byś bana dostał, ale nie na to forum tylko w ogóle na programowanie. Czy nie czujesz jak to okropnie wygląda?:>

Na marginesie: jak wklejasz kod to oznacz go przez znacznik [ code=ruby ] (bez spacji oczywiście)

dziękuje za cenne wskazówki

Więc jeszcze jedna relacja z którą nie mogę dać sobie rady :frowning:
układ jest taki:

tabela1
id
name

tabela2
id
match_id
home_id
away_id

tabela3
id
match_id

z listy rozwijanej chce pobrać id z tabeli2 i zapisać jako match_id w tabeli3. To tam nie problem, ale problem jest żeby na tej liście rozwijanej pojawiały się home_id + away_id, których wartość jest pobierana z tabeli 1 jako name.

jak to powinno być w modelach ?

Jeśli wklejasz opisy tabel to fajnie żeby były prostsze w odbiorze (‘desc tabela’ w mysql np). Poza tym nie ułatwiasz zrozumienia problemu jeśli usuwasz oryginalne nazwy i zastępujesz je tabela{1,2,3}.

Domyślam się, że home_id i away_id to klucze odonoszące się do tabela1. Tam gdzie generujesz opcje dla selecta podaj taką tablicę:

Tabela2.find(:all, :include => [:home_team, :away_team]).map {|t| [t.home_team.name + "-" + t.away_team.name, t.id] }

:include jest by zapobiec efektowi N+1 zapytań.

Witam
Niedano zacząłem przygodę z railsami i widzę, że tu taki temat o relacjach się trafił.
Mam dwie tabelki

Users
id
nazwa
address_id

Adresses
id

No i chciałbym, żeby była relacja has_one. Rails robi mi migrację, ale w bazie nie widzę żadnego klucza obcego.

class User < ActiveRecord::Base has_one :address, :class_name => :address, :foreign_key => :user_id end
W Address nie mam żadnych wpisów

Jak ma być właściwie skonstruowana relacja by pojawiły się klucze obce?

Migracja przechodzi ok, ale w bazie nie widać, żadnych kluczy obcych

[quote=radarek]Jeśli wklejasz opisy tabel to fajnie żeby były prostsze w odbiorze (‘desc tabela’ w mysql np). Poza tym nie ułatwiasz zrozumienia problemu jeśli usuwasz oryginalne nazwy i zastępujesz je tabela{1,2,3}.

Domyślam się, że home_id i away_id to klucze odonoszące się do tabela1. Tam gdzie generujesz opcje dla selecta podaj taką tablicę:

Tabela2.find(:all, :include => [:home_team, :away_team]).map {|t| [t.home_team.name + "-" + t.away_team.name, t.id] }

:include jest by zapobiec efektowi N+1 zapytań.[/quote]
dziekuje, a jeśli chodzi o nazwy tabel to mam je jeszcze po polskiemu wiec, żeby nie drażnić niektórych :slight_smile: to tak to zapisałem.

[quote=miras]class User < ActiveRecord::Base has_one :address, :class_name => :address, :foreign_key => :user_id end
W Address nie mam żadnych wpisów

Jak ma być właściwie skonstruowana relacja by pojawiły się klucze obce?

Migracja przechodzi ok, ale w bazie nie widać, żadnych kluczy obcych[/quote]
“Definiowanie” kluczy obcych odbywa sie przy tworzeniu struktury bazy.
To ze napiszesz w modelu has_many, czy has_one mowi Railsom gdzie znajduja sie klucze i jak z nich korzystac.

Polecam na poczatek: http://mboffin.com/stuff/ruby-on-rails-data-relationships.png
http://www.slash7.com/cheats/activerecord_cheatsheet.pdf

Nastepnie opis migracji: http://www.programuj.com/wiki/Ruby_on_Rails:_Migracje
I oczywiscie dokumentacja: http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

Twoj przypadek mozna rozwiazac tak:

[code]./script/generate model user name:string address_id:integer
./script/generate model address

class User < ActiveRecord::Base
belongs_to :address
end

class Address < ActiveRecord::Base
has_many :users
end[/code]

Yyyy, Oki, user należy do adresu a adres ma wielu userów ? Trochę dziwna relacja IMHO :slight_smile:

Miras, jeśli user ma mieć tylko 1 adres przypisany to wystarczy, że będziesz miał 2 tabele:

  1. users
  2. addresses

Tabela addresses ma mieć kolumnę user_id:integer

[code=ruby]class User < ActiveRecord::Base
has_one :address
end

class Address < ActiveRecord::Base
belongs_to :user
end[/code]
Jeśli user może mieć więcej niż 1 adres to zmień has_one na has_many :addresses

Taki wariant roiłem wcześniej i też nie pojawiły się klucze w tabelach

Relacje w modelach teraz są takie:

[code]class User < ActiveRecord::Base
has_one :address
end

class Address < ActiveRecord::Base
belongs_to :user
end[/code]
Po migracji mam takie tabele

[code]mysql> describe addresses;
±--------------±-------------±-----±----±--------±---------------+
| Field | Type | Null | Key | Default | Extra |
±--------------±-------------±-----±----±--------±---------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| user_id | int(11) | YES | | NULL | |
| miasto | varchar(255) | YES | | NULL | |
| kod_p | varchar(255) | YES | | NULL | |
| ulica | varchar(255) | YES | | NULL | |
| nr_domu | int(11) | YES | | NULL | |
| nr_mieszkania | int(11) | YES | | NULL | |
| email | varchar(255) | YES | | NULL | |
| tel | int(11) | YES | | NULL | |
±--------------±-------------±-----±----±--------±---------------+
9 rows in set (0.00 sec)

mysql> describe users;
±----------------±-------------±-----±----±--------±---------------+
| Field | Type | Null | Key | Default | Extra |
±----------------±-------------±-----±----±--------±---------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| user_name | varchar(255) | YES | | NULL | |
| hashed_password | varchar(255) | YES | | NULL | |
| salt | varchar(255) | YES | | NULL | |
| nazwisko | varchar(255) | YES | | NULL | |
| imie | varchar(255) | YES | | NULL | |
| firma | varchar(255) | YES | | NULL | |
| nip | varchar(255) | YES | | NULL | |
±----------------±-------------±-----±----±--------±---------------+
8 rows in set (0.00 sec)

mysql>[/code]
Klucze obce poawią się dopiero kiedy wpisuję z palca w migracji

execute "alter table addresses add constraint fk_address_users foreign key (user_id) references users(id)"
Cały czas wydawało mi się, że po to są relację w modelach, żeby nie trzeba było wpisywać SQLa w migracjach, a u mnie to wogóle nie działa. Piszę w Netbeans 6.0RC1. Rails 1.25, Ruby versoin 1,85(java). rails 1.25 dlatego, że iele materiałów i książek jest o tej wersji.