Czy zapisywać dodatkowe informacje

Mam modele:

City: zip_code:string, name:string, commune:references
Commune name:string district:references
District: name:string, province: references
Province name:string

Czy model User powinien wyglądać tak:
User name:string city:references

A w widoku User
@user.name
@user.city.zip_code
@user.city.name
@user.city.commune.name
@user.city.commune.district.name
@user.city.commune.district.province.name

czy model User powinien wyglądać tak:
User name:string, city:references, commune:references, district:references, province:references

a w widoku User:

@user.name
@user.city.zip_code
@user.city.name
@user.commune.name
@user.district.name
@user.province.name

Które podejście jest bardziej poprawne.

Pozdrawiam

To zależy. Zasada Demeter (https://en.wikipedia.org/wiki/Law_of_Demeter) mówi, że wywołanie takie jak @user.city.commune.district.province.name nie powinno mieć miejsca, bo powoduje, że model User posiada wiedzę o wewnętrznej implementacji kilku innych nie bezpośrednio powiązanych obiektów: Commune, District, Province. Zgodnie z tą zasadą możesz wprowadzić coś takiego:

[code]class User
def province_name
city.province_name
end
end

class City
def province_name
commune.province_name
end
end

class Commune
def province_name
district.province_name
end
end

class District
def province_name
district.province.name
end
end[/code]
Będziesz miał też wtedy znormalizowaną bazę danych.

Jednakże w tej sytuacji uzyskanie province_name dla użytkownika jest dosć skomplikowanym zapytaniem do bazy i może być kosztowne. Jeśli wykonujesz to często i nie chcesz z jakichś powodów tego keszować, to zdenormalizowanie bazy danych może być dobrym rozwiązaniem.

Denormalizacja, czyli masz na myśli mój drugi wariant?

Tak. (https://en.wikipedia.org/wiki/Denormalization)

Pamiętaj, że denormalizacja bazy danych zwiększa jej stopień skomplikowanie i należy mieć dobry powód, żeby ją wprowadzać. Premature optimization i takie tam.

Przykład który podałem jest dobrym powodem, czy może całkiem inaczej powinno się do tego podejsć?

Skorzystaj z delagate. Skoro nie jesteś w stanie określić czy to zbyt obciąża bazę danych, to najwyraźniej nie obciąża.

Sądzę że to nie będzie obciążać bazy danych ponieważ jest to aplikacja lokalna, intranetowa na której w porywach będzie pracowało 20 osób w jednym momencie.

delegate lub prezenterem:

[code=ruby]# app/presenters/user/some_action_presenter.rb
module User
class SomeActionPresenter
def initialize(user)
@user = user
def

def province
  @user.city.commune.district.province.name
end

end
end

app/controllers/users/user_controller.rb

def some_action
@user = …
@presenter = User::SomeActionPresenter(@user)
end

app/views/users/some_action.html.erb

<%= @presenter.province %>[/code]
No i ten name można choćby zaliasować na to_s i wtedy bez .name używać w widokach.

Z punktu widzenia bazy danych, wychodzi na to że pierwsze podejście jest lepsze. Nic nie stoi na przeszkodzie żebyś sobie oddelegował atrybuty do modelu powiązanego, albo zrobił jakiegoś presentera.

Reasumując,

Bazę trzymać znormalizowaną.

City: zip_code:string, name:string, commune:references
Commune name:string district:references
District: name:string, province: references
Province name:string

User name:string city:references

I aby nie tworzyć user.commune.district.province użyć delegate?