【问题标题】:Rails form rendering wrong URL after validation errors (not keeping passed parameter)验证错误后Rails表单呈现错误的URL(不保留传递的参数)
【发布时间】:2017-03-13 00:23:05
【问题描述】:

在项目展示页面上,我在“创建新任务”中传递了一个非常简单的参数,该参数存储了它来自哪个项目:

@project.id), :class=> "btn btn-info col-md-12" %>

所以当我为它创建一个新任务时,它将它存储在我的新任务表单的 URL 中,如下所示:

http://localhost:3000/task/new?project_id=5

我的新表格如下:

<div class="container sign-in-register">
    <div class="authform">

           <%= form_for @task, :html => {:multipart => true} do |f| %>

          <h3>Add a task for this project...</h3><br/>

            <%= f.label :name %>
            <%= f.text_field :name, class: 'form-control' %>

            <%= hidden_field_tag 'project_id', @project_id %>

            <%= f.fields_for :taskrelationships do |ff| %>
              <%= ff.hidden_field :taskproject_id, value: @project_id %>
              <%= ff.label :task_url %>
              <%= ff.text_field :task_url, class: 'form-control' %>
            <% end %>

            <br clear="all">

            <%= f.submit "Save Task", class: "btn btn btn-info" %>
          <% end %>

    </div>
</div>

如您所见,我在表单中使用了嵌套属性(我正在创建一个任务和一个 TaskRelationship。现在,当我尝试在不填写所有必填字段的情况下保存时,会引发验证,但由于某种原因它将我重定向到:

http://localhost:3000/tasks

代替原来的:

http://localhost:3000/tasks/new?project_id=5

我已经阅读了很多帖子,但似乎没有一个回答这个特殊情况。下面的 stackO 帖子已关闭,但是当我使用任务而不是用户尝试它时,它仍然找不到 task_ID

Render error on new page with customize url like http://localhost:3000/education_informations/new?user_id=10

我怎样才能让 rails 简单地呈现与我开始时完全相同的 url - 看起来这应该很容易,所以必须遗漏一些小东西。

我的控制器操作:

def new
    @project_id = params[:project_id]
    @task = Task.new
    @task.taskrelationships.build
  end

  def create
    @project = Project.find(params[:project_id])

    @task = Task.new(task_params)
    if @task.save
      flash[:success] = "This task has been added."
      @task.taskrelationships.create!(@taskrelationships_params)
      redirect_to tasks_project_path(@project)
    else
      @task.taskrelationships.build(@taskrelationships_params)
      flash[:alert] = @task.errors.full_messages.to_sentence
      render :new
    end
  end

 private

def task_params
      @taskrelationships_params = params.require(:task).permit(taskrelationships_attributes: [
        :task_url,
        :taskproject_id
        ])[:taskrelationships_attributes]["0"]

      params[:task].delete(:taskrelationships_attributes)
      params.require(:task).permit(
        :name,
        :user_id,
        taskrelationships_attributes: [
          :task_url,
          :taskproject_id
        ]
      ).merge(owner: current_user)
    end

使用路线更新

resources :projects do
    resources :reviews, except: [:destroy]
    member do
      get :tasks
    end
  end

  resources :tasks
  resources :taskrelationships, only: [:create, :destroy] do
    post :vote, on: :member, controller: "task_relationships"
  end

感谢您的帮助...

【问题讨论】:

  • 我对你的问题有点困惑 - 它与创建新任务有关,我假设控制器代码适用于你的 TasksController 在这种情况下,为什么你的网址是 project/new?task_id=5 - 这个怎么样任务有id吗?您不希望这会在 ProjectsController 中进行新的操作吗?
  • 道歉 - 表格应该是localhost:3000/tasks/new?project_id=5(我最初写错了,但现在已经更新了)
  • (所以我正在查看项目配置文件,并且有一个按钮可以创建新任务...打开 localhost:3000/tasks/new?project_id=5)。任务还没有 id,项目会有。
  • 是的,完全理解 - 感谢您的快速更正和解释 :) 好的,只有一点......您需要在调用 render :new 之前设置 @project_id(虽然我不认为那是重定向问题的原因 - 值得设置它,但只是为了确保)。其次,您能否发布与任务相关的路线。
  • 确定 - 刚刚发布了我的路线。

标签: ruby-on-rails forms validation ruby-on-rails-4 parameter-passing


【解决方案1】:

好的,首先解释一下这里发生了什么:

当您调用 http://localhost:3000/task/new?project_id=5 时,您实际上被路由到任务控制器上的新操作(使用 project_id 参数)。

然后您的新操作设置变量,rails 将呈现包含您的新任务表单的 new.html.erb。

当您提交表单时,它实际上是在向 /tasks 发送一个 http POST,它会路由到您的任务控制器的创建操作。该 url 和 http 方法是由 form_for 助手生成的结果:

<%= form_for @task, :html => {:multipart => true} do |f| %>

这就是网址从/tasks/new?project_id=5 更改为/tasks 的原因

现在,如果验证失败,则创建操作只会呈现新表单 - 它不会重定向到任何地方 - url 与输入此操作时保持不变 - 意思是,它仍然是 /tasks

您实际上不需要导航到 /tasks/new?project_id=5 来呈现新表单,但您需要做的是在控制器中设置 @project_id 以便视图可以访问该变量(就像在新动作中执行):

  def create
    @project = Project.find(params[:project_id])

    @task = Task.new(task_params)
    if @task.save
      flash[:success] = "This task has been added."
      @task.taskrelationships.create!(@taskrelationships_params)
      redirect_to tasks_project_path(@project)
    else
      @task.taskrelationships.build(@taskrelationships_params)
      @project_id = @project.id
      flash[:alert] = @task.errors.full_messages.to_sentence
      render :new
    end
  end

所以,为了澄清 url 的变化不是重定向,它只是表单发布到与 /tasks/new 不同的 url,这实际上只是一个表面问题。

现在,如果您担心,您可以将路由更改为以下内容:

  resources :tasks, except: [:create, :new]

  post     'new_task' => 'tasks#create'
  get      'new_task' => 'tasks#new'

这会将 POST 和 GET http 方法映射到 /new_task,因此对于 new 和 create 操作调用,url 看起来相同。请注意,您确实需要更改 form_for 助手中的 url 才能使用此新路由:

<%= form_for @task, url: 'new_task', multipart: true do |f| %>

【讨论】:

  • 做到了...现在完全有意义了。非常感谢今天的帮助,henner66。
  • 这并不能解决我想根据查询参数值显示特定表单字段的用例。提交表单时出错,它会删除查询参数并显示所有字段。
【解决方案2】:

由于 Rails 在表单中的默认行为是 remote: true,因此您可以将表单的内容移动到部分(我们将其命名为 _my_form.html.erb),添加到控制器操作(假设在创建操作中):

respond_to do |format|
  format.js {}
end

然后添加一个 create.js.erb 文件,您将在其中呈现部分表单

$("#form").html(
  "<%= j render partial: 'my_form', locals: { entity: @entity } %>"

);

因此,验证错误和所有属性都可以在表单内访问,无需破解“Rails 方法”

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-10-13
    • 2016-01-27
    • 1970-01-01
    • 1970-01-01
    • 2013-03-18
    • 1970-01-01
    • 2011-09-18
    • 1970-01-01
    相关资源
    最近更新 更多