Rails - 通过单一形式操作has_many与连接模型

时间:2013-06-07 21:29:31

标签: ruby-on-rails

我有以下三种模式:

class Site < AR::Base
  has_many :installed_templates, :as => :installed_templateable, :dependent => :destroy

  accepts_nested_attributes_for :installed_templates, :allow_destroy => true, :update_only => true, :reject_if => lambda { |t| t[:template_id].nil? }
 end

class Template < AR::Base
  has_many :installed_templates, :inverse_of => :template
end

class InstalledTemplate < AR::Base
  belongs_to :template, :inverse_of => :installed_template
  belongs_to :installed_templateable, :polymorphic => true
end

业务逻辑是,当我创建Templates时,存在多个Site,并且我可以通过为每个InstalledTemplate创建Site来尽可能多地关联。 Templates只能有唯一的Template - 我无法将同一Site两次关联到一个Site

我在<% Template.all.each_with_index do |template| %> <%= hidden_field_tag "site[installed_templates_attributes][][id]", Hash[@site.installed_templates.map { |i| [i.template_id, i.id] }][template.id] %> <%= check_box_tag "site[installed_templates_attributes][]]template_id]", template.id, (@site.installed_templates.map(&:template_id).include?(template.id) %> <%= label_tag "template_#{template.id}", template.name %> <% end %> 的表单上有以下内容:

form_for

以上是经过大量实验后似乎唯一可行的方法。我无法使用fields_for和{{1}}助手实现此目的。

这似乎是一种相当直接的关系,我担心我会遗漏一些东西。有人建议如何以更清洁的方式完成上述工作吗?

由于

3 个答案:

答案 0 :(得分:3)

尝试以下

<% form_for @site do |f| %>

  <%f.fields_for :installed_templates do |af|%>

    <%= af.text_field :name %>
  <%end%>
<%end%>

答案 1 :(得分:1)

这里是否需要连接模型?

class Site < ActiveRecord::Base
  has_and_belongs_to_many :templates
end

在表单中,最简单的方法是使用simple_form:

<%= form.input :template_ids, :as => :radio_buttons, :collection => Template.order(:name), :label => 'Templates installed:' %>

如果需要连接模型,那么我会有一个下拉列表或我可以添加的模板列表,每个模板都有一个提交表单并添加该模板的按钮。然后我将使用update_only嵌套属性表单来显示当前安装的模板及其设置。

class Site < ActiveRecord::Base
  ...
  attr_accessor :install_template_id
  before_validation :check_for_newly_installed_template
  def check_for_newly_installed_template
    if install_template_id.present?
      template = Template.find install_template_id
      if template.present? and not templates.include?(template)
        self.templates << template
      end
    end
  end
end

有点像Drupal,您必须先启用主题,然后才能编辑其设置或将其选为当前主题。

答案 2 :(得分:1)

我认为你在这里尝试做两件不同的事情。

  1. 选择要为其创建已安装模板连接的模板列表。
  2. 从每个选定的模板中创建一个链接到站点的已安装模板的实例。
  3. 我想我会通过模型上的访问器来处理这个问题。

    在站点模型上(假设标准的磁道命名约定)

    attr_accessor :template_ids
    
    def template_ids
      installed_templates.collect{|i_t| i_t.template.id}
    end
    
    def template_ids=(ids, *args)
      ids.each{|i| i.installed_template.build(:site_id => self.id, :template_id => i) }
    end
    

    然后表单变得非常简单

    <% form_for @site do |f| %>
      <% f.collection_select :template_ids, Template.all, :id, :name, {}, :multiple => true %>
    <% end %>