ZpfSysn
ZpfSysn

Reputation: 889

Rails : ajax call failed to get data from backend

I am trying to get a drop down data from a route.

I made the dropdown data a model.

create_table "choices", force: :cascade do |t|
    t.string "description"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
end

and I seed it as following:

Choice.create!(
  [
    {
      description: "Choice 1"
    },
    {
      description: "Choice 2"
    }
  ]
)

This drop down model does not have its own controller, it is used by another model's api controller. The model looks like

  create_table "forms", force: :cascade do |t|
    t.text "username"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

And this is how "Choice" Model is used in the form's controller

class Api::FormsController < ApplicationController
  def choices
    all_choices = Choice.all.
                map {|e| {"label" => e.description, "value" => e.id}}.as_json
    respond_to do |format|
      format.json { render json: all_choices, status: :ok }
    end
  end
end

I also create a get route for that model

constraints(lambda { |req| req.format.symbol.in? [:json, :csv, :xlsx] }) do

  post '/login' => 'sessions#create'

  namespace :api, defaults: { format: :json } do
    get '/forms/choices' => 'forms#choices' 
  end
end

and from my front-end(Using React)

getDropdown(){
  ajax({
    url: `/api/forms/choices.json`,
      dataType: 'json',
      success: data => {
        this.setState({
          choices: data
        });
      },
      error: () => {
        console.log("Error retrieving data")
      }
    })
}

When I use console.log(this.state.choices) to print out the data I got, I got empty object. I am relatively new to rails and understand that it is convention over configuration, so I believe I am missing something small here.

Any help is appreciated.

Upvotes: 0

Views: 84

Answers (2)

MrShemek
MrShemek

Reputation: 2483

The explanation is simple. You have the following route:

get '/forms/:user_id' => 'forms#show'

So, it will match:

/api/forms/1
/api/forms/2

But it also matches:

/api/forms/otherstuff
/api/forms/some_string
/api/forms/choices

In general, you should read your route as:
match /api/forms and then, if there is anything else added to the route, treat it as a :user_id.

This is described in the Rails documentation:

Rails routes are matched in the order they are specified, so if you have a resources :photos above a get 'photos/poll' the show action's route for the resources line will be matched before the get line. To fix this, move the get line above the resources line so that it is matched first.

Source: http://guides.rubyonrails.org/routing.html#crud-verbs-and-actions

Upvotes: 1

ZpfSysn
ZpfSysn

Reputation: 889

The problem is my route. There are other routes before the choice route in fact.

constraints(lambda { |req| req.format.symbol.in? [:json, :csv, :xlsx] }) do

  post '/login' => 'sessions#create'

  namespace :api, defaults: { format: :json } do
    get '/forms/otherstuff' => 'forms#otherstuff'
    get '/forms/:user_id' => 'forms#show'   <----
    get '/forms/choices' => 'forms#choices' <----
  end
end

I fixed it by switching the choice route with the route above it, just simply switched their places and it worked.

constraints(lambda { |req| req.format.symbol.in? [:json, :csv, :xlsx] }) do

      post '/login' => 'sessions#create'

      namespace :api, defaults: { format: :json } do
        get '/forms/otherstuff' => 'forms#otherstuff'
        get '/forms/choices' => 'forms#choices'  <----
        get '/forms/:user_id' => 'forms#show'    <----
      end
    end

I have no idea why, I would love to get a explanation of this rail behavior

Upvotes: 0

Related Questions