Eventful React/Rails project
Part 1
Repo | Starter Code | Finished Code |
---|---|---|
Rails API | 01_start | 01_end |
If you’d like to code along with me here, clone down the repo to your machine and checkout the 01_start
branch. Run bundle install
and then rails db:create
and you should be good to go.
For our initial setup, we’ll be following the Devise JWT Tutorial up to and including the Create User Model section. Later on in the series, we’ll complete the configuration to support JWT auth. For now, we just want to have the User
model set up so we can set up its relationship with the Event
model. If you want to clone down the GitHub repo and work along with me, you can checkout the 01_start
branch and work along with me. Note, you’ll probably want to fork the repo to your own account first, that way you’ll be able to push if you want to. If you’re okay just coding along locally without pushing to GitHub, the code below will clone my repo directly to your machine.
git clone git@github.com:DakotaLMartinez/eventfull-api.git
git checkout 01_start
Then, you can compare that branch to the 01_end
branch if you find anything going wrong.
git diff 01_end
Setting up CORS
To start, we want to set up a Cross Origin Resource Sharing (CORS) policy. We do this so that our rails API will be able to receive requests from origins. This is useful in the case where our API and our React code are managed separately and will be hosted on different domains when we deploy. To configure CORS, you’ll first want to find the line in the gemfile that refers to the rack-cors
gem and uncomment that line.
gem 'rack-cors'
Then install it by running
bundle install
and finally, we’ll copy this into cors.rb configuration file.
# config/initializers/cors.rb
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins '*'
resource(
'*',
headers: :any,
expose: ["Authorization"],
methods: [:get, :patch, :put, :delete, :post, :options, :show]
)
end
end
We’re allowing full access to our api from all origins and to all of our resources. If we wan to, we can be more restrictive here. For example, if we intend to only allow requests to our API from our react application, we could put origins 'http://localhost:3000'
in the configuration. We can also add a comma after that to specify where we’re hosting our application:
origins 'http://localhost:3000', 'https://myreactappdomain.com'
One notable downside to doing this at this point is that we’d be unable to use postman to send requests to our API without adding some additional configuration. So, we’re going to stick with origins '*'
for now.
Adding additional dependencies
As our next step, let’s add in some gems. We’re only going to do surface level configuration for these now. We’ll come back and go into greater depth when we’re ready to use their features. For now let’s add these to the gemfile:
gem 'devise'
gem 'devise-jwt'
gem 'jsonapi-serializer'
This is a slight departure from the tutorial linked above. The reason for this is that Netflix has stopped maintaining the fast jsonapi gem and the JSON API Serializer is a maintained fork of that gem. To add these dependencies, run
bundle install
Now let’s get our initial devise configuration set up.
rails g devise:install
Next, find this line in devise.rb initializer:
# config.navigational_formats = ['*/*', :html]
and replace it with this:
config.navigational_formats = []
We do this so that devise won’t try to generate redirects after sign_in/sign_up. Also, let’s add the following line to config/environments/development.rb. This will be a placeholder for now as we may add the confirmable
module later to allow confirming a user by their email.
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
Create a Devise User
You can create a devise model to represent a user. It can be named as anything. So, I’m gonna be going ahead with User. Run the following command to create User model.
rails generate devise User
Then double check the migrations. Make sure you’ve got everything there that you want and then run:
rails db:create
rails db:migrate
Adding Groups
rails g scaffold Group name
For our app, we don’t need update and destroy for groups so we’ll remove the update and destroy actions from the GroupsController and update the routes.rb file like so:
resources :groups, except: [:update, :destroy]
We can test out our routes by running
rails routes | grep groups
We should get something like this:
groups GET /groups(.:format) groups#index
POST /groups(.:format) groups#create
group GET /groups/:id(.:format) groups#show
Next, we can run the migration to add the table.
rails db:migrate
Setting up ActiveStorage to Support File Uploads
At this point, we’ll take a look at another of my tutorial about attaching file uploads to a model for use in a rails API only application.
We’ll start by adding active_storage migrations:
rails active_storage:install
You can read more about how these migrations support file uploads in this section of my tutorial. For now the important thing to note is that this will allow us to attach uploads to any model we like by adding a macro to it like this: has_one_attached :image
or has_many_attached :images
.
We can run rails db:migrate
to add these tables to our database and enable support for file uploads.
Adding the Event Model
Now that we’ve got the ActiveStorage migration’s tables, we’re going to need a model we can attach uploads to. In our case, we’ll be creating an Event resource that can have a poster attached.
rails g scaffold Event name start_time:datetime end_time:datetime location
Now, we’ll need to make a couple of changes to allow uploading a poster. First, we’ll add a macro to the Event model:
class Event < ApplicationRecord
has_one_attached :poster
end
Next, we’ll need to permit a poster through the params in the EventsController:
def event_params
params.require(:event).permit(:name, :start_time, :end_time, :location, :poster)
end
Before we move on, let’s check the migration to create our events table. Add these two lines to the bottom
t.references :group, null: false, foreign_key: true
t.references :users, null: false, foreign_key: true
So we’ll have this for our migration:
class CreateEvents < ActiveRecord::Migration[6.1]
def change
create_table :events do |t|
t.string :name
t.datetime :start_time
t.datetime :end_time
t.string :location
t.references :group, null: false, foreign_key: true
t.references :users, null: false, foreign_key: true
t.timestamps
end
end
end
now let’s run it
rails db:migrate
Now we can make a commit.
Add Relationships
Finally, we’re going to create our relationships.
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_many :events
end
class Group < ApplicationRecord
has_many :events
end
class Event < ApplicationRecord
has_one_attached :poster
belongs_to :user
belongs_to :group
end
When we get started building out our React frontend, we’ll need to add in serializers as well so we can actually include related data in our json responses from the API. For now, this should be a good start. If you like, you can check out the resources below to get a sense of where we’re going.
Resources
- Domain Model Spreadsheet
- Postico
- ActiveStorage Rails API File Uploads Tutorial
- Devise JWT Tutorial
- JSONAPI-Serializer gem (replacement for fast-jsonapi)
Links to Code for Study Groups
Part | Starter Code | Ending Code |
---|---|---|
1 | Starter Code | Ending code |