无法使具有 has_one 关联的嵌套表单正常工作

发布于 2024-10-31 02:02:56 字数 2113 浏览 4 评论 0原文

我有这些模型:

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

我不知道这是否是正确的方法,但看起来不错。

I have these models:

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

class City < ActiveRecord::Base
    belongs_to :user
end

This controller action:

   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

and this view:

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

I am trying to allow the user to select a city from the list of already added cities. I am trying to present him a select. The select part it works, but the generated html code for it, looks like this:

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

Notice that it's name doesn't have attribute anywhere. So, when I try to save it, I get this error:

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

How can I fix this?

EDIT: there is some progress, I tried to change the fields_for to this:

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

and now, the html seems to generate correctly. But I get this error now:

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

I have no idea what to do next.

EDIT2: overriding the city_attributes= method seems to work:

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

I don't know if it's the way to go, but it seems good.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

无人问我粥可暖 2024-11-07 02:02:56

看看这个与你的问题相似的问题:
Rails 3:“accepts_nested_attributes_for”如何工作?

实际上,由于城市已经存在,我认为这里不需要嵌套形式。

尝试替换

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

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

更新后的评论

您可以更改与的关系(并相应地更新数据库方案)

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

Have a look at this question that seems similar to yours :
Rails 3: How does "accepts_nested_attributes_for" work?

Actually, since the Cities already exsit, I think there is no need for nested forms here.

Try Replacing

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

With

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

Updated afters comments

Could you change your relationship with (and update database scheme accordingly)

class User < ActiveRecord::Base
    belongs_to :city
end

class City < ActiveRecord::Base
    has_many :users
end

And then try using:

<%= f.collection_select :city_id, City.all,:id,:name %>
情绪少女 2024-11-07 02:02:56

您还可以在视图中执行

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

,然后将虚拟属性添加到您的 User 模型:

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 时,都会“保存”关联的 City 模型。然而,这个解决方案使您的控制器和视图保持美观和干净。

注意:您可能还需要考虑传递给 setter 方法的空白 ID。

You could also do a

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

in your view and then add virtual attributes to your User model:

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

  def city_id
    city.id
  end
end

This might not be very clean, since the associated City model is "saved" whenever assigning an ID to some_user.city_id. However, this solution keeps your controller and view nice and clean.

Note: you might also want to account for a blank ID being passed in to the setter method.

_畞蕅 2024-11-07 02:02:56

试试这个

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

Try this

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文