Generators

Built-in Generators

A collection of generators to make life easier

Usage:
  buffalo generate [command]

Aliases:
  generate, g

Available Commands:
  action      Generates new action(s)
  docker      Generates a Dockerfile
  goth        Generates a actions/goth.go file configured to the specified providers.
  resource    Generates a new actions/resource file
  task        Generates a grift task
  webpack     Generates a webpack asset pipeline.

Flags:
  -h, --help   help for generate

Use "buffalo generate [command] --help" for more information about a command.

See also /docs/db#generators for a list of database related generators.

Generating Actions

$ buffalo g action --help

Generates new action(s)

Usage:
  buffalo generate action [name] [actionName...] [flags]

Aliases:
  action, a, actions
$ buffalo g a users show index create

--> templates/users/show.html
--> templates/users/index.html
--> templates/users/create.html
--> actions/users.go
--> actions/users_test.go
--> goimports -w .

In some cases you will need to generate an action with an HTTP method different than GET, for that case you can use the --method flag, like in the following example:

$ buffalo g actions users message --method POST

In some other scenarios you will need to generate an action without generating an HTML template. To skip the generation of the HTML template for creating an action you can pass the --skip-template flag to the generator, i.e:

$ buffalo g actions users update --skip-template

Destroying Actions

You can remove files generated by this generator by running:

$ buffalo destroy action users

Or in short form:

$ buffalo d a users

Resources

$ buffalo g resource --help

Generates a new actions/resource file
Usage:
  buffalo generate resource [name] [flags]

Aliases:
  resource, r
$ buffalo g resource users name email bio:nulls.Text

--> actions/users.go
--> actions/users_test.go
--> locales/users.en-us.yaml
--> templates/users/_form.html
--> templates/users/edit.html
--> templates/users/index.html
--> templates/users/new.html
--> templates/users/show.html
--> buffalo db g model user name email bio:nulls.Text
--> models/user.go
--> models/user_test.go
--> goimports -w .
> migrations/20170410180211_create_users.up.fizz
> migrations/20170410180211_create_users.down.fizz
--> goimports -w .
// actions/app.go
package actions

import (
  "github.com/gobuffalo/buffalo"
  "github.com/gobuffalo/buffalo/middleware"
  "github.com/gobuffalo/buffalo/middleware/csrf"
  "github.com/gobuffalo/buffalo/middleware/i18n"

  "github.com/markbates/coke/models"

  "github.com/gobuffalo/envy"
  "github.com/gobuffalo/packr"
)

// ENV is used to help switch settings based on where the
// application is being run. Default is "development".
var ENV = envy.Get("GO_ENV", "development")
var app *buffalo.App
var T *i18n.Translator

// App is where all routes and middleware for buffalo
// should be defined. This is the nerve center of your
// application.
func App() *buffalo.App {
  if app == nil {
    app = buffalo.Automatic(buffalo.Options{
      Env:         ENV,
      SessionName: "_coke_session",
    })

    if ENV == "development" {
      app.Use(middleware.ParameterLogger)
    }
    if ENV != "test" {
      // Protect against CSRF attacks. https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)
      // Remove to disable this.
      app.Use(csrf.Middleware)
    }

    // Wraps each request in a transaction.
    //  c.Value("tx").(*pop.PopTransaction)
    // Remove to disable this.
    app.Use(middleware.PopTransaction(models.DB))

    // Setup and use translations:
    var err error
    if T, err = i18n.New(packr.NewBox("../locales"), "en-US"); err != nil {
      app.Stop(err)
    }
    app.Use(T.Middleware())

    app.GET("/", HomeHandler)

    app.ServeFiles("/assets", packr.NewBox("../public/assets"))
    app.Resource("/users", UsersResource{&buffalo.BaseResource{}})
  }

  return app
}
// actions/users.go
package actions

import (
  "github.com/gobuffalo/buffalo"
  "github.com/markbates/coke/models"
  "github.com/markbates/pop"
  "github.com/pkg/errors"
)

// This file is generated by Buffalo. It offers a basic structure for
// adding, editing and deleting a page. If your model is more
// complex or you need more than the basic implementation you need to
// edit this file.

// Following naming logic is implemented in Buffalo:
// Model: Singular (User)
// DB Table: Plural (Users)
// Resource: Plural (Users)
// Path: Plural (/users)
// View Template Folder: Plural (/templates/users/)

// UsersResource is the resource for the user model
type UsersResource struct {
  buffalo.Resource
}

