如何避免以Rails嵌套形式为user_id使用隐藏字段

问题描述 投票:0回答:4

我感觉这在Rails中应该很容易做到,但是Rails中所有嵌套表单的示例都没有考虑到大多数嵌套表单在通过嵌套创建新对象时也需要传递current_user的事实。表格。

我目前可以使它起作用的唯一方法是传递一个隐藏字段,例如<%= form.hidden_field :user_id, value: current_user.id %>

对于我的特定示例,我有一个名为“ Result”的模型,该模型具有许多“教训”,并且我希望通过Result表单创建新的课程,而不会传递隐藏的:user_id

这似乎是不安全的,因为有人可以在浏览器中编辑该隐藏字段,然后提交表单,从而使提交内容与其他用户相关联。 current_user.id似乎是您不想作为隐藏字段嵌入html的类型。

因此,如何在嵌套对象和current_user之间创建关联,而又不将隐藏字段放入表单中?

FYI,我正在使用GoRails nested form with stimulus样式的javascript从结果表单中添加和删除课程。 (Here's the source code for that example。)这是我的代码的相关部分:

models / result.rb

class Result < ApplicationRecord
  belongs_to :user
  has_many :lessons, inverse_of: :result

  accepts_nested_attributes_for :lessons, reject_if: :all_blank, allow_destroy: true
end

models / lesson.rb

class Lesson < ApplicationRecord
  belongs_to :user
  belongs_to :result
end

controllers / results_controller.rb

class ResultsController < ApplicationController
  before_action :set_result, only: [:show, :edit, :update, :destroy]

  def new
    @result = Result.new
    @result.lessons.new
  end

  def create
    @result = current_user.results.new(result_params)

    respond_to do |format|
      if @result.save
        format.html { redirect_to @result, notice: 'Result was successfully created.' }
      else
        format.html { render :new }
      end
    end
  end

  private
    def set_result
      @result = Result.find(params[:id])
    end

    def result_params
      params.require(:result).permit(:prediction_id, :post_mortem, :correct,
                                     lessons_attributes: [:user_id, :id, :summary, :_destroy])
    end
end

controllers / lessons_controller.rb

class LessonsController < ApplicationController
  before_action :set_lesson, only: [:show, :edit, :update, :destroy]

  # GET /lessons/new
  def new
    @lesson = Lesson.new
  end

  def create
    @lesson = current_user.lessons.new(lesson_params)

    respond_to do |format|
      if @lesson.save
        format.html { redirect_to @lesson, notice: 'Lesson was successfully created.' }
      else
        format.html { render :new }
      end
    end
  end

  private
    def set_lesson
      @lesson = Lesson.find(params[:id])
    end

    def lesson_params
      params.require(:lesson).permit(:result_id, :summary)
    end
end

views / results / _form.html.erb

<%= form_with(model: result, local: true) do |form| %>

  <h3>Lessons</h3>

  <div data-controller="nested-form">
    <template data-target="nested-form.template">
      <%= form.fields_for :lessons, Lesson.new, child_index: 'NEW_RECORD' do |lesson| %>
        <%= render "lesson_fields", form: lesson %>
      <% end %>
    </template>

    <%= form.fields_for :lessons do |lesson| %>
      <%= render "lesson_fields", form: lesson %>
    <% end %>

    <div class="pt-4" data-target="nested-form.links">
      <%= link_to "Add Lesson", "#",
                  data: { action: "click->nested-form#add_association" } %>
    </div>
  </div>

  <div class="form-submit">
   <%= form.submit "Save" %>
 </div>

<% end %>

views / results / _lesson_fields.html.erb

<%= content_tag :div, class: "nested-fields", data: { new_record: form.object.new_record? } do %>
  # This hidden field seems unsafe!
  <%= form.hidden_field :user_id, value: current_user.id %>

  <div class="pb-8">
    <%= form.text_area :summary %>
    <%= link_to "Remove", "#", 
                data: { action: "click->nested-form#remove_association" } %>
  </div>

  <%= form.hidden_field :_destroy %>
<% end %>

我确定这是Rails中的常见问题,但是我找不到在线的任何将user_id作为嵌套字段示例一部分的教程。非常感谢您的帮助!

ruby-on-rails ruby nested-forms
4个回答
2
投票

个人,因为设置current_user id是控制器应该关心的事情,所以我将遍历所有课程并在那里设置user_id值。

def create
  @result = current_user.results.new(result_params)
  @result.lessons.each do |lesson|
    lesson.user ||= current_user if lesson.new_record?
  end

  ... the rest ...

1
投票

我认为没有一种在视图外部自动处理此问题的好方法。您可能必须将值注入到参数中,或者可能需要在Lesson中的default关联上使用user,以从记录的用户(belongs_to :user, default: -> { result.user })对其进行设置。在这些情况下,我通常移至默认的Rails流之外,并使用PORO,Form Object,Service Object等。


0
投票

根据对话,你可以吗?


0
投票
建立这样的形式
<%= form.fields_for :lessons, lesson_for_form(current_user.id) do |lesson| %>
  <%= render "lesson_fields", form: lesson %>
<% end %>
© www.soinside.com 2019 - 2024. All rights reserved.