Skip to content

Init from zauberware/rails-devise-graphql and update somethings that belongs to my organization needed.

License

Notifications You must be signed in to change notification settings

kokorolx/boiler_rails_graphql_docker

Repository files navigation

💎 Rails 6 boilerplate with devise, JWT, graphQL, CanCanCan and RailsAdmin.

Maintenance GitHub license GitHub top language GitHub issues

This is a boilerplate to build your next SaaS product. It's a RubyOnRails 6 backend with authentication, GraphQL API, Roles & Ability management and a admin dashboard. It works nicely together with clients made with Angular, React, Vue.js, React.Native, Swift, Kotlin or any other client framework which implements the JSON Web Tokens philosophy.

Versions

  • Current ruby version 2.6.x
  • Bundler version 2.1.4
  • Rails version 6.0.X
  • PostgreSQL Server as db connector

Dependencies

This boilerplate works like a charm with the following gems:

  • pg
  • devise
  • devise_invitable
  • graphql
  • graphql-auth
  • graphql-errors
  • rack-cors
  • rack_attack
  • rails_admin
  • cancancan
  • image_processing
  • mini_magick
  • puma
  • bootsnap
  • friendly_id
  • dotenv

🚀 Quick start

git clone https://github.com/zauberware/rails-devise-graphql my-saas-backend
cd my-saas-backend

Clone env_sample to .env for local development. We set it up with default rails 3000 and client 8000 ports:

cp env_sample .env

How to run on local machine

You need nodejs and yarn installed.

Run yarn && bundle && rails s to make the magic happen.

How to run with Docker

You need docker and docker-compose installed (for MacOS just use official app).

Provisioning

Run the following commands to prepare your Docker dev env:

$ docker-compose build
$ docker-compose run runner yarn install
$ docker-compose run runner ./bin/setup

It builds the Docker image, installs Ruby and NodeJS dependencies, creates database, run migrations and seeds.

You're all set! Now you're ready to code!

Commands

  • Running the app:

You can run the Rails up using the following command:

$ docker-compose up rails

If you want to run Webpack Dev server as well:

$ docker-compose up rails webpacker

Dip

You can also use dip–CLI utility for straightforward provisioning and interacting with an applications configured by docker-compose.

To install dip copy and run the command below:

$ gem install dip

Then use the following commands:

# provision application
dip provision

# run web app with all debuging capabilities (i.e. `binding.pry`)
dip rails s

# run rails console
dip rails c

# run webpacker dev server
dip up -d webpacker
# `-d` - mean that service will run in detached (background) mode

Download a GraphQL client like GraphiQL or others to access and test your API. Point the GraphQL IDE to http://0.0.0.0:3000/graphql

Note: Make sure that the .env file is included in the root of your project and you have defined CLIENT_URL and DEVISE_SECRET_KEY. Read more about the JSON Web Token this. There are plenty of packages available.

🎁 What's included?

1. Database

The app uses a PostgreSQL database. It implements the connector with the gem pg. The app already includes a User and a Company model with basic setup. We see an Company as a company with it's users. We did not add multi-tenancy to this app. If you want to do it by yourself check out the apartment gem.

2. Authentication

The app uses devise's logic for authentication. For graphQL API we use the JWT token, but to access the rails_admin backend we use standard devise views, but registration is excluded.

Change devise settings under config/initializers/devise.rb and config/initializers/graphql_auth.rb.

Invitations

Admins of a company can invite new users. The process is handled with devise_invitable. We added a inviteUser and acceptInvite mutation to handle this process via graphql.

Like in the reset password process we redirect the users to the frontend domain and not to backend.

3. JSON Web Token

graphql-auth is a graphql/devise extension which uses JWT tokens for user authentication. It follows secure by default principle.

4. GraphQL

graphql-ruby is a Ruby implementation of GraphQL. Sadly it's not 100% open source, but with the free version allows you amazing things to do. See the Getting Started Guide and the current implementations in this project under app/graphql/.

Filters, Sorting & Pagination

Our BaseResolver class provides everything you need to achieve filter, sorting and pagination. Have a look at the resolver resolvers/users/users.rb:

How to:

Include SearchObject module in your resolver:

  class Users < Resolvers::BaseResolver
      include ::SearchObject.module(:graphql)

Define the scope for this resolver:

scope { resources }

def resources
  ::User.accessible_by(current_ability)
end

Set a connection_type as return type to allow pagination:

type Types::Users::UserType.connection_type, null: false

Set order_by as query option and define allowed order attributes:

option :order_by, type: Types::ItemOrderType, with: :apply_order_by
def allowed_order_attributes
  %w[email first_name last_name created_at updated_at]
end

Allow filtering with a custom defined filter object & define allowed filter attributes:

# inline input type definition for the advanced filter
class UserFilterType < ::Types::BaseInputObject
  argument :OR, [self], required: false
  argument :email, String, required: false
  argument :first_name, String, required: false
  argument :last_name, String, required: false
end
option :filter, type: UserFilterType, with: :apply_filter
def allowed_filter_attributes
  %w[email first_name last_name]
end

Schema on production

We have disabled introspection of graphQL entry points here app/graphql/graphql_schema.rb. Remove disable_introspection_entry_points if you want to make the schema public accessible.

5. CORS

Protect your app and only allow specific domains to access your API. Set CLIENT_URL= in .env to your prefered client. If you need advanced options please change the CORS settings here config/initializers/cors.rb.

6. App server

The app uses Puma as the web serber. It is a simple, fast, threaded, and highly concurrent HTTP 1.1 server for Ruby/Rack applications in development and production.

7. UUID