// List gets all Users. This function is mapped to the path
// GET /users
func (v UsersResource) List(c buffalo.Context) error {
  // Get the DB connection from the context
  tx := c.Value("tx").(*pop.Connection)
  users := &models.Users{}
  // You can order your list here. Just change
  err := tx.All(users)
  // to:
  // err := tx.Order("create_at desc").All(users)
  if err != nil {
    return errors.WithStack(err)
  }
  // Make users available inside the html template
  c.Set("users", users)
  return c.Render(200, r.HTML("users/index.html"))
}

// Show gets the data for one User. This function is mapped to
// the path GET /users/{user_id}
func (v UsersResource) Show(c buffalo.Context) error {
  // Get the DB connection from the context
  tx := c.Value("tx").(*pop.Connection)
  // Allocate an empty User
  user := &models.User{}
  // To find the User the parameter user_id is used.
  err := tx.Find(user, c.Param("user_id"))
  if err != nil {
    return errors.WithStack(err)
  }
  // Make user available inside the html template
  c.Set("user", user)
  return c.Render(200, r.HTML("users/show.html"))
}

// New renders the form for creating a new user.
// This function is mapped to the path GET /users/new
func (v UsersResource) New(c buffalo.Context) error {
  // Make user available inside the html template
  c.Set("user", &models.User{})
  return c.Render(200, r.HTML("users/new.html"))
}

// Create adds a user to the DB. This function is mapped to the
// path POST /users
func (v UsersResource) Create(c buffalo.Context) error {
  // Allocate an empty User
  user := &models.User{}
  // Bind user to the html form elements
  err := c.Bind(user)
  if err != nil {
    return errors.WithStack(err)
  }
  // Get the DB connection from the context
  tx := c.Value("tx").(*pop.Connection)
  // Validate the data from the html form
  verrs, err := tx.ValidateAndCreate(user)
  if err != nil {
    return errors.WithStack(err)
  }
  if verrs.HasAny() {
    // Make user available inside the html template
    c.Set("user", user)
    // Make the errors available inside the html template
    c.Set("errors", verrs)
    // Render again the new.html template that the user can
    // correct the input.
    return c.Render(422, r.HTML("users/new.html"))
  }
  // If there are no errors set a success message
  c.Flash().Add("success", "User was created successfully")
  // and redirect to the users index page
  return c.Redirect(302, "/users/%s", user.ID)
}

// Edit renders a edit formular for a user. This function is
// mapped to the path GET /users/{user_id}/edit
func (v UsersResource) Edit(c buffalo.Context) error {
  // Get the DB connection from the context
  tx := c.Value("tx").(*pop.Connection)
  // Allocate an empty User
  user := &models.User{}
  err := tx.Find(user, c.Param("user_id"))
  if err != nil {
    return errors.WithStack(err)
  }
  // Make user available inside the html template
  c.Set("user", user)
  return c.Render(200, r.HTML("users/edit.html"))
}

// Update changes a user in the DB. This function is mapped to
// the path PUT /users/{user_id}
func (v UsersResource) Update(c buffalo.Context) error {
  // Get the DB connection from the context
  tx := c.Value("tx").(*pop.Connection)
  // Allocate an empty User
  user := &models.User{}
  err := tx.Find(user, c.Param("user_id"))
  if err != nil {
    return errors.WithStack(err)
  }
  // Bind user to the html form elements
  err = c.Bind(user)
  if err != nil {
    return errors.WithStack(err)
  }
  verrs, err := tx.ValidateAndUpdate(user)
  if err != nil {
    return errors.WithStack(err)
  }
  if verrs.HasAny() {
    // Make user available inside the html template
    c.Set("user", user)
    // Make the errors available inside the html template
    c.Set("errors", verrs)
    // Render again the edit.html template that the user can
    // correct the input.
    return c.Render(422, r.HTML("users/edit.html"))
  }
  // If there are no errors set a success message
  c.Flash().Add("success", "User was updated successfully")
  // and redirect to the users index page
  return c.Redirect(302, "/users/%s", user.ID)
}

// Destroy deletes a user from the DB. This function is mapped
// to the path DELETE /users/{user_id}
func (v UsersResource) Destroy(c buffalo.Context) error {
  // Get the DB connection from the context
  tx := c.Value("tx").(*pop.Connection)
  // Allocate an empty User
  user := &models.User{}
  // To find the User the parameter user_id is used.
  err := tx.Find(user, c.Param("user_id"))
  if err != nil {
    return errors.WithStack(err)
  }
  err = tx.Destroy(user)
  if err != nil {
    return errors.WithStack(err)
  }
  // If there are no errors set a flash message
  c.Flash().Add("success", "User was destroyed successfully")
  // Redirect to the users index page
  return c.Redirect(302, "/users")
}
// models/users.go
package models

