uninitialized constant API::V1::UserController - ruby-on-rails

I know there are already a lot of questions about this on stackoverflow, but none of them works in my case.
In my routes.rb
Exer9::Application.routes.draw do
namespace :api, defaults: {format: 'json'} do
namespace :v1 do
resources :users
end
end
end
exer9/app/controllers/api/v1/users_controller.rb
module Api
module v1
class UsersController < ApplicationController
# GET /user
# GET /user.json
def index
#users = User.all
render json: #users
end
def new
end
def update
end
# GET /user/1
# GET /user/1.json
def show
#user = User.find(params[:id])
render json: #user
end
def create
#user = User.new(params[:user])
if #user.save
render json: #user
else
render json: #user.errors
end
end
def delete
end
def destroy
end
end
end
end
Update
This is my ApplicationController file
class ApplicationController < ActionController::API
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
# protect_from_forgery with: :exception
end
The error message that I get is:
superclass mismatch for class UsersController
Extracted source (around line #2):
1
2
3
4
5
6
class Api::V1::UsersController < ApplicationController
# GET /user
# GET /user.json
def index
Rails.root: /home/steven/Desktop/weekly-exercises/exer9
Application Trace | Framework Trace | Full Trace
app/controllers/api/v1/users_controller.rb:2:in `<top (required)>
'
Any help here is really appreciated!

Use shorter syntax, like:
class Api::V1::UsersController < ApplicationController
# your code goes here
end
Also, do you restart rails server after renaming classes and files?

Make sure your folder structure is correct:
users_controller.rb
should be found:
app/controllers/api/v1/users_controller.rb

You can use it like this
In routes.rb
namespace :api, defaults: {format: 'json'} do
scope module: :v1, constraints: ApiConstraints.new(version: 1 , default: true) do
resources :users
end
end
In controller
class Api::V1::UsersController < ApplicationController
# Your code here
end

Related

Rails api controller doesn't inherit method from the parent class

Doing API for my first Rails project.
I have base class ApiController for all the APIs:
module Api
class ApiController < ::ApplicationController
respond_to :json
skip_before_action :verify_authenticity_token
def index
#collection = resource_class.all
render json: #collection.as_json(as_json_collection)
end
private
def resource_class
raise NotImplementedError
end
def as_json_collection
{}
end
end
end
And I have child class UsersController:
module Api
class UsersController < ApiController
private
def resource_class
User
end
def resource_params
params.require(:user).permit(:name, :email)
end
end
end
My routes:
namespace :api do
resources :users
end
Then I'm going to my_app/api/users I have error:
The action 'index' could not be found for Api::UsersController
But then I changing UsersController writing it's own index class, everything works fine and I'm having all my Users in JSON format.
I've alrady tried to comment all private marks in both classes, but that doesn't help.
I don't want to write an API for every entity in my project and I'd like to avoid this problem in future.
I got it to work with this:
module Api
class ApiController < ::ApplicationController
def index
respond_to do |format|
format.json { render json: '"abc"' }
end
end
end
end
module Api
class UsersController < ApiController
end
end
The URL was http://localhost:3000/api/users.json
So for you I suggest:
module Api
class ApiController < ::ApplicationController
def index
respond_to do |format|
format.json do
#collection = resource_class.all
render json: #collection.as_json(as_json_collection)
end
end
end
end
end
module Api
class UsersController < ApiController
def resource_class
User
end
def resource_params
params.require(:user).permit(:name, :email)
end
end
end
Its supposed to be like this:
class Api::ApiController < ApplicationController
and do not forget to remove extra end, end of the file!
#sample
- api(folder)
-- api_controller.rb (Api::ApiController < ApplicationController)
-- users_controller.rb (Api::UsersController < Api::ApiController)
application_controller.rb
You need to read this my friend:
rails routes
When you do this:
namespace :api do
resources :users
end
rails creates CRUD routes automatically which means that my_app/api/users will translate to: .../users#index.
Do this to see your routes created by rails:
rails routes and for specific word (e.g. user): rails routes | grep user
Seeing is believing ;)

Authorization error at ruby on rails' api project with Devise and ActiveAdmin

I'm beginner of Ruby on Rails.
I've added gems, Devise and ActiveAdmin, to make management screen and to make authentication system to my api.
At first, I added ActiveAdmin. After db-migrated, I requested localhost:3000/admin/login and it returned 200(OK) status and the login interface to me.
Next, I added Devise. After some coding for authentication and db-migration, localhost:3000/admin/login returned 401 status to me and "{"error":"You need to sign in or sign up before continuing."}" was written at localhost:3000/admin/login page. And absolutely It didn't show the login interface to me.
Here, I don't know why authorization error happened before authorization.
Mac OS version: 10.13.1
Ruby version: 2.4.2
Gem version: 2.7.4
Rails version: 5.1.6
application_contorller.rb
class ApplicationController < ActionController::Base
include AbstractController::Translation
before_action :authenticate_user_from_token!
respond_to :json
def authenticate_user_from_token!
auth_token = request.headers['Authorization']
if auth_token
authenticate_with_auth_token(auth_token)
else
authenticate_error
end
end
private
def authenticate_with_auth_token(auth_token)
unless auth_token.include?(':')
authenticate_error
return
end
user_id = auth_token.split(':').first
user = User.where(id: user_id).first
#current_user = user
if user && Devise.secure_compare(user.access_token, auth_token)
# ログインを許可
sign_in user, store: false
else
authenticate_error
render json: {error: "hello_error"}, status: 401
end
end
def authenticate_error
render json: {error: t('devise.failure.unauthenticated')}, status: 401
end
end
app/controller/v1/sessions_controller.rb
module V1
class SessionsController < ApiController
skip_before_action :authenticate_user_from_token!
# POST /v1/login
def create
#user = User.find_for_database_authentication(email: params[:email])
return invalid_email unless #user
if #user.valid_password?(params[:password])
sign_in :user, #user
render json: #user, serializer: SessionSerializer, root: nil
else
invalid_password
end
end
def invalid_email
warden.custom_failure
render json: {error: t('invalid_email')}
end
def invalid_password
warden.custom_failure
render json: {error: t('invalid_password')}
end
end
end
config/routes.rb
Rails.application.routes.draw do
devise_for :admin_users, ActiveAdmin::Devise.config
ActiveAdmin.routes(self)
devise_for :users
namespace :admin, defaults: {format: :json} do
delete 'sign_out', to: "sessions#destroy"
resources :login, only: [:create], controller: :sessions
end
namespace :v1, defaults: {format: :json} do
resources :login, only: [:create], controller: :sessions
end
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end

uninitialized constant Api

I am still a beginner concerning ruby on rails and I am trying to create a simple API but I am facing this error :"uninitialized constant Api"
ideas_controller.rb
module Api
module V1
class ItemsController < BaseController
def index
#ideas = Idea.all
render json: #ideas
end
end
end
end
routes.db
Rails.application.routes.draw do
namespace :api do
namespace :v1 do
resources :ideas
end
end
end
application_controller.rb
class ApplicationController < ActionController
protect_from_forgery with: :null_session
end
base_controller.rb
module Api
module V1
class BaseController < ApplicationController
respond_to :json
end
end
The project's directories:
The server's error:
I have also tried this approach and changed the project's structure to :
Also, I have enabled :
config.eager_load = true
After that I got the following error:
`block in load_missing_constant': uninitialized constant Api::V1::BaseController (NameError)
If you're in the development environment, eager loading is turned off by default, which can be fixed by turning on eager load (change to config.eager_load = true in config/development.rb). Eager loading will allow the whole Rails app to be loaded when the server starts (which is slightly slower), but will fix your problem since that file will be loaded.
This error because module Api is not defined before, I guess if you made like this it gonna work. from an answer here
module Api
module V1
class IdeasController < ApplicationController
def index
#ideas = Idea.all
render json: #ideas
end
end
end
end
another solution could be like this:
module Api
module V1
end
end
class Api::V1::IdeasController < ApplicationController
def index
#ideas = Idea.all
render json: #ideas
end
end
hope it helps.
Try this in your ideas controller
module Api
module V1
class IdeasController < Api::V1::BaseController
def index
#ideas = Idea.all
render json: #ideas
end
end
end
end
And define your base controller in the following way
class Api::V1::BaseController < ApplicationController
respond_to :json
end

Rails controller class does not inherit a method from the parent class

I'm following a tutorial on how to create a REST Api using the rails-api gem.
In the tutorial, most of the API logic is encapsulated in the base class file app/controllers/api/v1/api_base_controller.rb
module Api
module V1
class ApiBaseController < ApplicationController
protect_from_forgery with: :null_session
before_action :set_resource, only: [:destroy, :show, :update]
respond_to :json
private
#Returns the resource from the created instance variable
##return [Object]
def get_resource
instance_variable_get("##{resource_name}")
end
#Returns the allowed parameters for searching
# Override this method in each API controller
# to permit additional parameters to search on
# #return [Hash]
def query_params
{}
end
#Returns the allowed parameters for pagination
# #return [Hash]
def page_params
params.permit(:page, :page_size)
end
# The resource class based on the controller
# #return [Class]
def resource_class
#resource_class ||= resource_name.classify.constantize
end
# The singular name for the resource class based on the controller
# #return [String]
def resource_name
#resource_name ||= self.controller_name.singularize
end
#Only allow a trusted parameter "white list" through.
# If a single resource is loaded for #create or #update,
# then the controller for the resource must implement
# the method "#{resource_name}_params" to limit permitted
# parameters for the individual model.
def resource_params
#resource_params ||= self.send("#{resource_name}_params")
end
#Use callbacks to share common setup or constraints between actions.
def set_resource(resource = nil)
resource ||= resource_class.find(params[:id])
instance_variable_set("##{resource_name}", resource)
end
#POST /api/v1/{plural_resource_name}
def create
set_resource(resource_class.new(resource_params))
if get_resource.save
render :show, status: :created
else
render json: get_resource.errors, status: :unprocessable_entity
end
end
#DELETE /api/v1/{plural_resource_name}/:id
def destroy
get_resource.destroy
head :no_content
end
#GET /api/v1/{plural_resource_name}
def index
plural_resource_name = "##{resource_name.pluralize}"
resources = resource_class.where(query_params).page(page_params[:page]).per(page_params[:page_size])
instance_variable_set(plural_resource_name, resources)
respond_with instance_variable_get(plural_resource_name)
end
#GET /api/v1/{plural_resource_name}/1
def show
respond_with get_resource
end
#PATCH/PUT /api/{plural_resource_name}/1
def update
if get_resource.update(resource_params)
render :show
else
render json: get_resource.errors, status: :unprocessable_entity
end
end
end
end
end
The model controllers inherit from this ApiBaseController
one of the model controllers (albums_controllers.rb) looks like this:
module Api
module V1
class AlbumsController < Api::V1::ApiBaseController
private
def album_params
params.require(:album).permit(:title)
end
def query_params
params.permit(:title, :artist_id)
end
end
end
end
I also have this in routes.rb
Rails.application.routes.draw do
namespace :api, defaults: {format: 'json'} do
namespace :v1 do
resources :albums, :artists
end
end
end
when I do http://localhost:3000/api/v1/artists on the browser, i get this error:
`The action 'index' could not be found for Api::V1::ArtistsController`
I have also noted that the ApplicationController generated by the rails-api gem inherits from ActionController::API and not ActionController::Base but i'm not sure whether this is the problem.
private methods are not available to subclasses. If you REALLY want to hide all of those methods but make it available to subclasses, use protected instead.

Naming error in rails - creating API Controllers

I have my directory under app/controllers set up as such: api/v1/sessions_controller.rb I then have a BaseController: api/v1/base_controller.rb
I then set up each class to look as such:
module Api
module V1
class BaseController < ApplicationController
respond_to :json
before_action :default_json
protected
def default_json
request.format = :json if params[:format].nil?
end
def auth_only!
render :json: {}, status: 401 unless current_user
end
end
end
end
And then Sessions:
module Api
module V1
class SessionsController < BaseController
def create
user = User.authenticate(params[:user_name], params[:password])
if sign_in(user)
set_up_cookie(user)
render json: create_session_data, status: 201
else
invalid_user_crendentials
end
end
end
end
end
The tests are set up the same way, for example the sessions test is:
require 'spec_helper'
describe Api::V1::SessionsController do
before(:each) do
#user = FactoryGirl.create(:user)
end
context "Create a session" do
it "should NOT create a session" do
post :create
response.response_code.should == 401
end
end
end
The Error:
'<module:V1>': uninitialized constant Api::V1::BaseController (NameError)
Try formatting your naming slightly differently.
class Api::V1::BaseController < ApplicationController
# code
end
and
class Api::V1::SessionsController < BaseController
# might need to name this Api::V1::BaseController
end

Resources