Rails 在简单表单提交的模型属性中保存哈希

Rails Save Hash in Model Attribute Submitted by Simple Form

我正在构建一个 Rails5 应用程序,其中我有一个模型 Training,属性 participant_ratings,一个散列,它应该包含以 [=16] 的方式分配给培训的所有参与者的评分=].我已经设法构建了用于提交哈希的表单。

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

我可以看到哈希已正确发送到服务器:
"participant_ratings"=>{"3"=>"5", "1"=>"3.5", "2"=>""}

但我无法管理将此散列保存在 Trainings 属性中。我收到错误: Attribute was supposed to be a Hash, but was a ActionController::Parameters. -- <ActionController::Parameters {"3"=>"5", "1"=>"3.5", "2"=>""} permitted: false>

我的控制器代码:

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

我的Trainingclass:

class Training < ApplicationRecord
...

  serialize :participant_ratings, Hash

...
end

我必须更改什么才能将散列保存在我的 Training 模型的 participant_ratings 属性中?

你可以试试

@training.participant_ratings = params[:participant_ratings].to_hash

但我认为将其存储为 json 会更好,所以:

@training.participant_ratings = params[:participant_ratings].to_json

然后将其作为哈希读取:

hash = JSON.parse(@training.participant_ratings)

控制器出现错误。 update 方法没有得到 ratings 参数,所以它没有被保存。解决方法如下:

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

首先,(正如 Dmitry Kukhlevsky 所指出的),我必须确保 participants_rating-hash 是 inside training-hash当通过我的表单提交时,我不得不更改隐藏表单输入中的名称属性以获取评级:

<input id="rating<%= "#{p.id}" %>" name="training[participant_ratings][<%= "#{p.id}" %>]" type="hidden" value="<%= "#{@training.participant_ratings[p.id]}" %>" />

其次,我必须将 participant_ratings-哈希的密钥列入白名单,以便允许它们:

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

我在 this rails thread

中找到了这个解决方案

之后participant_ratings保存就好了!

仍然非常感谢 Dmitry 的所有帮助!!!