import (
  "encoding/json"
  "time"

  "github.com/markbates/pop"
  "github.com/markbates/pop/nulls"
  "github.com/markbates/validate"
  "github.com/markbates/validate/validators"
  "github.com/satori/go.uuid"
)

type User struct {
  ID        uuid.UUID    `json:"id" db:"id"`
  CreatedAt time.Time    `json:"created_at" db:"created_at"`
  UpdatedAt time.Time    `json:"updated_at" db:"updated_at"`
  Name      string       `json:"name" db:"name"`
  Email     string       `json:"email" db:"email"`
  Bio       nulls.String `json:"bio" db:"bio"`
}

// String is not required by pop and may be deleted
func (u User) String() string {
  ju, _ := json.Marshal(u)
  return string(ju)
}

// Users is not required by pop and may be deleted
type Users []User

// String is not required by pop and may be deleted
func (u Users) String() string {
  ju, _ := json.Marshal(u)
  return string(ju)
}

// Validate gets run everytime you call a "pop.Validate" method.
// This method is not required and may be deleted.
func (u *User) Validate(tx *pop.Connection) (*validate.Errors, error) {
  return validate.Validate(
    &validators.StringIsPresent{Field: u.Name, Name: "Name"},
    &validators.StringIsPresent{Field: u.Email, Name: "Email"},
  ), nil
}

// ValidateSave gets run everytime you call "pop.ValidateSave" method.
// This method is not required and may be deleted.
func (u *User) ValidateSave(tx *pop.Connection) (*validate.Errors, error) {
  return validate.NewErrors(), nil
}

// ValidateUpdate gets run everytime you call "pop.ValidateUpdate" method.
// This method is not required and may be deleted.
func (u *User) ValidateUpdate(tx *pop.Connection) (*validate.Errors, error) {
  return validate.NewErrors(), nil
}
// migration
create_table("users", func(t) {
  t.Column("id", "uuid", {"primary": true})
  t.Column("name", "string", {})
  t.Column("email", "string", {})
  t.Column("bio", "text", {"null": true})
})
// users/index.html
<h1>Users</h1>

<p>
  <a href="<%= newUserPath() %>" class="btn btn-primary">Create New User</a>
</p>

<table class="table table-striped">
  <thead>
  <th>Name</th>
  <th>Email</th>
  <th>&amp;nbsp;</th>
  </thead>
  <tbody>
    <%= for (user) in users { %>
      <tr>
        <td><%= user.Name %></td>
        <td><%= user.Email %></td>
        <td>
          <div class="pull-right">
            <a href="<%= userPath({ user_id: user.ID }) %>" class="btn btn-info">View</a>
            <a href="<%= editUserPath({ user_id: user.ID }) %>" class="btn btn-warning">Edit</a>
            <a href="<%= userPath({ user_id: user.ID }) %>" data-method="DELETE" data-confirm="Are you sure?" class="btn btn-danger">Destroy</a>
          </div>
        </td>
      </tr>
    <% } %>
  </tbody>
</table>
// users/show.html
<h1>Users#Show</h1>

<ul class="list-unstyled list-inline">
  <li><a href="<%= usersPath() %>" class="btn btn-info">Back to all Users</a></li>
  <li><a href="<%= editUserPath({ user_id: user.ID })%>" class="btn btn-warning">Edit</a></li>
  <li><a href="<%= userPath({ user_id: user.ID })%>" data-method="DELETE" data-confirm="Are you sure?" class="btn btn-danger">Destroy</a>
</ul>

<p>
  <strong>Name</strong>: <%= user.Name %>
</p>
<p>
  <strong>Email</strong>: <%= user.Email %>
</p>
<p>
  <strong>Bio</strong>: <%= user.Bio %>
</p>
// users/new.html
<h1>New User</h1>

<%= form_for(user, {action: usersPath(), method: "POST"}) { %>
  <%= partial("users/form.html") %>
  <a href="<%= usersPath() %>" class="btn btn-warning" data-confirm="Are you sure?">Cancel</a>
<% } %>
// users/_form.html
<%= f.InputTag("Name") %>
<%= f.InputTag("Email") %>
<%= f.TextArea("Bio", {rows: 10}) %>
<button class="btn btn-success" role="submit">Save</button>
// users/edit.html
<h1>Edit User</h1>

<%= form_for(user, {action: userPath({ user_id: user.ID }), method: "PUT"}) { %>
  <%= partial("users/form.html") %>
  <a href="\<%= userPath({ user_id: user.ID }) %>" class="btn btn-warning" data-confirm="Are you sure?">Cancel</a>
<% } %>

