我不知道为什么这不起作用,但我似乎无法通过复杂的形式来创建必要的连接模型。
因此,一个站点可以通过siteenvs拥有许多环境。
class Site < ActiveRecord::Base
has_many :siteenvs, :dependent => :destroy
has_many :environments, :through => :siteenvs, :uniq => true
attr_accessible :name, :description, :documentation, :protocol, :port, :siteenvs_attributes
accepts_nested_attributes_for :siteenvs, :reject_if => proc { |attributes| attributes["environment_id"] == "0"}
end
class Siteenv < ActiveRecord::Base
belongs_to :site
belongs_to :environment
validates :site_id, :uniqueness => { :scope => :environment_id }
end
class Environment < ActiveRecord::Base
has_many :siteenvs, :dependent => :destroy
has_many :sites, :through => :siteenvs, :uniq => true
end
这里很标准的东西。现在这是我的控制器。我正在做的是询问数据库有多少个环境,并为新站点构建那么多的siteenvs。这样,表单将为每个环境提供一个复选框,因此用户可以选择他们想要的任何内容。
class SitesController < ApplicationController
load_and_authorize_resource
respond_to :html, :xml, :json
def new
@site = Site.new
Environment.all.each do |env|
siteenv = @site.siteenvs.build(:environment_id => env.id)
end
respond_with (@site)
end
...
def create
@site = Site.new(params[:site])
if @site.save
flash[:success] = "New site created."
respond_with(@site, :location => @site)
else
render 'new'
end
end
end
然后我的新网站表单如下:
<h1>Create a new site</h1>
<%= form_for(@site) do |f| %>
<h3>Step 1 - General</h3>
<table>
<%= render 'site_fields', :f => f %>
</table>
<h3>Step 2 - Environments</h3>
<div id="environments">
<ul>
<%= f.fields_for :siteenvs do |builder| %>
<% environment = Environment.find(builder.object.environment_id) %>
<li><%= builder.check_box :environment_id, { :checked => false, :class => "s_environment_checkbox", :env => environment.name, :domain => environment.domain }, builder.object.environment_id %>
<%= builder.label :environment_id, "#{environment.name}" %>
</li>
<% end %>
</ul>
</div>
<div class="actions">
<%= f.submit "Finish" %>
</div>
<% end %>
所以会发生什么,我的表单呈现正确,并且所有HTML属性看起来都是正确的。复选框的值是相应环境的ID,所有名称都显示为Rails生成的HTML:
<li>
<input name="site[siteenvs_attributes][0][environment_id]" type="hidden" value="0">
<input class="s_environment_checkbox" domain="example.com" env="env1" id="site_siteenvs_attributes_0_environment_id" name="site[siteenvs_attributes][0][environment_id]" type="checkbox" value="1">
</li>
但是,除非您标记每个复选框,否则我会在siteenvs模型上引用某个方法时出错。我想这是因为提交的参数引用了一个不存在的环境_(0),但我认为rails会忽略它。事实上,如果没有检查环境标识,我甚至不确定为什么会提交这些环境标识!这是一个示例输出,当我只选择一个复选框时,5:
{"utf8"=>"✓",
"authenticity_token"=>"Q1zdbb/ibcJrKb2FYf45o+Q43o2PZm1UU75dngis1UE=",
"site"=>{"name"=>"bob",
"description"=>"",
"documentation"=>"",
"protocol"=>"http",
"port"=>"80",
"siteenvs_attributes"=>{"0"=>{"environment_id"=>"1",
"url"=>""},
"1"=>{"environment_id"=>"0"},
"2"=>{"environment_id"=>"0"},
"3"=>{"environment_id"=>"0"},
"4"=>{"environment_id"=>"0"}}},
"commit"=>"Finish"}
所以我不知道0来自哪里,也不知道为什么未选中的复选框甚至包含在参数中。有什么想法吗?
答案 0 :(得分:1)
这直接来自表单check_box方法的文档:
返回为访问指定属性而定制的复选框标记 (通过方法识别)分配给模板的对象 (由对象确定)。该对象必须是实例对象 (@object)而不是本地对象。这意味着该方法返回一个 整数,如果该整数大于零,则复选框为 检查。输入标记上的其他选项可以作为哈希传递 有选项。 checked_value默认为默认值1 unchecked_value设置为0,便于布尔值。
<强>疑难杂症强>
HTML规范说未经检查的复选框不成功, 因此Web浏览器不会发送它们。不幸的是这引入了 问题:如果发票模型有付费标志,并且形式为 编辑付费发票,用户取消选中其复选框,不付款 参数被发送。所以,任何像
这样的质量分配习语
@invoice.update_attributes(params[:invoice])
不会更新旗帜。
从代码的参数中我看到四个environment_id => "0"
是复选框的未选中值。您需要在处理数据时过滤掉这些数据。