提交 form_for 时路由参数不可用?

Route params not available when submitting form_for?

为什么我在提交表单时会收到此错误消息?我不是已经建好id了吗?

ActiveRecord::RecordNotFound at /polls/:poll_id/responses
Couldn't find Poll with 'id'=

在我的 Polls_Controller 中,我正在使所有表单输入都可访问。 poll_id 来自路由参数,显示路由成功响应 :id

def show
  @poll_options = @poll.options

  # since you can respond to a poll from its show route
  @poll_response = PollResponse.new
end

def responses
  @poll_response = PollResponse.create(
    params.require(:poll_response).permit(:poll_option_id, :ip_address, :poll_id)
  )
  if @poll_response.save
    redirect_to "/welcome"
  else
  end
end

private

def set_poll
  @poll = Poll.find(params[:id])
end

我的显示视图在 /polls/:id 成功加载,但是,当我提交表单时,似乎 Rails 无法访问该参数,因为路由发生了变化。

#Poll/Show.html.erb
<%= form_for(@poll_response, url: '/polls/:poll_id/responses/') do |f| %>

  <%= f.hidden_field(:ip_address, value: request.remote_ip) %>
  <%= f.hidden_field(:poll_id, value: @poll.id) %>
  <ul>
    <% @poll_options.each do |option_id, option_value| %>
      <li>
        <%= f.radio_button(:poll_option_id, option_id) %>
        <%= option_value %> </br>
      </li>
    <% end %>
  </ul>
  <%= f.submit "Vote!" %>

<% end %>

这是我的路线。 Poll_Response 和 Poll_Option 模型属于投票。

resources :polls, only: [:show, :create, :index, :responses] do
  post 'responses', as: :responses
end

这里有些地方出了问题。

首先,您对表单的url: '/polls/:poll_id/responses/'选项意味着表单将在提交表单时使用文字路由/polls/:poll_id/responses/form_for不理解您'重新期望它用任何东西替换 :poll_id 所以它不会。

接下来,当您 rake routes 时,路由应显示为 /polls/:id/responses,因此路由本身可能在 routes.rb 中定义不正确。您的 routes.rb 应该看起来更像这样:

resources :polls, only: [:show, :create, :index, :responses] do
  member do
    post :responses
  end
end

这将为您提供类似 /polls/:id/response 的路由,您也可以将 set_poll 控制器回调附加到 responses 路由。现在当你 rake routes 你应该看到:

responses_poll POST /polls/:id/responses(.:format) polls#responses

这里有 responses_poll_path URL 表单助手:

<%= form_for(@poll_response, url: responses_poll_path(@poll) do |f| %>

您还可以删除:

<%= f.hidden_field(:poll_id, value: @poll.id) %>

来自您的表单,因为投票的 id 现在位于它所属的路线中。

通过上述更改,您的表单将发布到正确的控制器,该控制器中的 params[:id] 将识别有问题的民意调查,而 @poll 将是您的 responses控制器。

现在你已经正确设置了路由和表单,你的控制器变得简单多了:

@poll_response = @poll.responses.create(
  params.require(:poll_response).permit(:poll_option_id, :ip_address)
)

@poll.responses 协会应该自动提供民意调查的 id(当然,如果 app/models/poll.rb 里面有 has_many :responses)。