Rails在验证错误后形成错误的URL(不保留传递的参数)

BB5*_*500 3 forms validation ruby-on-rails parameter-passing ruby-on-rails-4

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

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

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

http://localhost:3000/task/new?project_id=5
Run Code Online (Sandbox Code Playgroud)

我的新表格如下:

<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>
Run Code Online (Sandbox Code Playgroud)

正如你所看到我在表单中使用嵌套属性(我正在创建一个任务和一个TaskRelationship.现在,当我尝试保存而不填写所有必需的字段时,会抛出验证但是由于某种原因它将我重定向到:

http://localhost:3000/tasks
Run Code Online (Sandbox Code Playgroud)

而不是原来的:

http://localhost:3000/tasks/new?project_id=5
Run Code Online (Sandbox Code Playgroud)

我看过很多帖子,似乎都没有回答这个特例.下面的stackO帖子很接近,但是当我尝试使用任务而不是用户时,它仍然无法找到task_ID

使用自定义URL(例如http:// localhost:3000/education_informations/new?user_id = 10)在新页面上呈现错误

我怎么能有轨道只是​​渲染与我开始时相同的网址 - 似乎这应该很容易,所以一定要丢失一些小东西.

我的控制器动作:

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
Run Code Online (Sandbox Code Playgroud)

更新W /路由

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
Run Code Online (Sandbox Code Playgroud)

谢谢你的帮助......

Dav*_*vid 6

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

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

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

当您提交表单时,它实际上正在对/ tasks执行http POST,它将路由到任务控制器的create操作.url和http方法是form_for帮助器生成的结果:

<%= form_for @task, :html => {:multipart => true} do |f| %>
Run Code Online (Sandbox Code Playgroud)

这就是为什么URL从改变/tasks/new?project_id=5/tasks

现在创建操作如果验证失败,则只需渲染新表单 - 它不会重定向到任何地方 - 网址与进入此操作时的状态保持不变 - 这意味着,它仍然是/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
Run Code Online (Sandbox Code Playgroud)

因此,为了澄清url中的更改不是重定向,只是表单发布到与/ tasks/new不同的URL,这实际上只是一个整容问题.

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

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

  post     'new_task' => 'tasks#create'
  get      'new_task' => 'tasks#new'
Run Code Online (Sandbox Code Playgroud)

这是将POST和GET http方法映射到/ new_task,因此对于new和create action invocations,url显示相同.请注意,您需要更改form_for帮助程序中的URL以使用此新路由:

<%= form_for @task, url: 'new_task', multipart: true do |f| %>
Run Code Online (Sandbox Code Playgroud)