Problem z ActiveRecord i belongs_to

Witam.
Tworzę pierwszy projekt w RoR i mam pewien problem z relacjami pomiędzy tabelami w AR. Mam 2 tabele: user i task. W tabeli task jest klucz obcy responsible_id (dla pola user.id) .
Tak więc w modelu task mam:
belongs_to :user, :foreign_key => “responsible_id”

Pobieranie rekordów z połączonych tabel task i user wykonuje poprzez (btw czy muszę podawać :joins?):
Task.find(:all, :joins => :user, :select => “task.*, user.name AS user”)

Wszystko działa dopóki nie będę chciał dodać nowego użytkownika do tabeli user bo wtedy pojawia się błąd, że nie istnieje task o id usera którego chce dodać. Czy tak jakby relacja działa w drugą stronę.

Co robię źle bo mam wrażenie że czegoś nie rozumiem w związku z relacjami?

pozdrawiam…

[code=ruby]class User < ActiveRecord::Base
has_many :tasks, :foreign_key => “responsible_id”
end

class Task < ActiveRecord::Base
belongs_to :user, :foreign_key => “responsible_id”, :class_name => “User”
end[/code]
Wybieranie tasków z userami

tasks = Task.find(:all, :include => :user)

Nadal mam z tym problem ale od razu nasuwają mi się 3 pytania:

  1. Z tego co czytalem w dokumentacji jeśli nazwa klasy jest taka sama jak nazwa tabeli to mogę ją pominąć. Czy mam rację?
belongs_to :user, :foreign_key => "responsible_id", :class_name => "User"
  1. Czy jeśli użyję belongs_to to muszę dodatkowo definiować has_many dla tabeli nadrzędnej (czy oba wpisy nie powodują tego samego)?
has_many :tasks, :foreign_key => "responsible_id"
  1. Jeśli chce użyć aliasów w tabli dołączanej to muszę chyba użyć :select bo :include dołączy mi po prostu wszystkie kolumny z drugiej tabeli:
tasks = Task.find(:all, :include => :user)

Przepraszam za te pewnie lamerskie pytania ale studiuje od kilku dni dokumentację i liczne przykłady w necie ale jakoś nie mogę znaleźć jednoznacznej odp. na swoje pytania.

pozdrawiam…

  1. Coś mi świta w głowie, że railsy (tylko nie pamiętam która wersja) w takim wypadku ostrzega żeby dodać explicite nazwę klasy, bo w nowszych wersjach sposób jej określania może ulec zmianie. Lepiej moim zdaniem podać nazwę klasy, ale jeśli działa bez to też ok.

  2. Musisz i nie musisz. Jeśli nie chcesz by jakaś klasa wiedziała o relacji to nie dodajesz wpisu. Dodanie asocjacji z jednej strony nie powoduje automatycznie utworzenie z drugiej.

  3. Po co Ci aliasy? Jeśli aliasujesz jakąś kolumnę to wystarczy, że zrobisz tak jak ja proponowałem i dodatkowo zdefiniujesz sobie taką metodę jak nazwa aliasu, która będzie zwracać wartość tej aliasowanej kolumny.

Jeśli zaczynasz od dokumentacji to może być ciężko na początku. Lepiej zaopatrz się w jakąś książkę, a to co jest w internecie przyda Ci się dopiero jak już będziesz miał solidne podstawy.

Nadal mam problem. Przy próbie zapisu nowego rekordu do tabeli user mam błąd, w którym mam info odnośnie nieistniejącego pola passwd (z tabeli user) w tabeli task. Nie wiem dlaczego pole z tabeli user jest szukane w task - nadal wygląda to na błędną relację. Kod mam taki sam jaki podałeś z małą różnicą:

has_many :task, :foreign_key => "responsible_id"

bo u mnie tabela nazywa się task i mam pluralize_table_names = false.

