2011-04-07 4 views
4

Je ces modèles:Ne peut pas obtenir emboîtées avec une association has_one pour travailler

class User < ActiveRecord::Base 
    has_one :city 
    accepts_nested_attributes_for :city 
end 

class City < ActiveRecord::Base 
    belongs_to :user 
end 

Cette action du contrôleur:

def create 
    @user = User.new(params[:user]) 

    respond_to do |format| 
     if @user.save 
     format.html { redirect_to(@user, :notice => 'User was successfully created.') } 
     format.xml { render :xml => @user, :status => :created, :location => @user } 
     else 
     format.html { render :action => "new" } 
     format.xml { render :xml => @user.errors, :status => :unprocessable_entity } 
     end 
    end 
    end 

et ce point de vue:

<%= form_for :user,:url => users_path,:method => :post do |f| %> 
<%= f.fields_for :city do |b| %> 
    <%= b.collection_select :id,City.all,:id,:name %> 
    <% end %> 

    <div class="field"> 
    <%= f.label :name %><br /> 
    <%= f.text_field :name %> 
    </div> 
    <div class="actions"> 
    <%= f.submit %> 
    </div> 
<% end %> 

Je suis en train pour permettre à l'utilisateur de sélectionner une ville dans la liste des villes déjà ajoutées. J'essaie de lui présenter un select. La partie select cela fonctionne, mais le code HTML généré pour elle, ressemble à ceci:

<select name="user[city][id]" id="user_city_id"> 
    <option value="1">One</option> 
    <option value="2">Two</option> 
</select> 

Notez que son nom n'a pas attribute nulle part. Ainsi, quand j'essaye de le sauver, j'obtiens cette erreur:

City(#37815120) expected, got ActiveSupport::HashWithIndifferentAccess(#32969916) 

Comment puis-je résoudre ce problème?

EDIT: il y a des progrès, j'ai essayé de changer le fields_for à ceci:

<%= f.fields_for :city_attributes do |b| %> 
    <%= b.collection_select :id,City.all,:id,:name %> 
<% end %> 

et maintenant, le code html semble générer correctement. Mais j'obtenir cette erreur maintenant:

Couldn't find City with ID=1 for User with ID= 

Je ne sais pas quoi faire.

EDIT2: redéfinissant la méthode city_attributes= semble fonctionner:

def city_attributes=(attribs) 
    self.city = City.find(attribs[:id]) 
end 

Je ne sais pas si c'est le chemin à parcourir, mais il semble bon.

+0

Merci. Tu as sauvé mon temps! – oivoodoo

Répondre

0

Essayez cette

<% = f.select (: CITY_ID, City.all.collect {| p | [p.name, p.id]})%>

+0

Je reçois cette erreur: 'méthode undefined 'city.user_id' pour # ' – Geo

+0

désolé, doit être 'user.city_id' – Sector

+0

Toujours doesn ' t travail. 'méthode indéfinie 'user.city_id' pour # ' – Geo

2

Jetez un oeil à cette question qui ressemble à la vôtre: Rails 3: How does "accepts_nested_attributes_for" work?

En fait, puisque les villes existent déjà, je pense qu'il n'y a pas besoin de formes imbriquées ici.

Essayez de remplacer

<%= f.fields_for :city_attributes do |b| %> 
    <%= b.collection_select :id,City.all,:id,:name %> 
<% end %> 

Avec

<%= f.collection_select :city, City.all,:id,:name %> 

Mis à jour afters commentaires

Pourriez-vous changer votre relation avec (et schéma de base de données mise à jour en conséquence)

class User < ActiveRecord::Base 
    belongs_to :city 
end 

class City < ActiveRecord::Base 
    has_many :users 
end 

Et puis essayez d'utiliser:

<%= f.collection_select :city_id, City.all,:id,:name %> 
+0

Ouais, c'était aussi ma première approche. Mais ceci donne cette erreur: 'City (# 37103820) attendu, a obtenu la chaîne (# 21183516)'. Parce qu'il appellera la méthode '.city', qui attend une instance de City. – Geo

+0

Oops, juste réalisé que vous utilisateur n'aurez pas CITY_ID Pouvez-vous changer votre relation avec (et schéma de base de données mise à jour en conséquence) classe utilisateur LapinLove404

+0

Oui, je sais que l'inversion de la relation fonctionne, je était juste curieux de savoir pourquoi les formes imbriquées ne semblent fonctionner que pour créer de nouvelles associations, et non pour trouver celles qui existent déjà. – Geo

1

Vous pouvez également faire un

<%= f.collection_select :city_id, City.all, :id, :name %>

dans votre vue, puis ajouter des attributs virtuels à votre modèle d'utilisateur:

class User < ActiveRecord::Base 
    ... 
    def city_id(c_id) 
    update_attribute(:city, City.find(c_id)) 
    end 

    def city_id 
    city.id 
    end 
end 

Cette n'est peut-être pas très propre, puisque le modèle City associé est "sauvegardé" lors de l'attribution d'un ID à l'utilisateur some_user.city_id. Cependant, cette solution maintient votre contrôleur et affiche belle et propre.

Remarque: vous pouvez également prendre en compte un ID vide transmis à la méthode setter.

Questions connexes