【问题标题】:Editing a single attribute with more than one form field编辑具有多个表单字段的单个属性
【发布时间】:2012-05-13 17:38:21
【问题描述】:

背景:用户和社区共享一个

has_many:通过

关系。每个社区都有一个标识它的“community_type”字符串(即“Gender”、“City”等)。

目标:在我的编辑表单中,我想允许用户根据社区类型编辑他的 :community_ids。比如:

<%= form_for current_user do |f| %>
<%= f.collection_select(:community_ids, Community.filtered_by("Gender"), :id, :name) %>
<%= f.collection_select(:community_ids, Community.filtered_by("City"), :id, :name) %>
<% end %>

问题在于表单只接受 :community_ids 的最后一个表单字段值——在本例中是“城市”——而不是将所有这些值合并为一个大的 :community_ids 数组。

解决方案:

对于那些感兴趣的人,我最终从以下答案重构了我的模型代码:

  %W[ community1 community2 community3 community4 ].each do |name|
    define_method "#{name}" do
      self.communities.filtered_by("#{name}").map(&:name)
    end
    define_method "#{name}_ids" do
      self.communities.filtered_by("#{name}").map(&:id)
    end
    define_method "#{name}_ids=" do |val|
      self.community_ids += val
    end
  end

【问题讨论】:

  • 一个问题:您是否只想为您的用户选择每种类型中的一种,或者用户可以选择每种类型中的几种(我只是想弄清楚我们的 select_tags 是否是最好的方法)?

标签: ruby-on-rails ruby-on-rails-3 forms has-many-through


【解决方案1】:

您将选择框用于has_many 关系是否有原因?似乎复选框会更合适。如果您想使用选择框,我认为您不能使用FormHelper#select,因为据我所知,它需要一个值,而您的community_ids 是一个数组。这就是为什么它只选择你给它的值之一。

对于选择框(或任何字段),您可以通过将[] 添加到参数名称来组合字段中的值,这告诉 Rails 该参数是一个值数组。您可以使用常规的select_tag 创建字段,并设置参数名称如下:

<%= form_for current_user do |f| %>
  <%= select_tag("user[community_ids][]", options_for_select(Community.filtered_by("Gender").map{|c| [c.name, c.id]}, :selected => current_user.communities.filtered_by("Gender").first.id) %>
  <%= select_tag("user[community_ids][]", options_for_select(Community.filtered_by("City").map{|c| [c.name, c.id]}, :selected => current_user.communities.filtered_by("City").first.id) %>
<% end %>

您也可以采用 Ryan 发送单独参数的方法,但缺点是您的 User 模型必须非常了解存在的社区类型,并且您必须在 @ 中编写单独的逻辑987654328@ 每种社区的模型。这将使您的资源不那么模块化。但如果你这样做,我建议使用伪属性而不是before_save,这样你的community_ids 会自动从params 更新:

class User < ActiveRecord::Base
  ...
  def community_gender_ids=(cg_ids)
    self.community_ids ||= []
    self.community_ids += cg_ids
  end

  def community_city_ids=(cc_ids)
    self.community_ids ||= []
    self.community_ids += cc_ids
  end
  ...
end

然后您的select_tag 调用将如下所示:

<%= form_for current_user do |f| %>
  <%= select_tag("user[community_gender_ids][]", options_for_select(Community.filtered_by("Gender").map{|c| [c.name, c.id]}, :selected => current_user.communities.filtered_by("Gender").first.id) %>
  <%= select_tag("user[community_city_ids][]", options_for_select(Community.filtered_by("City").map{|c| [c.name, c.id]}, :selected => current_user.communities.filtered_by("City").first.id) %>
<% end %>

【讨论】:

  • 有趣。我正在使用这种方法,但不断收到“# 的未定义方法 `community_gender_ids'”错误。我将这些方法放在 user.rb 和 @Ryan 的表单视图中。有什么想法吗?
  • 查看我的答案以扩展 tsherif 的答案。基本上问题是 form_for 帮助器试图预填充应该选择值的选择字段。它正在尝试调用 current_user.community_gender_ids。因为没有“getter”方法,所以它说方法未定义。我为您的答案添加了一些 getter 方法。
  • @neon 我对我的答案进行了一些实质性的修改,我认为应该让事情更清楚,并提出一些其他的方法。如果有帮助,请告诉我。
  • 现在尝试一下,但要回答您的问题 - 用户可以拥有多个特定的 community_types 并且只有一个其他的(如 Gender)
【解决方案2】:

更新以完成 tsherif 的(比我原来的)答案。

view.rb

<%= form_for current_user do |f| %>
  <%= f.collection_select(:community_gender_ids, Community.filtered_by("Gender"), :id, :name, {}, id: 'community-gender-options') %>
  <%= f.collection_select(:community_city_ids, Community.filtered_by("City"), :id, :name, {}, id: 'community-city-options') %>
<% end %>

模型.rb

def community_gender_ids=(cg_ids)
  self.community_ids ||= []
  self.community_ids += cg_ids
end

def community_city_ids=(cc_ids)
  self.community_ids ||= []
  self.community_ids += cc_ids
end

def community_gender_ids
  self.communities.select(:id).where(:community_type => 'gender').map(&:id)
end

def community_city_ids
  self.communities.select(:id).where(:community_type => 'city').map(&:id)
end

或者,您可以编写一些 CoffeeScript/Javascript 来绑定到选择标签并将 ID 添加到隐藏值,然后将其与表单一起提交给服务器。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-18
    • 2017-11-06
    • 1970-01-01
    • 2018-08-05
    • 2023-03-25
    • 1970-01-01
    • 2016-01-20
    相关资源
    最近更新 更多