Search code examples
ruby-on-railsformsroutesnested-routes

Rails 6 & route for custom post- action for nested resource & form


I need to make a separate create action for the nested Answer resource, such as create_xhr, which will be called in the form on the parent resource.
This is what the route for the Answer resource looks like:

  namespace :admin do
    resources :tests do
      resources :questions, shallow: true, except: %i[index] do
        resources :answers, shallow: true, except: %i[index]
      end
    end
  end

The path should look something like this:

post '/questions/:question_id/answers/create_xhr

So that in the Answers controller, the new object is associated with the current Question.
Now I've come to an option:

  namespace :admin do
    resources :tests do
      resources :questions, shallow: true, except: %i[index] do
        resources :answers, shallow: true, except: %i[index] do
          post :create_xhr, on: :new
        end
      end
    end
  end

I get the route:

create_xhr_new_admin_question_answer POST   /admin/questions/:question_id/answers/new/create_xhr(.:format)  admin/answers#create_xhr

And then I create a form on the show page for Question:

<%= form_with url: create_xhr_new_admin_question_answer_path(@question), local: false do |form| %>

But the parameters of the new Answer do not come inside the "answer" key:

Parameters: {"authenticity_token"=>"[FILTERED]", "body"=>"text", "correct"=>"false", "commit"=>"Add answer", "lang"=>"en", "question_id"=>"7"}

It must be:

Parameters: {"authenticity_token"=>"[FILTERED]", "answer"=>{"body"=>"text", "correct"=>"false"}, "commit"=>"Add answer", "lang"=>"en", "question_id"=>"7"}

If I specify a model in the form instead of a URL, then rails selects the default action create.

I also tried writing the route directly in the Admin namespace block:

post '/questions/:question_id/answers/create_xhr', to: 'answers#create_xhr', as: :create_answer_on_question

and get a route:

admin_create_answer_on_question POST   /admin/questions/:question_id/answers/create_xhr(.:format)   admin/answers#create_xhr

However, the problem with the parameters coming to the controller is the same.

Where am I wrong?
Should I write the router or the form differently?


Solution

  • OK, in the form you must specify both the model and the path. In the end, it all looks like this:

      namespace :admin do
        resources :tests do
          resources :questions, shallow: true, except: %i[index] do
            resources :answers, shallow: true, except: %i[index]
          end
        end
        
        post '/questions/:question_id/answers/create_xhr', to: 'answers#create_xhr', as: :create_answer_on_question
      end
    

    and form:

    <%= form_with model: [:admin, @question, @question.answers.new ], url: admin_create_answer_on_question_path(@question), local: false do |form| %>
    

    Then Answer parameters come nested in the controller.

    Inside the resources :answers block, I couldn't find a way to normally spell the action without new in the path.