2011-04-07 78 views
4

我有這些模型:無法獲得嵌套形式有HAS_ONE協會工作

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

class City < ActiveRecord::Base 
    belongs_to :user 
end 

此控制器操作:

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 

這種觀點:

<%= 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 %> 

我想以允許用戶從已經添加的城市列表中選擇一個城市。我正試圖給他一個選擇。它的工作原理選擇部分,但它生成的HTML代碼,如下所示:

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

注意,它的名字沒有attribute任何地方。所以,當我嘗試保存它時,出現此錯誤:

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

我該如何解決這個問題?

編輯:有一些進展,我試圖fields_for改成這樣:

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

而現在,HTML似乎正常生成。但我現在得到這個錯誤:

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

我不知道下一步該怎麼做。

EDIT2:重寫city_attributes=方法似乎工作:

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

我不知道這是否是要走的路,但似乎不錯。

+0

謝謝。你節省了我的時間! – oivoodoo 2012-10-25 09:03:06

回答

0

嘗試此

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

+0

我得到這個錯誤:'未定義的方法'city.user_id'爲#<用戶ID:無,名稱:無,created_at:無,updated_at:無> – Geo 2011-04-07 07:26:56

+0

對不起,需要'user.city_id' – Sector 2011-04-07 07:48:37

+0

仍然沒有'工作。 'undefined method'user.city_id'for#<用戶id:nil,name:nil,created_at:nil,updated_at:nil' – Geo 2011-04-07 07:52:53

2

看一看這個問題似乎與你的相似: Rails 3: How does "accepts_nested_attributes_for" work?

其實,既然城市已經存在,我認爲這裏沒有必要嵌套窗體。

嘗試更換

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

隨着

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

更新afters評論

你能不能改變與(和更新數據庫的相應方案)

class User < ActiveRecord::Base 
    belongs_to :city 
end 

class City < ActiveRecord::Base 
    has_many :users 
end 
的關係

然後嘗試使用:

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

是的,這也是我的第一個方法。但是,這給出了這個錯誤:'城市(#37103820)預計,得到字符串(#21183516)'。因爲它會調用'.city'方法,它需要一個City實例。 – Geo 2011-04-07 08:08:25

+0

哎呀,只是意識到,你的用戶不會有city_id 你能不能改變與(和更新數據庫的相應方案) 類用戶<的ActiveRecord :: Base的 belongs_to的你們之間的關係:城市 結束 級市<的ActiveRecord :: Base的 的has_many:用戶 結束 然後嘗試使用: <%= f.collection_select:city_id,City.all,:ID,:名稱%> – LapinLove404 2011-04-07 08:08:42

+0

是的,我知道,扭轉關係的作品,我只是好奇爲什麼嵌套窗體似乎只能用於創建新的關聯,而不是爲了找到現有的關聯。 – Geo 2011-04-07 09:37:32

1

你也可以在你看來做一個

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

,然後虛擬屬性添加到您的用戶模式:

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

    def city_id 
    city.id 
    end 
end 

這可能不是很乾淨,因爲只要將某個ID分配給some_user.city_id,相關城市模型就會「保存」。但是,這種解決方案可以讓您的控制器和視圖更加乾淨。

注意:您可能還需要考慮傳入setter方法的空白ID。