使用 accepts_nested_attributes_for 创建新记录或更新现有记录

4

阅读最新信息的大更新。

大家好,

我的Rails应用中有一个涉及三个表的多对多关系:一个用户表、一个兴趣表和一个join user_interests表,它还有一个评分值,所以用户可以在1-10分的范围内评价他们的每个兴趣。

我基本上是在寻找一种方法让新用户在注册时创建他们的评分,并在将来的某个日期编辑它们,同时与任何其他个人资料信息一起进行编辑。

我尝试遵循这个问题Rails nested form with has_many :through, how to edit attributes of join model?,但我遇到的问题是如何将选择列表与多个兴趣整合在一起进行用户评分。

模型代码:

user.rb
has_many :user_interests, :dependent => :destroy
has_many :interests, :through => :user_interests, :foreign_key => :user_id  
accepts_nested_attributes_for :user_interests

interest.rb
has_many :user_interests, :dependent => :destroy
has_many :users, :through => :user_interests, :foreign_key => :interest_id, :dependent => :destroy

user_interest.rb
belongs_to :user
belongs_to :interest

查看代码:

app/views/user/_form.html.erb
<%= form_for(@user) do |form| %>
  ... user fields
  <%= form.fields_for :user_interests do |ui_form| %>
    ... loop through ALL interests
    <% Interest.all.each do |interest| %>
      <%= ui_form.select :rating, options_for_select(1..10) %>
      <%= ui_form.hidden_field :interest_id, :value => interest.id %>
    <% end %>
  <% end %>
<% end %>

我还在我的控制器的新建/编辑操作中包含了以下内容@user.interests.build.build_interest

我遇到的问题是,当我想要有多个兴趣评分时,只有一个兴趣评分被传递到参数哈希中。此外,我还遇到了Rails抛出的异常。

Interest(#2172840620) expected, got Array(#2148226700)

我错过或错误的微小细节导致了问题吗?
编辑:
我找到了一种强制解决此问题的方法,但需要手动编辑Chrome开发人员工具中的HTML。我的表单元素的:name属性被生成为user[user_interests_attributes][rating],但如果我将其更改为user[user_interests_attributes][][rating],当我更新记录时它将起作用。但是,我无法手动指定与表单对象相关联的表单元素的:name。那么,我该怎么做才能显示传递了多个兴趣评级,而不仅仅是Rails认为的一个?
重大更新:
我进行了一些微小的更改,得到了一个半功能版本:
视图代码:
<% form.fields_for :user_interests do |ui_form| %>
<p>
    <%= ui_form.select :rating, options_for_select(1..5), :selected => :rating %>
    <%= ui_form.label :interest_title %>
    <%= ui_form.hidden_field :interest_id %>
</p>
<% end %>

控制器代码:

def new
  @user = User.new
  Interest.all.each { |int| @user.user_interests.build({ :interest_id => int.id }) }
end

def edit
  @user = @current_user
  Interest.unrated_by_user_id(@user.id).each { |int| @user.user_interests.build({ :interest_id => int.id }) }
end

现在我可以编辑并更新我的用户兴趣,如果没有评分,则创建。但是,当我尝试创建一个新用户时,会出现“用户为空”的错误。此外,我无法访问表单中的任何兴趣属性,以显示用户实际评分的兴趣。有人能帮忙解决这些问题吗?

1个回答

3
你只需要使用@user.interests.build,因为它是一个has_many关系。而build_interest用于has_one/belongs_to关系。
当使用fields_for :user_interests时,你告诉User模型在创建/更新用户时,参数哈希中将包含一个或多个user_interest对象的实例。表单不会创建或更新任何user_interests,但它会发送回一个user_interest_attributes哈希数组,表示表单引用的用户的user_interests。这是一个user_interests评分值的数组,其中没有任何user_interests存在,因为你在表单中引用了它们,这就是你收到错误的原因。
由于你将一个范围传递给select表单助手,因此实际上并未提供任何可供选择的兴趣爱好。select将为user_interests表中的rating列设置一个值,该值介于1和10之间。即使user_interests表具有rating列,也不存在任何user_interest来设置该值。
在select标记的选项哈希中传递:multiple => true将创建一个多选列表,但我认为这不是你想要的。我认为你想要让用户在页面上放置许多感兴趣的项目。
如果确实想让用户选择多个兴趣爱好,则可以按如下方式在has_many :through关系上使用fields_for和accepts_nested_attributes_for:
<%= form_for(@user) do |f| %>
  <% f.fields_for :interest_ids  do |interest| %>
    <ul>
      <% Interest.all.each do |choice,i| %>
      <li class="selection">
        <%= interest.check_box [], { :checked => f.object.user_interest_ids.include?(choice.id) }, choice.id, ''  %>
        <%= interest.label [], choice.name %>
      </li>
    <% end %>
    </ul>
  <% end %>
<% end %>

我正在处理这个问题,看起来我在上面的代码示例中漏掉了我的视图中所有兴趣的循环,我将修改它以反映最初的想法,或许能够更好地解决问题。 - Jimmy
是的,我不想为每个兴趣爱好都设置复选框,而是希望使用下拉菜单为每个兴趣爱好设置评分值。 - Jimmy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接