使用多个表单域编辑单个属性

时间:2012-04-21 20:33:34

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

背景:用户和社区共享

  

has_many:通过

的关系。每个社区都有一个“community_type”字符串,用于标识它(即“性别”,“城市”等)。

目标:在我的编辑表单中,我想允许用户根据社区类型编辑他的: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 - 在这种情况下是“City” - 而不是将它们全部合并为一个大的: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

2 个答案:

答案 0 :(得分:1)

更新以完成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 %>

model.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添加到隐藏值,然后使用表单将其提交给服务器。

答案 1 :(得分: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模型必须非常了解存在的社区类型,你必须编写单独的逻辑每种类型社区的User模型。这将使您的资源更少模块化。但是,如果你这样做,我建议使用伪属性而不是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 %>