The app uses UUID as ids for active record entries in the database. If you want to know more about using uuid instead of integers read this article by pawelurbanek.com.

8. Automatic model annotation

Annotates Rails/ActiveRecord Models, routes, fixtures, and others based on the database schema. See annotate_models gem.

Run $ annotate in project root folder to update annotations.

9. Abilities with CanCanCan

CanCanCan is an authorization library for Ruby and Ruby on Rails which restricts what resources a given user is allowed to access. We combine this gem with a role field defined on user model.

Start defining your abilities under app/models/ability.rb�.

10. Rails Admin

To access the data of your application you can access the rails_admin dashboard under route http://0.0.0.0:3000/admin. Access is currently only allowed for users with super admin role.

If you want to give your admin interface a custom branding you can override sass variables or write your own css under app/assets/stylesheets/rails_admin/custom.

Change rails_admin settings under config/initializers/rails_admin.rb.

11. I18n

This app has the default language en and already set a secondary language de. We included the rails-i18n to support other languages out of the box. Add more languages under config/initializers/locale.rb.

Setting locale

To switch locale just append ?locale=de at the end of your url. If no locale param was set it uses browser default language (request env HTTP_ACCEPT_LANGUAGE). If this is unknown it takes the default language of the rails app.

Devise

For devise we use devise-i18n to support other languages.

Change translations under config/locales/devise.�If you want to support more languages install them with rails g devise:i18n:locale fr. (<-- installs French)

Rails Admin

To get translations for rails admin out of the box we use rails_admin-i18n.

Testing Locales

How to test your locale files and how to find missing one read this.

12. HTTP Authentication

For your staging environment we recommend to use a HTTP Auth protection. To enable it set env var IS_HTTP_AUTH_PROTECTED to true.

Set user with HTTP_AUTH_USER and password with HTTP_AUTH_PASSWORD.

We enable HTTP auth currently for all controllers. The ApplicationController class includes the concern HttpAuth. Feel free to change it.

13. Auto generated slugs

To provider more user friendly urls for your frontend we are using friendly_id to auto generate slugs for models. We have already implemented it for the Company model. For more configuration see config/initializers/friendly_id.rb.

To create a new slug field for a model add a field slug:

$ rails g migration add_slug_to_resource slug:uniq
$ bundle exec rake db:migrate

Edit your model file as the following:

class Company < ApplicationRecord
  extend FriendlyId
  friendly_id :name, use: :slugged
end

Replace traditional Company.find(params[:id]) with Company.friendly.find(params[:id])��

  company = Company.friendly.find(params[:id])

14. Testing

We are using the wonderful framework rspec. The test suit also uses factory_bot_rails for fixtures.

Run rspec spec

FactoryBot

To create mock data in your tests we are using factory_bot. The gem is fixtures replacement with a straightforward definition syntax, support for multiple build strategies (saved instances, unsaved instances, attribute hashes, and stubbed objects), and support for multiple factories for the same class (user, admin_user, and so on), including factory inheritance.

Faker

Create fake data easily with faker gem. Caution: The created data is not uniq by default.

Shoulda Matchers

Shoulda Matchers provides RSpec- and Minitest-compatible one-liners to test common Rails functionality that, if written by hand, would be much longer, more complex, and error-prone.

Simplecov

SimpleCov is a code coverage analysis tool for Ruby. It uses Ruby's built-in Coverage library to gather code coverage data, but makes processing its results much easier by providing a clean API to filter, group, merge, format, and display those results, giving you a complete code coverage suite that can be set up with just a couple lines of code.

Open test coverage results with

  $ open /coverage/index.html

15. Linter with Rubocop

We are using the wonderful rubocop to lint and auto fix the code. Install the rubocop VSCode extension to get best experience during development.

16. Security with Rack Attack

See config/initializers/rack_attack.rb file. We have defined a common set of rules to block users trying to access the application multiple times with wrong credentials, or trying to create a hundreds requests per minute.

To speed up tests add this to your .env.test

ATTACK_REQUEST_LIMIT=30
ATTACK_AUTHENTICATED_REQUEST_LIMIT=30

17. Sending emails

Set your SMTP settings with these environment variables:

  • SMTP_ADDRESS
  • SMTP_PORT
  • SMTP_DOMAIN
  • SMTP_USERNAME
  • SMTP_PASSWORD
  • SMTP_AUTH
  • SMTP_ENABLE_STARTTLS_AUTO

Have a look at config/environments/production.rb where we set the config.action_mailer.smtp_settings.

from: email

Set the email address for your ApplicationMailer and devise emails with env var DEVISE_MAILER_FROM.

18. Deployment

The project runs on every server with ruby installed. The only dependency is a PostgreSQL database. Create a block production: in theconfig/database.yml for your connection.

Bitbucket Pipelines

If you want to use Bitbucket pipelines for CI you can use the sample file bitbucket-pipelines.yml in the project root.

Make sure to set ENV vars $HEROKU_API_KEY and $HEROKU_APP_NAME in Bitbuckets pipeline settings. (Will appear after enabling pipelines for your project.)

The pipeline has 2 environments: staging and production. Staging pipeline is getting triggered in develop branch. Production deploy triggered by master branch.

It also triggers pipeline while opening a PR.

What's missing?

  • Check & retest locked accounts
  • Invite for users, inviteMutation & acceptInviteMutation
  • Registration add more fields (Firstname, Last name)
  • Tests for filter, sorting & pagination
  • Security: brakeman and bundler-audit

Author

Script: https://github.com/zauberware/rails-devise-graphql

Author website: https://www.zauberware.com

zauberware technologies

About

Init from zauberware/rails-devise-graphql and update somethings that belongs to my organization needed.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published