简体   繁体   中英

Rails 5 Simple Form Save Hash Value Submitted by a Form in Model Attribute

In my Rails 5 app I have a Simple Form form for creating or updating for my model Training . In this form I already have checkboxes for each of my Participant s to assign them to the Training . Now I'm trying to add a radio button group (5 for a rating from 1 to 5) for each Participant , because each can rate the Training .

Screen shot of the rendered form

I managed to render the radio buttons as I wanted but unfortunately I can only select one of all the radio buttons rendered. They are even strangely connected to the checkboxes, which will probably be because they have the same input method participant_ids , which is connected to the has_and_belongs_to_many association with Participant :participants .

<%= simple_form_for @training do |f| %>
...
  <div id="participants-ratings-container">
    <div id="participants-container" style="display: inline-block; vertical-align: top; width: 8em">
    <%= f.label t('activerecord.models.participant') %>
    <%= f.collection_check_boxes :participant_ids, Participant.all.order(:name), :id, :name, {:item_wrapper_class => 'checkbox-container'}  %>
  </div>

  <div id="ratings-container" style="display: inline-block; vertical-align: top">
    <%= f.label t('trainings._form.ratings') %>
    <% Participant.all.order(:name).each do |p| %>
    <%= f.input :participant_ids, collection: 1..5, as: :radio_buttons, label: false%>
    <% end %>
  </div>
...
<% end %>

I tried a lot of things but I have no ideas anymore. If it is possible I would like to fill a Hash participant_ratings in my Training class in the way "participant.name" => rating value.

Can anyone give me a hint on how to achieve this? Maybe even tell me how to disable the radio button group if the corresponding Participant is not checked?

Thanks in advance!

UPDATE

I managed to adapt my form and even integrate jQuery raty plugin to enter the rating value for each Participant . Each rating is sent with it's corresponding participant-id to the server as a hash, eg like so:

"participant_ratings"=>{"3"=>"5", "1"=>"3.5", "2"=>""}.

Every rating is disabled and it's value set to 0 if the corresponding participant checkbox isn't checked. Here is my view code:

<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>    

New screen shot of the rendered form

The last thing I don't seem to be able to figure out is how to save the participant_ratings hash in the corresponding model attribute :participant_ratings

If I allowed the param :participant_ratings in my trainings_controller.rb but nothing was saved. So I added

@training.participant_ratings = params[:participant_ratings]

and now 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>

The methods in my trainings_controller.rb :

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

How do I save the hash sent by the form in the model's attribute? Where am I going wrong?
Can I somehow define participant_ratings as a hash in the params similar to the array participant_ids there?

Firstly, 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!

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM