
Rails API
A starting template for a Rails API with login/sign-up functionality, PostgreSQL, RSpec and Pundit.
Repo
This template is a public repo on GitHub, and can be found here.
Specifications
This project template is setup with Ruby 3.3.0 and Rails 7.1.3.2, the Pundit authorization gem, and has a PostgreSQL database.
Testing has been setup with RSpec, including factory_bot, Faker and Database Cleaner Adapter for ActiveRecord.
It includes authentication setup with Rails' has_secure_password (see 'Authentication' and 'Endpoints' sections below).
It also includes linting with a custom setup of Rubocop, and a GitHub workflow which run two checks, tests and linting, on each push or pull request to master.
Setup
Feel free to clone this template or use it any way you see fit. However, the simplest way to get started is to:
-
Navigate to the template on GitHub.
-
Click 'Use this template'.

-
On the next screen, fill-in a repository name and click 'Create repository from template'.

-
On the next page, click the 'Code' button, and in the dropdown, copy the url beneath 'HTTPS'.

-
In your local terminal, CD into the folder where you want to store the project. Then type
git clone [THE URL YOU JUST COPIED], for examplegit clone https://github.com/jro31/my-new-project.git, and pressEnter.
-
CD into the created repo, for example
cd my-new-project.
-
To check that all specs are passing, run
bundle exec rspec. You should get 0 failures.

-
Run
rails sto start the server. Then navigate to localhost:3001. If all is well, you should see{"status":"It's working"}.

Notes
Development
- Run the development server with
rails s. - The default port is 3001.
- So when running, the api can be accessed at localhost:3001.
- Update the
origins "http://localhost:3000"line ofconfig/initializers/cors.rbwith the development URL of your frontend. - Update both
keyvalues ofconfig/initializers/session_store.rbwith the name of your app. - Update all instances of
rails_api_templateinconfig/cable.yml,config/database.ymlandconfig/environments/production.rbto the name of your app, for example:config/cable/yml- Update
channel_prefix: rails_api_template_productiontochannel_prefix: my_new_project_production
- Update
config/database.yml- Update
database: rails_api_template_developmenttodatabase: my_new_project_development - Update
#username: rails_api_templateto#username: my_new_project - Update
database: rails_api_template_testtodatabase: my_new_project_test - Update
database: rails_api_template_productiontodatabase: my_new_project_production - Update
username: rails_api_templatetousername: my_new_project - Update
password: <%= ENV["RAILS_API_TEMPLATE_DATABASE_PASSWORD"] %>topassword: <%= ENV["MY_NEW_PROJECT_DATABASE_PASSWORD"] %>
- Update
config/environments/production.rb- Update
# config.active_job.queue_name_prefix = "rails_api_template_production"to# config.active_job.queue_name_prefix = "my_new_project_production"
- Update
- This is necessary for nothing but brevity if you only ever use this template once. However, if you use it multiple times without updating these values (particularly those in
config/database.yml), you will run into issues such as both apps will start using the same development database.
Production
- Update the
origins "https://myappurl.com"line ofconfig/initializers/cors.rbwith the production URL of your frontend. - Update the
domainvalue ofconfig/initializers/session_store.rbwith the production URL of your API.
Authentication
This template includes authentication setup using has_secure_password. This includes:
-
A User model with email/password validations (and specs for these validations).
-
A registrations controller that includes a
#createaction:- This action allows a user to register (sign-up).
- If successful, it returns the status
:created(201), with a json that includes the user ID, and the user email. - If unsuccessful, it returns the status
:unprocessable_entity(422) with an error message. - This action has a request spec.
-
A sessions controller that has three actions:
-
The
#createaction allows a user to login.- If they provide a correct email/password combo, it returns the status
:created(201), with a json that includes the user ID, and the user email. - Otherwise it returns the status
:unauthorized(401) with an error message.
- If they provide a correct email/password combo, it returns the status
-
The
#logged_inaction utilises the CurrentUserConcern to check if a user is logged-in.- If they are it returns
logged_in: trueand the user, if not it returnslogged_in: false.
- If they are it returns
-
The
#logoutaction allows a user to logout. -
All actions have request specs.
-
Endpoints
GET http://localhost:3001/
- Root, to check that the API is working.
POST http://localhost:3001/api/v1/registrations
- To register a user.
- Requires a
userparam containing anemail,passwordandpassword_confirmation, for example:
fetch('http://localhost:3001/api/v1/registrations', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
user: {
email: 'example@email.com',
password: 'password',
password_confirmation: 'password',
},
}),
credentials: 'include',
});
POST http://localhost:3001/api/v1/sessions
- To create a session (login a user).
- Requires a
userparam containing anemailandpassword, for example:
fetch('http://localhost:3001/api/v1/sessions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
user: {
email: 'example@email.com',
password: 'password',
},
}),
credentials: 'include',
});
GET http://localhost:3001/api/v1/logged_in
- To check if a user is logged-in.
- Example request:
fetch('http://localhost:3001/api/v1/logged_in', {
credentials: 'include',
});
DELETE http://localhost:3001/api/v1/logout
- To logout a user.
- Example request:
fetch('http://localhost:3001/api/v1/logout', {
method: 'DELETE',
credentials: 'include',
});