I am building a Rails5 app where I have a model Training
with an attribute participant_ratings
, a hash which should hold the ratings of all participants assigned to the training in the way participant.id => rating value
. I already managed to build the form for submitting the hash.
<%= simple_form_for @training do |f| %>
...
<div id="ratings-container" style="display: inline-block; vertical-align: top">
<%= f.label t('trainings._form.ratings') %>
<% Participant.all.order(:name).each do |p| %>
<span class="checkbox_container">
<% current_rating = @training.participant_ratings[p.id].nil? ? '' : @training.participant_ratings[p.id] %>
<label id='star<%= "#{p.id}" %>' data-rating='<%= "#{current_rating}" %>' style="margin-bottom: 12px;" ></label>
<input id="rating<%= "#{p.id}" %>" name="participant_ratings[<%= "#{p.id}" %>]" type="hidden" value="<%= "#{@training.participant_ratings[p.id]}" %>" />
</span>
<script>
$('#star<%= "#{p.id}" %>').raty({
score: function() {
return $(this).attr('data-rating');
},
half : true,
readOnly: <%= !@training.participants.include?(p) %>,
path: '/assets',
click : function(score, evt) {
$('#rating<%= "#{p.id}" %>').val(score);
}
});
$('#training_participant_ids_<%= "#{p.id}" %>').change(function () {
var star = $('#star<%= "#{p.id}" %>');
if(document.getElementById('training_participant_ids_<%= "#{p.id}" %>').checked) {
star.raty('readOnly', false);
} else {
star.raty('cancel');
star.raty('readOnly', true);
$('#rating<%= "#{p.id}" %>').val("");
}
})
</script>
<% end %>
</div>
...
<% end %>
I can see that the hash is sent correctly to the server:
"participant_ratings"=>{"3"=>"5", "1"=>"3.5", "2"=>""}
But I cannot manage this hash to be saved in the Training
s attribute. I get the error: Attribute was supposed to be a Hash, but was a ActionController::Parameters. -- <ActionController::Parameters {"3"=>"5", "1"=>"3.5", "2"=>""} permitted: false>
Attribute was supposed to be a Hash, but was a ActionController::Parameters. -- <ActionController::Parameters {"3"=>"5", "1"=>"3.5", "2"=>""} permitted: false>
My controller code:
class TrainingsController < BaseController
...
def update
@training = Training.find(params[:id])
@training.updated_date_time = DateTime.now
@training.participant_ratings = params[:participant_ratings]
if @training.update(training_params)
flash[:notice] = t('flash.training.updated')
redirect_to @training
else
render 'edit'
end
end
private
def training_params
params.require(:training).permit(:village, :topic, :user_id, :start_time, :end_time, {:participant_ids => []}, :participant_ratings)
end
end
My Training
class:
class Training < ApplicationRecord
...
serialize :participant_ratings, Hash
...
end
What do I have to change to save the hash in the participant_ratings
attribute in my Training
model?
You can try
@training.participant_ratings = params[:participant_ratings].to_hash
But i think storing it as json will be even better, so:
@training.participant_ratings = params[:participant_ratings].to_json
And then to read it as a hash:
hash = JSON.parse(@training.participant_ratings)
There's a an error in the controller. update method doesn't get the ratings param, so it goes unsaved. Here's the workaround:
class TrainingsController < BaseController
...
def update
@training = Training.find(params[:id])
@training.updated_date_time = DateTime.now
@training.participant_ratings = params[:participant_ratings]
@training.assign_attributes(training_params)
if @training.save
flash[:notice] = t('flash.training.updated')
redirect_to @training
else
render 'edit'
end
end
private
def training_params
params.require(:training).permit(:village, :topic, :user_id, :start_time, :end_time, {:participant_ids => []})
end
end
Firstly, (as pointed out by Dmitry Kukhlevsky), I had to make sure that the participants_rating
-hash was inside the training
-hash when submitted by my form, so I had to change the name attribute in my hidden form input for the rating:
<input id="rating<%= "#{p.id}" %>" name="training[participant_ratings][<%= "#{p.id}" %>]" type="hidden" value="<%= "#{@training.participant_ratings[p.id]}" %>" />
Secondly, I had to whitelist the keys for my participant_ratings
-hash so that they are permitted:
def training_params
ratings_keys = params[:training].try(:fetch, :participant_ratings, {}).keys
params.require(:training).permit(:village, :topic, :user_id, :start_time, :end_time, {:participant_ids => []}, participant_ratings: ratings_keys )
end
I found this solution in this rails thread
After that participant_ratings
was saved just fine!
Still thanks a lot to Dmitry for all his help!!!
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.