在大多数情况下,我无疑是一个真正的新手,包括形成和解析params哈希。我正在尝试从投票应用程序的表单中获取相同模型的实例的哈希值。用户可以根据等级投票选出尽可能多的候选人。
我的votes#new
确实创建了Candidate.count
个投票实例,user_id
和rank
已正确设置。我知道这一点,因为表格正在为每个候选人正确地迭代@user.votes
。
以下是呈现形式的片段:
<input id="vote_rank" name="vote[rank]" type="hidden" value="1" />
<label for="vote_Candidate">Candidate</label>
<select id="vote_candidate_id" name="vote[candidate_id]"><option value=""></option>
<option value="1">Smithers</option>
<option value="2">Mr. Burns</option>
<option value="3">Bart</option>
<option value="4">Lionel Hutz</option>
<option value="5">Jimbo</option>
<option value="6">Troy McClure</option>
<option value="7">Duffman</option>
<option value="8">Maggie</option>
<option value="9">Moe</option>
<option value="10">Principal Skinner</option>
<option value="11">Apu Nahasapeemapetilan</option></select>
我无法弄清楚如何将表单从表单恢复到我的votes#create
。我能够使用一组candidate_id
和rank
值(最后一个)得到一个params哈希值,但不是所有11个实例都放在第一位。表单希望放弃正确的数据。
@user.votes.create(vote_params)
中的{p> votes#create
会抛出此错误:undefined method `stringify_keys' for "rank":String
以下是我的控制器方法和表格。
def new
@user = current_user
@votes = Candidate.count.times { |i| @user.votes.build(:rank => i + 1) }
end
def create
@user = current_user
#params[:user][:votes].each do |vote_params|
#@user.votes.create(vote_params)
params[:vote].each do |vote_params|
@user.votes.create(vote_params)
end
respond_to do |format|
if @user.valid?
format.html { redirect_to @user, notice: 'votes were successfully created.' }
else
format.html { render action: "new" }
end
end
end
<%= form_for :votes, :url => votes_path do |f| %>
<% @user.votes.each do |v| %>
<%= fields_for v do |vote_fields| %>
<%= vote_fields.hidden_field :rank %>
<%= vote_fields.label "Candidate" %>
<%= vote_fields.collection_select :candidate_id, Candidate.all, :id, :name, :include_blank => true %>
<% end %>
<% end %>
<p><%= f.submit :class => 'medium radius button' %></p>
<% end %>
这是相关的HTML
只传递了一组值:
{"utf8"=>"✓", "authenticity_token"=>"bVLXCQtOffEtu5xBNI0e94o9j9mJ8alHhuBhDkkfaRA=", "vote"=>{"rank"=>"11", "candidate_id"=>""}, "commit"=>"Save Votes", "action"=>"create", "controller"=>"votes"}
虽然表单试图放弃正确的值:
vote[rank]:1
vote[candidate_id]:2
vote[rank]:2
vote[candidate_id]:4
vote[rank]:3
vote[candidate_id]:2
vote[rank]:4
vote[candidate_id]:9
etc. (up to 11!)
任何帮助表示感谢。
更新
解决了这个问题。我把它放在以防万一,因为我没有直接找到任何东西,我花了很长时间来解决这个问题。
我的表单正在创建具有相同名称的对象,这些对象只是被覆盖。解释为什么我只能将最后一组值放入数据库中。
我的表单现在迭代从votes#new
传递的对象,并在名称中包含投票的排名。
<%= form_for :vote, :url => votes_path do |f| %>
<% @user.votes.each do |v| %>
<% if v.errors.any? %>
<h1>errors</h1>
<% end %>
<%= f.fields_for "#{v.rank}" do |builder| %>
<%= builder.hidden_field :rank, :value => v.rank %>
<div class="row">
<div class="one columns"><%= builder.label "Rank #{v.rank}", :class => "left inline" %></div>
<div class="eleven columns"><%= builder.collection_select :candidate_id, Candidate.all, :id, :name, {:include_blank => true}, :class => "two" %></div>
</div>
<% end %>
<% end %>
<%= f.submit "Submit", :confirm => "Please review your ballot and confirm that your votes are correct before submitting. This message will appear as a reminder each time you press 'Submit', even if you've edited your ballot.", :class => "small round button" %>
<% end %>
这会产生一个params[:vote]
散列的唯一命名哈希值,例如
{"1"=>{"rank"=>"1", "candidate_id"=>"5"}, "2"=>{"rank"=>"2", "candidate_id"=>"2"}, "3"=>{"rank"=>"3", "candidate_id"=>"7"}, "4"=>{"rank"=>"4", "candidate_id"=>"4"}, "5"=>{"rank"=>"5", "candidate_id"=>"10"}, "6"=>{"rank"=>"6", "candidate_id"=>""}, "7"=>{"rank"=>"7", "candidate_id"=>""}, "8"=>{"rank"=>"8", "candidate_id"=>""}, "9"=>{"rank"=>"9", "candidate_id"=>""}, "10"=>{"rank"=>"10", "candidate_id"=>""}, "11"=>{"rank"=>"11", "candidate_id"=>""}}
我的votes#create
方法将由params哈希中的键/值对组成的数组转储到@user.votes.create(my_array)
def create
@user = current_user
@user.votes.create(sanitize_and_compress_vote_array params[:vote])
redirect_to thankyou_path
end
接下来的挑战是让验证错误消息正常工作。这是我的头脑,因为我想要验证的是在任何值到达数据库之前candidate_id
作用于user_id
的唯一性的一组键值对。看起来Rails并不容易。
validates :candidate_id, :presence => true, :uniqueness => {:scope => :user_id, :message => "You may only vote for a candidate once."}
验证适用于拒绝重复值,但它没用,因为那些已经传递的值显然已经存在于数据库中。我没有发现如何在他们保存之前对自己的成员进行自我验证,并且我觉得我正在和自己说话: - (