Creating Custom Ruby on Rails Generators

Episode #89 by Teacher's Avatar David Kimura

Summary

Simplify your workflow by using custom generators to streamline the creation of files and templates that you use often.
rails template 11:02

Resources

Summary

# lib/generators/datatables/USAGE
Description:
    Creates the datatables structure for you.

Example:
    rails generate datatables init

    This will create:
        app/services/datatables
        app/services/datatables/application_datatable.rb

    rails generate datatables users

    This will create:
        app/services/datatables
        app/services/datatables/application_datatable.rb
        app/services/datatables/users_datatable.rb

# lib/generators/datatables/datatables_generators.rb
class DatatablesGenerator < Rails::Generators::Base
  source_root File.expand_path('../templates', __FILE__)
  argument :model, type: :string
  class_option :doc, type: :boolean, default: true, desc: "Include documentation."

  def generate_init
    generate_application_datatable
  end

  def generate_model
    generate_model_datatable unless model == 'init'
  end

  private

  def generate_application_datatable
    copy_file 'datatable_template.template', 'app/services/datatables/application_datatable.rb'
  end

  def generate_model_datatable
    template 'model_datatable_template.template', "app/services/datatables/#{model.underscore}_datatable.rb"
  end
end

# lib/generators/datatables/templates/datatable_template.template
class ApplicationDatatable
  # delegate :params, to: :@view
  # delegate :link_to, to: :@view

  def initialize(view)
    @view = view
  end

  def as_json(options = {})
    {
      recordsTotal: count,
      recordsFiltered: total_entries,
      data: data
    }
  end

private

  def page
    params[:start].to_i/per_page + 1
  end

  def per_page
    length > 0 ? length : 10
  end

  def sort_column
    columns[params[:order]['0'][:column].to_i]
  end

  def sort_direction
    params[:order]['0'][:dir] == "desc" ? "desc" : "asc"
  end

  def length
    params[:length].to_i
  end
end

# lib/generators/datatables/templates/model_datatable_template.template
class <%= model.camelcase %>Datatable < ApplicationDatatable
  delegate :edit_<%= model.singularize.downcase %>_path, to: :@view

  private

  <%- if options.doc? -%>
  # Loop through memoized collection and build the columns.
  # If extracting from a view, be sure to add delegates
  # and to also clean up and inject each column into the column var.
  # Also, if you have multiple items (links) in a single column, you
  # will need to create a separate variable and join them accordingly
  # when pushing to the column array
  <%- end -%>
  def data
    <%= model.downcase.pluralize %>.map do |<%= model.downcase.singularize.underscore %>|
      [].tap do |column|
        column << nil # something
      end
    end
  end

  <%- if options.doc? -%>
  # Returns the count of records.
  <%- end -%>
  def count
    <%= model.singularize.camelcase %>.count
  end

  def total_entries
    <%= model.downcase.underscore %>.total_count
    # will_paginate
    # <%= model.downcase.underscore %>.total_entries
  end

  def <%= model.downcase.underscore %>
    @<%= model.downcase.underscore %> ||= fetch_<%= model.downcase.underscore %>
  end

  def fetch_<%= model.downcase.underscore %>
    search_string = []
    columns.each do |term|
      search_string << "#{term} like :search"
    end

    # will_paginate
    # <%= model.downcase.underscore %> = <%= model.singularize.camelcase %>.page(page).per_page(per_page)
    <%= model.downcase.underscore %> = <%= model.singularize.camelcase %>.order("#{sort_column} #{sort_direction}")
    <%= model.downcase.underscore %> = <%= model.downcase.underscore %>.page(page).per(per_page)
    <%= model.downcase.underscore %> = <%= model.downcase.underscore %>.where(search_string.join(' or '), search: "%#{params[:search][:value]}%")
  end

  <%- if options.doc? -%>
  # The columns needs to be the same list of searchable items and IN ORDER that they will appear in Data.
  <%- end -%>
  def columns
    %w()
  end
end