確かに、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)
invotes#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は次のとおりです
渡される値のセットは1つだけです。
{"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."}
検証は重複する値を拒否する場合は問題なく機能しますが、すでに渡された値は明らかにデータベースにすでに存在するため、役に立ちません。コレクションのメンバーを保存する前に自分自身に対して検証する方法についてスクワットを見つけていません。自分自身と話しているような気がします:-(