You can remove files generated by this generator by running:

$ buffalo destroy resource users

This command will ask you which files you want to remove, you can either answer each of the questions with y/n or you can pass the -y flag to the command like:

$ buffalo destroy resource users -y

Or in short form:

$ buffalo d r users -y

Tasks

Easily generate new https://github.com/markbates/grift tasks.

$ buffalo g task foo:bar

--> grifts/bar.go
// grifts/bar.go
package grifts

import (
  . "github.com/markbates/grift/grift"
)

var _ = Namespace("foo", func() {

  Desc("bar", "TODO")
  Add("bar", func(c *Context) error {
    return nil
  })

})

Goth

Goth provides a simple, clean, and idiomatic way to write authentication packages for Go web applications. In Buffalo version, v0.9.4, the Goth generator was moved into it's own plugin, https://github.com/gobuffalo/buffalo-goth

Installation

$ go get -u github.com/gobuffalo/buffalo-goth

Usage

$ buffalo g goth twitter facebook linkedin github

--> actions/auth.go
--> go get github.com/markbates/goth/...
--> goimports -w .
// actions/app.go
package actions

import (
  "github.com/gobuffalo/buffalo"
  "github.com/gobuffalo/buffalo/middleware"
  "github.com/gobuffalo/buffalo/middleware/csrf"
  "github.com/gobuffalo/buffalo/middleware/i18n"

  "github.com/markbates/coke/models"

  "github.com/gobuffalo/envy"
  "github.com/gobuffalo/packr"

  "github.com/markbates/goth/gothic"
)

// ENV is used to help switch settings based on where the
// application is being run. Default is "development".
var ENV = envy.Get("GO_ENV", "development")
var app *buffalo.App
var T *i18n.Translator

// App is where all routes and middleware for buffalo
// should be defined. This is the nerve center of your
// application.
func App() *buffalo.App {
  if app == nil {
    app = buffalo.Automatic(buffalo.Options{
      Env:         ENV,
      SessionName: "_coke_session",
    })

    if ENV == "development" {
      app.Use(middleware.ParameterLogger)
    }
    if ENV != "test" {
      // Protect against CSRF attacks. https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)
      // Remove to disable this.
      app.Use(csrf.Middleware)
    }

    // Wraps each request in a transaction.
    //  c.Value("tx").(*pop.PopTransaction)
    // Remove to disable this.
    app.Use(middleware.PopTransaction(models.DB))

    // Setup and use translations:
    var err error
    if T, err = i18n.New(packr.NewBox("../locales"), "en-US"); err != nil {
      app.Stop(err)
    }
    app.Use(T.Middleware())

    app.GET("/", HomeHandler)

    app.ServeFiles("/assets", packr.NewBox("../public/assets"))
    auth := app.Group("/auth")
    auth.GET("/{provider}", buffalo.WrapHandlerFunc(gothic.BeginAuthHandler))
    auth.GET("/{provider}/callback", AuthCallback)
  }

  return app
}
// actions/auth.go
package actions

import (
  "fmt"
  "os"

  "github.com/gobuffalo/buffalo"
  "github.com/markbates/goth"
  "github.com/markbates/goth/gothic"
  "github.com/markbates/goth/providers/facebook"
  "github.com/markbates/goth/providers/github"
  "github.com/markbates/goth/providers/linkedin"
  "github.com/markbates/goth/providers/twitter"
)

func init() {
  gothic.Store = App().SessionStore

  goth.UseProviders(
    twitter.New(os.Getenv("TWITTER_KEY"), os.Getenv("TWITTER_SECRET"), fmt.Sprintf("%s%s", App().Host, "/auth/twitter/callback")),
    facebook.New(os.Getenv("FACEBOOK_KEY"), os.Getenv("FACEBOOK_SECRET"), fmt.Sprintf("%s%s", App().Host, "/auth/facebook/callback")),
    linkedin.New(os.Getenv("LINKEDIN_KEY"), os.Getenv("LINKEDIN_SECRET"), fmt.Sprintf("%s%s", App().Host, "/auth/linkedin/callback")),
    github.New(os.Getenv("GITHUB_KEY"), os.Getenv("GITHUB_SECRET"), fmt.Sprintf("%s%s", App().Host, "/auth/github/callback")),
  )
}

func AuthCallback(c buffalo.Context) error {
  user, err := gothic.CompleteUserAuth(c.Response(), c.Request())
  if err != nil {
    return c.Error(401, err)
  }
  // Do something with the user, maybe register them/sign them in
  return c.Render(200, r.JSON(user))
}