0

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

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
4

2 回答 2

1

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

视图.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 添加到隐藏值,然后将其与表单一起提交给服务器。

于 2012-04-21T21:10:07.487 回答
1

您是否有理由使用选择框来建立has_many关系?似乎复选框会更合适。如果您想使用选择框,我认为您不能使用FormHelper#select,因为据我所知,它需要一个值,而 yourcommunity_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模型中为每种类型的社区编写单独的逻辑。这将使您的资源不那么模块化。但是,如果您确实这样做,我建议您使用伪属性而不是 abefore_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 %>
于 2012-04-21T21:26:44.090 回答