Как избежать использования скрытого поля для user_id в вложенной форме Rails - PullRequest
1 голос
/ 02 декабря 2019

Мне кажется, что это должно быть легко сделать в Rails, но во всех примерах вложенных форм в Rails не учитывается тот факт, что большинству вложенных форм также необходимо передавать current_user при создании новых объектов черезвложенная форма.

Единственный способ заставить это работать в данный момент - передать скрытое поле, например <%= form.hidden_field :user_id, value: current_user.id %>.

. В моем конкретном примере у меня есть модель под названием "Результат », который содержит много« Уроки », и я хотел бы создавать новые уроки с помощью формы« Результат », не пропуская скрытую :user_id.

Это кажется небезопасным, поскольку кто-то может отредактировать это скрытое поле в браузере, а затемотправить форму, таким образом связывая представление с другим пользователем. Current_user.id выглядит как тип вещи, которую вы не хотите вставлять в html как скрытое поле.

Так как же создать ассоциацию между вложенными объектами и current_user без помещения этого скрытого поля в форму?

К вашему сведению, я использую вложенную форму GoRails со стимулом стиль javascript для добавления и удаления уроков из формы результатов. ( Вот исходный код для этого примера .) Вот соответствующие части моего кода:

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

модели / урок.рб

class Lesson < ApplicationRecord
  belongs_to :user
  belongs_to :result
end

контроллеры / 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

контроллеры / courses_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

просмотров / результатов / _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 %>

просмотров / результатов / _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 является частью примера вложенных полей. Любая помощь очень ценится!

Ответы [ 3 ]

3 голосов
/ 02 декабря 2019

Лично, поскольку установка идентификатора current_user - это то, о чем должен заботиться контроллер, я бы перебрал все уроки и установил там значение 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 голос
/ 02 декабря 2019

Я не думаю, что есть отличный способ справиться с этим автоматически вне поля зрения. Вам нужно будет либо ввести значение в параметры, либо возможно использовать default в ассоциации user в Уроке, которая устанавливает его от пользователя Записи (belongs_to :user, default: -> { result.user }). В этих сценариях я обычно выхожу за пределы потока Rails по умолчанию и использую PORO, объект формы, объект службы и т. Д.

0 голосов
/ 02 декабря 2019
построить форму, как это
<%= form.fields_for :lessons, lesson_for_form(current_user.id) do |lesson| %>
  <%= render "lesson_fields", form: lesson %>
<% end %>

удалить скрытое поле user_id, которое вы добавили

обновить файл result.rb
 class Result < ApplicationRecord

   def lesson_for_form(user_id)
     collection = lessons.where(user_id: user_id)
     collection.any? ? collection : lessons.build(user_id: user_id)
   end

 end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...