简体   繁体   中英

How to set Rails routes on nested resources?

This may seem redundant because similar question has been asked here and here , but I haven't found a solution yet.

I am running an RSpec to test :update for api. When I run RSpec, it shows No Route Matches on my first test. All I need is to have the testing to have_http_status(401) for unauthenticated user. Rails can't figure out the routing. Here is what the error says:

Failures:

  1) PostsController unauthenticated user PUT update returns http unauthenticated
     Failure/Error: put :update, topic_id: my_topic.id, post_id: my_post.id, post: {title: my_post.title, body: my_post.body}

     ActionController::UrlGenerationError:
       No route matches {:action=>"update", :controller=>"posts", :post=>{:title=>"Xdiwbu zuitsom prubmlhd oxmgtkb swphb ukije salhvk.", :body=>"Pjlb ywlzqv igdesqmw oqjgy mrwpye ujierxtn owqxbvt. Wzxu sjcikthg xare tcawzx tedmiqwf lewab. Twkeoun mos ophta fvae krmnsqe. Jxefyo ncd agj ieyanvt uehazwnk mtsi fbsm."}, :post_id=>"1", :topic_id=>"1"}
     # ./spec/api/v1/controllers/posts_controller_spec.rb:11:in `block (3 levels) in <top (required)>'

Here is the RSpec (spec/api/v1/controllers/posts_controller_spec.rb)

require 'rails_helper'

RSpec.describe Api::PostsController, type: :controller do
  let(:my_user) { create(:user) }
  let(:my_topic) { create(:topic) }
  let(:my_post) { create(:post, topic: my_topic, user: my_user) }

context "unauthenticated user" do

it "PUT update returns http unauthenticated" do
  put :update, topic_id: my_topic.id, post_id: my_post.id, post: {title: my_post.title, body: my_post.body}
  expect(response).to have_http_status(401)
end
...

Here are the routes:

  namespace :api do
    namespace :v1 do
      resources :users, only: [:index, :show, :create, :update]
      resources :topics, except: [:edit, :new] do
        resources :posts, only: [:update, :create, :destroy]
      end
    end
  end

And here is the first part of the test:

class Api::V1::PostsController < Api::V1::BaseController
  before_action :authenticate_user, except: [:index, :show]
  before_action :authorize_user, except: [:index, :show]

     def update
       post = Post.find(params[:id])

       if post.update_attributes(post_params)
         render json: post.to_json, status: 200
       else
         render json: {error: "Post update failed", status: 400}, status: 400
       end
     end
...

No matter what I change the RSpec, I can't get it to match the routes. Would you guys mind helping?

Thanks!!

2 things stand out to me.

1: The controller itself is namespaced under Api::V1 . The controller in the spec however, is namespaced under just Api . This should be updated to match.

2: If you run rake routes , you'll notice a line like this:

PUT /api/v1/topics/:topic_id/posts/:id(.:format) api/v1/posts#update .

It's important to note the names being given after the : in that message. In here, it's stating that the ID of the topic should be supplied to the controller as topic_id , and the ID of the post should be supplied as just id . If you modify your put statement to be something more like put :update, topic_id: my_topic.id, id: my_post.id, post: {title: my_post.title, body: my_post.body} , it should work.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM