Skip to content

everson-ever/restme

Repository files navigation

Restme

Gem Version

Adds support for new Rails/Postgres controller actions such as pagination, filtering, sorting, and selecting specific model fields. Easily implement full CRUD functionality by importing Restme into your controller.

This gem manages your controller's responsibilities for:

  • Read Actions: Provide complete pagination, filtering, sorting, and field selection for records, all handled through query parameters (e.g., http://127.0.0.1/products?name_equal=foo).
  • Create/Update Actions: Enabling automatic creation and updating of records.

ℹ️ This doc reference latest version of Restme

Installation

GEMFILE:

gem 'restme', '~> 1.3.2'

INSTALL:

gem 'restme'

Usage

ℹ️ Current Version of gem require the following pré configs

  • Your controllers must be named using the plural form of the model (e.g., Product → ProductsController). Alternatively, you can manually set the model name by defining the MODEL_NAME constant (e.g., MODEL_NAME = "Product").
  • You must create a folder inside app named restme to define controller rules for authorization, scoping, creation, updating, and field selection (see example below).

Optional Configuration (Available from version 1.1 or higher)

You can create a restme.rb file inside config/initializers to customize Restme's behavior:

  • Define the name of the controller variable that holds the current user (default: current_user).
  • Define the name of the user field that identifies the user's role (default: role).
  • Set the default number of items returned per page (default: 12).
  • Set the default starting page (default: 1).
  • Define the maximum number of items allowed per page (default: 100).

Example:

# config/initializers/restme.rb

Restme.configure do |config|
  config.current_user_variable = :current_user
  config.user_role_field = :role
  config.pagination_default_per_page = 12
  config.pagination_default_page = 1
  config.pagination_max_per_page = 100
end

current_user_variable

Defines the name of the method used to access the currently authenticated user within the controller context. This should match the method that returns the logged-in user (for example, :current_user when using authentication libraries like Devise). Represent the the field where the role of user is (can be one or many rules)

user_role_field

Defines the attribute on the user model that represents the user's role. This field is used to determine authorization rules and may support single or multiple roles, depending on your application's implementation.

pagination_default_per_page

Specifies the default number of records returned per page when pagination parameters are not explicitly provided in the request.

pagination_default_page

Specifies the default page number used when the request does not include a page parameter.

pagination_max_per_page

Defines the maximum number of records allowed per page. This acts as a safety limit to prevent clients from requesting excessively large result sets, helping protect application performance and resource usage.


Usage examples

Rails API project example here: everson-ever/restme-example#1

First of all

Include the Restme module in your controller (or, optionally, in your ApplicationController if you want it available globally):

include Restme::Restme

before_action :initialize_restme  # This will authorize or deny the current action based on `ProductsController::Authorize::Rules` (see example below)


ProductsController example with restme

module Api::V1::Products
  class ProductsController < ApplicationController
    include Restme::Restme

    before_action :initialize_restme

    def index
      render json: pagination_response, status: restme_scope_status
    end

    def show
      render json: model_scope_object, status: restme_scope_status
    end

    def create
      render json: creatable_record, status: restme_create_status
    end

    def update
      render json: updateable_record, status: restme_update_status
    end
  end
end
  • restme_scope_status, restme_create_status, and restme_update_status are dynamic status codes generated by Restme.
  • model_scope_object returns a single record or nil base on scope users.
  • pagination_response returns the dynamic collection response generated by Restme.


Each Restme controller works together with its corresponding rules defined inside app/restfy. Restme dynamically loads the rules for each controller.

For example, ProductsController has the following rules:

app/restfy/products_controller/authorize/rules.rb

  • Used to verify if a user is authorized to access the current action based on their role.
module ProductsController::Authorize
  class Rules
    ALLOWED_ROLES_ACTIONS = {
      create: %i[manager],
      index: %i[client manager],
      show: %i[client manager],
      update: %i[manager]
    }.freeze
  end
end

app/restfy/products_controller/create/rules.rb

  • Used to check if the current create action is within the user's scope. The example below checks if a manager is authorized to create a product for a specific establishment_id.
  • CREATABLE_ACTIONS_RULES defines which controller actions are considered POST actions.
module ProductsController::Create
  class Rules
    CREATABLE_ACTIONS_RULES = %i[create].freeze

    # The initialization of the create rules must receive the following three parameters: current_record (the record in memory), current_user, and the controller's params.
    def initialize(temp_record, current_user, controller_params = {})
      @temp_record = temp_record
      @current_user = current_user
      @controller_params = controller_params
    end

    def create_manager_scope?
      @current_user.manager.establishments.exists?(id: @temp_record.establishment_id)
    end
  end
end

app/restfy/products_controller/update/rules.rb

  • Used to check if the current update action is within the user's scope. The example below checks if a manager is authorized to update a product for a specific establishment_id.
  • UPDATABLE_ACTIONS_RULES defines which controller actions are considered PUT actions.
module ProductsController::Update
  class Rules
    UPDATABLE_ACTIONS_RULES = %i[update].freeze

    # The initialization of the create rules must receive the following three parameters: current_record (the record in memory), current_user, and the controller's params.
    def initialize(temp_record, current_user, controller_params = {})
      @temp_record = temp_record
      @current_user = current_user
      @controller_params = controller_params
    end

    def update_manager_scope?
      @current_user.manager.establishments.select(:id).ids.include?(@temp_record.establishment_id)
    end
  end
end

app/restfy/products_controller/scope/rules.rb

This rule defines which records are part of the current user's scope (i.e., visible to them).

module ProductsController::Scope
  class Rules

    # The initialization of the scope rules must receive the following three parameters: current_record (the record in memory), current_user, and the controller's params.
    def initialize(klass, current_user, controller_params = {})
      @klass = klass
      @current_user = current_user
      @controller_params = controller_params
    end

    def client_scope
      @klass.all
    end

    def deliveryman_scope
      @klass.all
    end

    def manager_scope
      @klass.where(establishment_id: @current_user.manager.establishments.ids)
    end
  end
end

app/restfy/products_controller/field/rules.rb

This rule defines which nested_fields are selectable (nested fields are model relationships).

module ProductsController::Field
  class Rules
   # Defines the default fields that will be automatically selected
   # in queries when no explicit field selection is provided.
   # These fields are always included in the response.
   MODEL_FIELDS_SELECT = %i[id].freeze

   UNALLOWED_MODEL_FIELDS_SELECT = %i[internal_code].freeze

    NESTED_SELECTABLE_FIELDS = {
      unit: {},
      establishment: {},
      category: {},
      producer: {}
    }.freeze
  end
end

And now how to use that?



Filtering

To enable data filtering, specify the filterable fields in your model using the FILTERABLE_FIELDS constant (e.g., FILTERABLE_FIELDS = %[name]).

You can filter data using the following query parameters:

  • in: Filters by matching any of the specified values.

    • Example: id_in=1,2,3
  • equal: Filters by exact match.

    • Example: name_equal=foo
  • like: Filters by partial match (using LIKE SQL operator).

    • Example: name_like=foo
  • bigger_than: Filters by records where the field is greater than the specified value.

    • Example: created_at_bigger_than=2025-01-01
  • less_than: Filters by records where the field is less than the specified value.

    • Example: created_at_less_than=2025-01-01
  • bigger_than_or_equal_to: Filters by records where the field is greater than or equal to the specified value.

    • Example: created_at_bigger_than_or_equal_to=2025-01-01
  • less_than_or_equal_to: Filters by records where the field is less than or equal to the specified value.

    • Example: created_at_less_than_or_equal_to=2025-01-01

Example request:

http://127.0.0.1/api/v1/products?name_equal=foo,establishment_id_in=1,2,3



Sorting

To enable data sorting, specify the sortable fields in your model using the SORTABLE_FIELDS constant (e.g., SORTABLE_FIELDS = %[id]).

You can sort records using the following query parameters:

Examples

  • Descending (DESC): Sort records in descending order.

     http://localhost:3000/api/v1/products?id_sort=desc
  • Ascending (ASC): Sort records in ascending order.

     http://localhost:3000/api/v1/products?id_sort=asc



Pagination

Pagination functionality is available for any index endpoint that uses the pagination_response variable in the controller.

There are two query parameters available to control pagination:

  • per_page: Defines the number of items per page.
  • page: Sets the current page number.

Example usage:

http://localhost:3000/api/v1/products?per_page=12&page=1



Field Selection (fields_select)

You can select specific fields from your model, such as id, name, or created_at. The generated query will retrieve only the selected fields directly from the database, reducing unnecessary data loading and improving performance.

Example:

http://localhost:3000/api/v1/products?fields_select=id,name



Nested Field Selection (nested_fields_select)

You can also select specific relationships of your records, such as product.client or product.establishment.
The resulting query will automatically include the related data, optimizing the response for your needs.

ℹ️ Note:
If you select a nested field, you must also ensure that the related foreign key (e.g., establishment_id, client_id) is included via fields_select.
If the fields_select parameter is not provided, Restme will automatically handle the necessary field selections.

Example:

http://localhost:3000/api/v1/products?nested_fields_select=client
{
  "products": [
    {
      "id": 1,
      "name": "foo",
      "client": {
        "id": 5,
        "name": "bar"
      }
    }
  ]
}



Attachment Field Selection (attachment_fields_select)

If your model uses Active Storage and has attachments, you can retrieve the URL of an attached file by using the attachment_fields_select parameter.
When specified, Restme will include the URL of the attachment in the response.

ℹ️ Note:
If the specified attachment field does not exist in the model, Restme will return an HTTP 422 Unprocessable Entity error.

Example:

http://localhost:3000/api/v1/products?attachment_fields_select=image

{
  "products": [
    {
      "id": 1,
      "image_url": "http://localhost/image.png", // The field includes the `_url` suffix
    }
  ]
}



License

The gem is available as open source under the terms of the MIT License.

Code of Conduct

Everyone interacting in the Restme project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.

About

Adds support for new Rails controller actions such as pagination, filtering, sorting, and selecting specific model fields. Easily implement full CRUD functionality by importing Restme into your controller.

Resources

License

Code of conduct

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages