Aktualizacja dwóch modeli z jednego formularza

Mam dwa modele: User i UserProfile w relacji jeden-do-jeden i chcę aktualizować dane tej relacji w jednym formularzu. Z zakładaniem nowego użytkownika poradziłem sobie bez problemu ale aktualizacji nie potrafię zrobić.
Widok formularza:

[code]<% form_for :user, :url => uprofile_user_url(@user), :html => { :method => :put } do |f| %>
<% fields_for :user_profile, @user.user_profile do |up| %>

Real name:
<%= up.text_field :real_name, :size => 60 %>

Contact:
<%= up.text_field :contact, :size => 60 %>

E-mail:
<%= f.text_field :email, :size => 60 %>

Phone:
<%= up.text_field :phone, :size => 60 %>

Comment:
<%= up.text_area :comment, :rows => 10, :cols=>60 %>

<% end %> <%= submit_tag 'Save' %> <% end %>[/code] Akcja uprofile: [code]def uprofile @user=User.find(params[:id], :include=>:user_profile) @user.attributes = params[:user] @user.user_profile.attributes=params[:user_profile] if (@user.valid? && @user.user_profile(&:valid?)) @user.save! @user.user_profile(&:save!) flash[:notice]="User updated" redirect_to user_path(@user) else render :action => 'edit' end end[/code] O ile User aktualizuje się doskonale to User.user_profile jest odporny na wszelkie próby aktualizacji. Sprawdzałem debugerem krok po kroku działanie i niby atrybuty są aktualizowane ale na koniec gdzieś to wszystko ginie. Jak sobe poradzić z tym problemem?

Może używaj normalnych metod zamiast hakerskich wywołań przez symbole, zupełnie tutaj niepotrzebnych?

A możesz to rozwinąć?
Rozwiązanie to znalazłem na forum RoR i wydaje się być całkiem logiczne. Google pytane o ten problem prowadzi do wielu stron ale finalnie i tak trafiam na ten jeden opis.

Nie stosuj takich konstrukcji &:valid?, skąd wogóle ten pomysł?

Zamiast @user.user_profile(&:valid?) używaj @user.user_profile.valid?, natomiast zamiast attributes= używaj update_attributes, czyli
@user.user_profile.update_attributes(params[:user_profile])

if (@user.valid? && @user.user_profile(&:valid?))
@user.user_profile(&:save!)

Gdzie Ty to znalazłeś? Dawno nie widziałem tak “ciekawego” kodu :).

Aktualizacja kilku modeli w jednym formularzu to chyba najczęstszy problem na tym forum :slight_smile:

Poniżej link do screencasta który opisuje bardzo eleganckie i elastyczne rozwiązanie przy pomocy fields_for i faux accessors:

Railscasts Complex Forms

Jak wcześniej pisałem na forum railsowym: http://railsforum.com/viewtopic.php?id=719

Poradziłem sobie może mało elegancko ale działa:

def uprofile @user=User.find(params[:id]) @user.attributes = params[:user] @p=UserProfile.find_by_user_id(params[:id]) @p.attributes=params[:user_profile] if (@user.valid? && @p.valid?) @user.save! @p.save! flash[:notice] = _("User updated") redirect_to user_path(@user) else render :action => 'edit' end end end
Przy okazji … jak widać udało mi się wykorzystać gettext: rozpoznaje preferencje przeglądarki, tłumaczy model i komunikaty validacji.

Jak wcześniej pisałem na forum railsowym: http://railsforum.com/viewtopic.php?id=719[/quote]
I nawet źle przepisałeś…

Jak wcześniej pisałem na forum railsowym: http://railsforum.com/viewtopic.php?id=719[/quote]
I nawet źle przepisałeś…[/quote]
Bo nie przepisałem. Podany przykład dotyczy relacji jeden-do-wielu i nie można go zastosować wprost do relacji jeden-do-jeden. Metody each i all? nie istnieją w przypadku jeden-do-jeden (przynajmniej takie miałem komunikaty) co jest całkiem logiczne. Inna sprawa, że problemem nie były te warunki ale przypisywanie atrybutom wartości z formularza, które gdzieś ginęły.
Zresztą zanim zastosuję rozwiązanie znalezione w sieci to staram się najpierw zrozumieć jak działa i dopiero zastosować. W tym przypadku wydawało mi się całkiem logiczne (poza tą konstrukcją &:symbol). Zadałem pytanie licząc na wytłumaczenie problemu. W końcu to “Zielona szkoła”.

W każdym bądź razie problem już został rozwiązany.