Skip to content

anonychun/paradis

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

49 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Paradis logo

PARADIS

This project is a Rails application template designed to streamline the setup of new Rails projects. It includes predefined configurations, routes, and utility modules to help you get started quickly.

I created this template after being inspired by ecosystems outside of Rails. Observing how other frameworks and languages structure their projects and provide out-of-the-box solutions for common tasks motivated me to bring similar conveniences to the Rails community.

Installation

Create a new Rails application using the template by running the following command in your terminal:

rails new app \
  --javascript esbuild \
  --css tailwind \
  --skip-rubocop \
  -m https://raw.githubusercontent.com/anonychun/paradis/main/template.rb

This command will create a new Rails application named app and apply the Paradis template to it. The --skip-rubocop option is used to skip the default RuboCop configuration, as Paradis uses standard for linting and formatting.

Basic Usage

Paradis is just combination of built-in Rails features and some additional gems. Here are some of the features that you can use:

Blueprint Layer

Blueprint objects are used to represent your models in a way that can be easily serialized into JSON. You can define an blueprint object by inheriting from ApplicationBlueprint powered by blueprinter gem and expose the attributes you want to include in the JSON response.

Be aware that you can also expose associations and nested entities, avoid exposing sensitive and unnecessary attributes.

class ArticleBlueprint < ApplicationBlueprint
  field :title
  field :content
  association :author, blueprint: AuthorBlueprint
end

If you're using Active Storage, you can expose the attachment URLs by using the other defined blueprint that only exposes the URL.

class Article < ApplicationRecord
  has_one_attached :thumbnail_file
  has_many_attached :content_files
end

class BlobBlueprint < ApplicationBlueprint
  field :url
end

class ArticleBlueprint < ApplicationBlueprint
  field :title
  field :content
  field :thumbnail_file, blueprint: BlobBlueprint
  field :content_files, blueprint: BlobBlueprint
end

Standardize API Response

Use present method in controller or view to standardize the API response. The present method will automatically wrap the response in a JSON object with the following structure:

if the status code is indicating an error the errors field will be containing the error messages otherwise null.

{
  "ok": true,
  "meta": null,
  "data": {
    "article": {
      "id": "0196a944-0603-7464-8363-99b2d0ef18f4",
      "title": "Hello world",
      "content": "This is the content of the article"
    }
  },
  "errors": null
}

Example of using present in a controller or view:

# app/controllers/api/v1/hello_controller.rb
class Api::V1::HelloController < Api::V1Controller
  def greeting
    @to = "world"
  end
end

# app/views/api/v1/hello/greeting.json.jbuilder
present json do
  json.hello @to
end

Or return a JSON response directly in the controller.

class Api::V1::HelloController < Api::V1Controller
  def greeting
    present json: {
      hello: "world"
    }
  end
end

Both methods will return the same JSON response.

{
  "ok": true,
  "meta": null,
  "data": {
    "hello": "world"
  },
  "errors": null
}

You can also use present_meta in controller to include meta information in the response.

class Api::V1::HelloController < Api::V1Controller
  def greeting
    present_meta :weather, "sunny"

    present json: {
      hello: "world"
    }
  end
end
{
  "ok": true,
  "meta": {
    "weather": "sunny"
  },
  "data": {
    "hello": "world"
  },
  "errors": null
}

Error Handling

Send error response using the error! method if you're on a controller and raise ApiError if you're outside of the controller.

If you're sending a string as error it will automatically be converted to an object with the key message.

class Api::V1::ArticleController < Api::V1Controller
  def restricted
    error!("You are not authorized to access this resource", status: :unauthorized)
  end
end
def get_article(id)
  article = Article.find_by(id: id)
  raise ApiError.new("Article not found", :not_found) unless article.present?

  article
end

When you want to send a manual parameter validation error, you can use the param_error! method.

param_error!(:email, "must be filled", "must be a valid email")

Parameters Validation

You can validate parameters using the params.validate! method. This method uses the dry-schema gem to validate parameters based on the rules you define.

class Api::V1::ArticleController < Api::V1Controller
  def create
    params.validate! do
      required(:title).filled(:string)
      required(:content).filled(:string)
    end

    @article = Article.create!(title: params[:title], content: params[:content])
  end
end

When validation fails, the response will properly map the error messages with the corresponding fields.

{
  "ok": false,
  "meta": null,
  "data": null,
  "errors": {
    "params": {
      "email": ["must be filled"],
      "password": ["must be filled"]
    }
  }
}

Pagination

Use the paginate method to paginate the records. The paginate method automatically validate and uses the page, per_page, start_date and end_date parameters from the request to paginate the records.

class Api::V1::ArticleController < Api::V1Controller
  def index
    articles = paginate Article.order(id: :desc)
    present json: ArticleBlueprint.represent(articles)
  end
end

The result will send the paginated information in the meta section of the response.

{
  "ok": true,
  "meta": {
    "pagination": {
      "page": 1,
      "per_page": 10,
      "total": 50
    }
  },
  "data": [],
  "errors": null
}

About

Saying Yes When Rails Says No

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages