toptal / example_granite_application

Example application for Granite framework

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Example Granite Application

This is an example application to cover the basics of using Granite in a Rails app. For detailed documentation, check out the official docs.

Setup

Clone the repository:

git clone https://github.com/toptal/example_granite_application.git

Install Ruby and bundler if you haven't already and then:

cd example_granite_application
bundle install

Running the server

bundle exec rails s

Running specs

bundle exec rspec

Understanding the application example

In apq folder you can find the business action usage of Granite. The application samples just contain one real model persisted in the database.

The model persisted is Book:

> Book # => Book(id: integer, title: string)

BooksController uses the action Ba::Book::Create combined with the current_user to insert the new book in the database.

And, with a logged user we create some books with a title.

In the controller, the action is instantiated with the current user as a performer and render feedback depending on action success.

app/controllers/book_controller.rb

class BooksController < ApplicationController
  rescue_from Granite::Action::NotAllowedError do |exception|
    redirect_to books_path, alert: 'You\'re not allowed to execute this action.'
  end

  # POST /books
  def create
    book_action = Ba::Book::Create.as(current_user).new(params.require(:book))
    if book_action.perform
      # render success
    else
      # render errors
    end
  end

  # ... 
end

The current action and controller are clean because the logic and important behavior from Ba::Book::BusinessAction is where the magic is:

class Ba::Book::BusinessAction < BaseAction
  allow_if { performer.is_a?(User) }

  represents :title, of: :subject

  validates :title, presence: true

  private

  def execute_perform!(*)
    subject.save!
  end
end

Let's break down each macro and comprehend how it's being used:

Policies

You can expect only to execute some action with a user. For testing purposes, it's only verifying if the performer is a user.

allow_if { performer.is_a?(User) }

Testing it on the console:

Ba::Book::Create.as('Fake User').new.allowed? # => false

With a real user:

Ba::Book::Create.as(User.first).new.allowed? # => true

Remember you need to have at least one user to make this example work.

Attributes

The book has a title:

represents :title, of: :subject

Instancing with the title attribute:

Ba::Book::Create.as(User.first).new(title: "My first book")
# => #<Ba::Book::Create title: "My first book">

Validations

You can also be validating your model:

validates :title, presence: true

And check if the action is valid or not:

Ba::Book::Create.as(User.first).new().valid? # => false
Ba::Book::Create.as(User.first).new(title: "My first book").valid? #  => true

And, with a logged user we create some books with a title.

In the controller, the action instantiates with the current user as the performer and render feedback depending on the action response.

Subject

The subject needs memoization because the record will be persistent in the action performed.

class Ba::Book::Create < BA::Book::BusinessAction
  def subject
    @subject ||= ::Book.new
  end
end

While we have a special macro for subject in the action Ba::Book::Update, just referring it's a book.

class Ba::Book::Update < BA::Book::BusinessAction
  subject :book
end

Performing the action

The method execute_perform contains the real logic performed:

def execute_perform!(*)
  subject.save!
end

Note that the title is not being assigned because it's using represents and active_data is doing the assignment behind the scenes.

The policies, preconditions, and validations can also block the perform call and from running the execute_perform method.

Rescue from Granite::Action::NotAllowedError

BooksController uses rescue_from to encapsulate exceptions in case the policies are not satisfied.

rescue_from Granite::Action::NotAllowedError do |exception|
  redirect_to books_path, alert: 'You\'re not allowed to execute this action.'
end

You can check more details about the entire application following the official documentation tutorial.

About

Example application for Granite framework


Languages

Language:Ruby 86.4%Language:HTML 9.8%Language:CSS 2.6%Language:JavaScript 1.3%