Konkretnie dostaje błąd: ‘undefined method `passwd=’ for #Task:0x415ed6c

pozdrawiam…

powinno być has_many :tasks, a nie :task, musi być liczba mnoga

To i tak nie ma znaczenia bo nadal mam ten sam błąd ale thx za uwagę.

pozdrawiam…

Po co na siłę komplikujesz sobie to wszystko, Railsy są zrobione tak, żeby nie trzeba było nic ustawiać jak to nie jest konieczne.

Nazwij sobie te tabele, users i tasks, a ten klucz obcy user_id i nie będziesz musiał podać tych wszystkich opcji i pewnie zacznie działać.

[quote=bukox]Nadal mam problem. Przy próbie zapisu nowego rekordu do tabeli user mam błąd, w którym mam info odnośnie nieistniejącego pola passwd (z tabeli user) w tabeli task.
Konkretnie dostaje błąd: ‘undefined method `passwd=’ for #Task:0x415ed6c’[/quote]
Pokaż kod który tworzy obiekt Task.

[code]class TaskService

Lista zadan

def self.list(id)
Task.find(
:all,
:include => :user,
:conditions => { :project_id => id },
:order => “start_time ASC”
)
end

Szczegoly zadania

def self.details(id)
Task.find(id)
end

Dodanie zadania

def self.create(data)
@task = Task.new(data)
@task.save
if !@task.errors.empty?
@task.errors.each{|msg|}
end
end

Aktualizacja zadania

def self.update(data)
@task = Task.find(data[‘id’])
@task.update_attributes(data)
if !@task.errors.empty?
@task.errors.each{|msg|}
end
end

Usuniecie zadania

def self.remove(id)
@task = Task.find(id)
@task.destroy
end

end[/code]
PS. Jak się wstawia “kod ruby” zamiast “kod” ?

pozdrawiam…

Podejrzewam, że w zmiennej ‘data’ (metoda self.create) przekazujesz niepoprawne dane, w szczególności klucz o nazwie “passwd”. Stąd błąd o nieznanej metodzie “passwd=”.

Kod wstawia się poprzez
[ code=ruby ]
[ /code ]

Spacje dodane celowo.

Ale problem dotyczy nie dodawania task’a bo to akurat działa prawidłowo a dodania usera i dlatego wydaje mi się, że winne są relacje bo co ma dodawanie usera do task’a i to jeszcze w taki dziwny sposób?

pozdrawiam…

A to źle Cię zrozumiałem. Pokaż więc kod klasy User oraz kod tworzący obiekt usera. Relacje nie powinny mieć to wpływu (chyba że używasz np validates_associated_of …). Btw, próbowałeś z konsoli dodać nowego usera?

[code=ruby]class UserService

Logowanie

def self.login(login,passwd)
User.find(:first, :conditions => [“login = ? AND passwd = ? AND status = ‘active’”, login, passwd])
end

Lista uzytkownikow

def self.list
User.find(:all)
end

Szczegoly uzytkownika

def self.details(id)
User.find(id)
end

Dodanie uzytkownika

def self.create(data)
@user = User.new(data)
@user.save
if !@user.errors.empty?
@user.errors.each{|msg|}
end
end

Aktualizacja uzytkownika

def self.update(data)
@user = Task.find(data[‘id’])
@user.update_attributes(data)
if !@user.errors.empty?
@user.errors.each{|msg|}
end
end

Usuniecie uzytkownika

def self.delete(id)
@user = User.find(id)
@user.destroy
end

end[/code]
Co do dodawania z konsoli to nie probowałem bo nawet nie bardzo wiem jak :frowning:

pozdrawiam…

Twój błąd ewidentnie pokazuje, że próbujesz tworzyć obiekt Task. Zresztą nawet w metodzie update masz:

@user = Task.find(data['id'])

Zapewne powinno być User.

O rany. Ale błąd. Sorki za zamieszanie i dzięki za pomoc.

pozdrawiam…