Generators

Built-in Generators

$ buffalo g --help

A collection of generators to make life easier

Usage:
  buffalo generate [command]

Aliases:
  generate, g


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

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

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

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 .

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 .

package actions

import (
  "log"

  "github.com/gobuffalo/buffalo"
  "github.com/gobuffalo/buffalo/middleware"
  "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

// 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)
    }
    // Protect against CSRF attacks. https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)
    // Remove to disable this.
    app.Use(middleware.CSRF)

    app.Use(middleware.PopTransaction(models.DB))

    // Setup and use translations:
    t, err := i18n.New(packr.NewBox("../locales"), "en-US")
    if err != nil {
      log.Fatal(err)
    }
    app.Use(t.Middleware())

    app.GET("/", HomeHandler)

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

  return app
}

package actions

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

// 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 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("(case when completed then 1 else 2 end) desc, lower([sort_parameter]) asc").All(users)
  // Don't forget to change [sort_parameter] to the parameter of
  // your model, which should be used for sorting.
  if err != nil {
    return 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 err
  }
  // Make user available inside the html template
  c.Set("user", user)
  return c.Render(200, r.HTML("users/show.html"))
}

// New renders the formular 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 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 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 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 err
  }
  // Bind user to the html form elements
  err = c.Bind(user)
  if err != nil {
    return err
  }
  verrs, err := tx.ValidateAndUpdate(user)
  if err != nil {
    return 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 err
  }
  err = tx.Destroy(user)
  if err != nil {
    return 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")
}

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
}

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})
})

<h1>Users</h1>

<p>
  <a href="/users/new" class="btn btn-primary" rel="nofollow">Create New User</a>
</p>

<table>
  <thead>
    <th>Name</th>
    <th>Email</th>
    <th> </th>
  </thead>
  <tbody>
    <%= for (user) in users { %>
      <tr>
        <td><%= user.Name %></td>
        <td><%= user.Email %></td>
        <td>
          <div class="pull-right">
            <a href="/users/<%= user.ID %>" class="btn btn-info">View</a>
            <a href="/users/<%= user.ID %>/edit" class="btn btn-warning">Edit</a>
            <a href="/users/<%= user.ID %>" data-method="DELETE" data-confirm="Are you sure?" class="btn btn-danger">Destroy</a>
          </div>
        </td>
      </tr>
    <% } %>
  </tbody>
</table>

<h1>Users#Show</h1>

<ul>
  <li><a href="/users" class="btn btn-info">Back to all Users</a></li>
  <li><a href="/users//edit" class="btn btn-warning">Edit</a></li>
  <li><a href="/users/" 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>

<h1>New User</h1>

<%= form_for(user, {action: "/users", method: "POST", errors: errors}) { %>
  <%= partial("users/form.html") %>
  <a href="/users" class="btn btn-warning" rel="nofollow">Cancel</a>
<% } %>

<%= f.InputTag("Name") %>
<%= f.InputTag("Email") %>
<%= f.TextArea("Bio", {rows: 10}) %>
<button class="btn btn-success" role="submit">Save</button>

<h1>Edit User</h1>

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

Goth

Goth provides a simple, clean, and idiomatic way to write authentication packages for Go web applications.


$ buffalo g goth twitter facebook linkedin github

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

package actions

import (
    "github.com/gobuffalo/buffalo"

    "github.com/gobuffalo/buffalo/middleware"
    "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

// 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",
        })

        app.Use(middleware.PopTransaction(models.DB))

        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
}

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))
}