I am learning api on rails,and my code is below
routes.rb
require 'api_constraints'
Rails.application.routes.draw do
devise_for :users
namespace :api, defaults: { format: :json }, constraints: { subdomain: 'api' }, path: '/' do
scope module: :v1, constraints: ApiConstraints.new(version: 1, default: true) do
resources :users, :only => [:show]
end
end
end
users_controllers.rb
class Api::V1::UsersController < ApplicationController
respond_to :json
def show
respond_with User.find(params[:id])
end
end
when I run the rails server with localhost:3000/users/1 then It gives me the error No route matches
Then i checked routes using rake routes and it is included in my routes
`api_user GET /users/:id(.:format) api/v1/users#show'
but i don't know why it gives me the error
api_constraints.rb
class ApiConstraints
def initialize(options)
#version = options[:version]
#default = options[:default]
end
def matches?(req)
#default || req.headers['Accept'].include?("application/vnd.marketplace.v#{#version}")
end
end
`
Try the following:
api.lvh.me:3000/api/v1/users/1
You've setup a constraint that requires an api sub domain. You'll need to remove the constraint to make the following work:
lvh.me:3000/api/v1/users/1
Note: lvh.me points to 127.0.0.1
Related
I am practicing to make API in rails. The api has currently only one end point which receives a url via get request. My routes are:
Rails.application.routes.draw do
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
namespace :api, defaults: { format: :json } do
namespace :v1 do # resources :orders
get "*link" => "application#parse_link"
end
end
end
My Application Controller Code:
require 'open-uri'
class Api::V1::ApplicationController < ActionController::Base
respond_to :json
# protect_from_forgery with: :exception
def parse_link
begin
url = URI.parse(params[:link])
doc = Nokogiri::HTML(open(url).read)
rescue
redirect_to 'http://localhost:3000/'
end
end
end
When I send urls like this:
http://localhost:3000/api/v1/http://stackoverflow.com/questions/41138538/dynamic-urls-in-rails-params
It works fine
But the following type of urls does not work:
http://localhost:3000/api/v1/http://stackoverflow.com/
In this case, it splits the link and give me these params
<ActionController::Parameters {"link"=>"http:/stackoverflow", "format"=>"com"} permitted: true>
As you can see it splits the given url and save half of it in link param and the ".com" part in format params.
Thanks
Try changing defaults to constraints:
Rails.application.routes.draw do
namespace :api, constraints: { format: :json } do
namespace :v1 do # resources :orders
get "*link" => "application#parse_link"
end
end
end
Notice: it will constraint format to be json, not only set it as default. Rails treated .com at end of your URL as response type.
I'm getting this error.When I want to run te server on localhost:3000/api/v1/songs.json
Routing Error
uninitialized constant API::V1::SongsController.
Thats my routes.rb file:
Rails.application.routes.draw do
namespace :api do
namespace :v1 do
resources :songs, only: [:index, :create, :update, :destroy]
end
end # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
Routes
Routes match in priority from top to bottom
Helper HTTP Verb Path Controller#Action
Path / Url
Path Match
api_v1_songs_path GET /api/v1/songs(.:format)
api/v1/songs#index
POST /api/v1/songs(.:format)
api/v1/songs#create
api_v1_song_path PATCH /api/v1/songs/:id(.:format)
api/v1/songs#update
PUT /api/v1/songs/:id(.:format)
api/v1/songs#update
DELETE /api/v1/songs/:id(.:format)
api/v1/songs#destroy
and thats my SongsController:
class Api::V1::SongsController < Api::V1::BaseController
def index
respond_with Song.all
end
def create
respond_with :api, :v1, Song.create(song_params)
end
def destroy
respond_with Song.destroy(params[:id])
end
def update
song = Song.find(params["id"])
song.update_attributes(song_params)
respond_with song, json: song
end
private
def song_params
params.require(:song).permit(:id, :name, :singer_name, :genre, :updated_at, :tag)
end
end
I'm going to copy how we have this running, cause I cannot see a direct difference between your code and our code....
routes.rb
constraints subdomain: Settings.subdomains.api do # you can ignore this
namespace :api do
namespace :v1 do
resources :maps, only: [] do
collection do
get :world_map
end
end
end
end
maps_controller.rb
module Api
module V1
class MapsController < BaseController
def world_map; end
end
end
end
routes output
world_map_api_v1_maps GET /v1/maps/world_map(.:format) api/v1/maps#world_map {:subdomain=>"api"}
The spelling is really crucial from what I can see.
The directort structure for us:
app/controllers/api/v1/maps_controller.rb
So check those points and this should work because it's standard Rails magic.
In my API, I've implemented the following way of showing a users account in JSON (very simple).
class API::V1::UsersController < ApplicationController
respond_to :json
def show
respond_with User.find(params[:id])
end
end
This is my routes.rb
Rails.application.routes.draw do
devise_for :users
# Api definition
namespace :api, defaults: { format: :json } do
namespace :v1 do
resources :users, :only => [:show]
end
end
end
As of now, this works by allowing my to browse to the URL: http://localhost/api/v1/users/1 to show the user account with ID 1. What I want is to be able to type http://localhost/api/v1/users/show?id=1 to allow for the possibility of specifying more than just the one parameter to the show method.
I've setup a rails application that expects the parameters to be specified in this way in the past but this time around it's not working. I'm assuming it's something to do with the way I've defined the route in my routes.rb (first time I'm using the resource do notation). Any help would be greatly appreciated. thanks!
Figured it out.
Routes.rb:
Rails.application.routes.draw do
devise_for :users
# Api definition
namespace :api, defaults: { format: :json } do
namespace :v1 do
#resources :users, :only => [:show]
get '/users/show/' => 'users#show'
end
end
end
My routes.rb is :
Rails.application.routes.draw do
namespace :api, path: "/", constraint: { subdomain: "api" }, defaults: { format: :json } do
scope module: :v1 do
resources :users, only: [:show]
end
end
end
My users_controller.rb is :
class Api::V1::UsersController < ApplicationController
respond_to :json
def show
respond_with User.find(params[:id])
end
end
My test is :
require 'test_helper'
class Api::V1::UsersControllerTest < ActionController::TestCase
test '#show displays the specific user' do
#user = FactoryGirl.create(:user)
get :show, id: #user.id, format: :json
assert_response :success
end
end
Why does this test give the following error:
ActionController::UrlGenerationError: No route matches {:action=>"show", :controller=>"api/v1/users", :format=>:json, :id=>1}
I just needed to add the constraint to the test:
get :show, id: #user.id, format: :json, :constraint=>{:subdomain=>"api"}
Attempting to create an API using doorkeeper. When I sign into my account and the session user is authenticated and access my API on
http://localhost:3000/api/v1/trials
I get a routing error page saying "uninitialized constant TrialsController" and a rake routes listing. Including:
trials_path GET /api/v1/trials(.:format) trials#index
I am using rails version 4.0.3, ruby 2.0.0. This is my config/routes.rb file:
MyApp::Application.routes.draw do
devise_for :users
use_doorkeeper :scope => 'oauth2' do
end
root :to => 'welcome#index'
scope 'api' do
scope 'v1' do
resources :trials
end
end
end
My app/ dir contains:
app/
controllers/
application_controller.rb
welcome_controller.rb
api/
v1/
trials_controller.rb
My trials_controller.rb is:
module Api::V1
class TrialsController < ::ApplicationController
doorkeeper_for :all
def index
#trials = Trials.all
end
def show
...
end
...
end
end
UPDATE:
When I change the routes.rb to namespace the trails controller like so:
namespace :api do
namespace :v1 do
resources :trails
end
end
I get a "no route matches" error when attempting to access:
http://localhost:3000/api/v1/trials(.json)
(With or without the extension.)
I have also added to trials#index:
def index
#trials = Trials.all
respond_to do |format|
format.json { render :json => #trials }
format.xml { render :xml => #trials }
end
end
Also with no luck.
I'm not sure how it would play out against doorkeeper but I have a similar API structure in an app. I have the following in my routes (matching what Sergio notes)
namespace :api, defaults: {format: 'json'} do
namespace :v1 do
resources :api_controller_1
resources :api_controller_2
end
end
And here's how I build my API classes:
module Api
module V1
class ApiNamedController < ApplicationController
# code
end
end
end