Repository: gobuffalo/buffalo
Pull request #1728 (2019-07-10 13:40:56)

Use model#isPlural to pick which template to auto-render
I ran into an issue attempting to use hyphens instead of underscores in resource URLS (Google recommends underscores not be used: https://support.google.com/webmasters/answer/76329?hl=en).

I traced the limitation down to the autorender, which makes assumptions about the url path segment matching the underscore form. Instead, it is possible to know whether to render the index.html or show.html based on whether we have a collection or a single instance of the model. 

markbates: Can you please add some tests? Thanks. 

Also, Go convention is underscores for file names, which is why Buffalo uses underscores. 
bytheway: Happy to add tests, will do that this evening.

I understand the underscore convention for identifiers and file names (this PR doesn't change that), but that convention gets messy when it runs into the more visible url conventions which have their own style guides, especially when it comes to search engines, etc.  

Patch:
diff --git a/render/auto.go b/render/auto.go
index 469df592..be0f448d 100644
--- a/render/auto.go
+++ b/render/auto.go
@@ -6,7 +6,6 @@ import (
 	"io"
 	"path"
 	"reflect"
-	"regexp"
 	"strings"
 
 	"github.com/gobuffalo/flect/name"
@@ -93,8 +92,9 @@ func (htmlAutoRenderer) ContentType() string {
 func (ir htmlAutoRenderer) Render(w io.Writer, data Data) error {
 	n := name.New(ir.typeName())
 	pname := name.New(n.Pluralize().String())
+	isPlural := ir.isPlural()
 
-	if ir.isPlural() {
+	if isPlural {
 		data[pname.VarCasePlural().String()] = ir.model
 	} else {
 		data[n.VarCaseSingle().String()] = ir.model
@@ -134,11 +134,7 @@ func (ir htmlAutoRenderer) Render(w io.Writer, data Data) error {
 		return ir.HTML(fmt.Sprintf("%s/new.html", templatePrefix)).Render(w, data)
 	}
 
-	x, err := regexp.Compile(fmt.Sprintf("%s/.+", pname.URL()))
-	if err != nil {
-		return err
-	}
-	if x.MatchString(cp) {
+	if !isPlural {
 		return ir.HTML(fmt.Sprintf("%s/show.html", templatePrefix)).Render(w, data)
 	}
 	return defCase()


Test patch:
diff --git a/render/auto_test.go b/render/auto_test.go
index 71e73873..f7b38caf 100644
--- a/render/auto_test.go
+++ b/render/auto_test.go
@@ -138,6 +138,32 @@ func Test_Auto_HTML_List_Plural_MultiWord(t *testing.T) {
 	r.NoError(err)
 }
 
+func Test_Auto_HTML_List_Plural_MultiWord_Dashed(t *testing.T) {
+	r := require.New(t)
+
+	type RoomProvider struct {
+		Name string
+	}
+
+	type RoomProviders []RoomProvider
+
+	err := withHTMLFile("room_providers/index.html", "INDEX: <%= len(roomProviders) %>", func(e *render.Engine) {
+		app := buffalo.New(buffalo.Options{})
+		app.GET("/room-providers", func(c buffalo.Context) error {
+			return c.Render(200, e.Auto(c, RoomProviders{
+				RoomProvider{Name: "Ford"},
+				RoomProvider{Name: "Chevy"},
+			}))
+		})
+
+		w := httptest.New(app)
+		res := w.HTML("/room-providers").Get()
+
+		r.Contains(res.Body.String(), "INDEX: 2")
+	})
+	r.NoError(err)
+}
+
 func Test_Auto_HTML_Show(t *testing.T) {
 	r := require.New(t)
 
@@ -154,6 +180,28 @@ func Test_Auto_HTML_Show(t *testing.T) {
 	r.NoError(err)
 }
 
+func Test_Auto_HTML_Show_MultiWord_Dashed(t *testing.T) {
+	r := require.New(t)
+
+	type RoomProvider struct {
+		ID   int
+		Name string
+	}
+
+	err := withHTMLFile("room_providers/show.html", "SHOW: <%= roomProvider.Name %>", func(e *render.Engine) {
+		app := buffalo.New(buffalo.Options{})
+		app.GET("/room-providers/{id}", func(c buffalo.Context) error {
+			return c.Render(200, e.Auto(c, RoomProvider{ID: 1, Name: "Ford"}))
+		})
+
+		w := httptest.New(app)
+		res := w.HTML("/room-providers/1").Get()
+
+		r.Contains(res.Body.String(), "SHOW: Ford")
+	})
+	r.NoError(err)
+}
+
 func Test_Auto_HTML_New(t *testing.T) {
 	r := require.New(t)