Skip to content
This repository has been archived by the owner on Feb 24, 2024. It is now read-only.

Implementing the flash helper #143

Merged
merged 27 commits into from
Jan 25, 2017
Merged

Implementing the flash helper #143

merged 27 commits into from
Jan 25, 2017

Conversation

paganotoni
Copy link
Member

@markbates @bketelsen @bscott this is where i am on the flash helper, i'll continue tomorrow with the iterator implementation, look forward for your feedback.

@bscott
Copy link

bscott commented Jan 19, 2017

@apaganobeleno

Should we add a notice and/or success message level?

@bketelsen
Copy link

bketelsen commented Jan 19, 2017 via email

Copy link
Member

@markbates markbates left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's looking good. A few comments. We should be able to add multiple messages to a key, so there should be an 'Add' function as well as a 'Set'

I also wonder if instead of having the session in the flash strict, what if we saved the flash to the session at the end of the request, instead of everytime we need to get or set things. It might be easier and cleaner.

Also, in the view we need to be able to check for the existence of a flash before we render code to display it. If I'm reading the code correctly the 'defer' call would delete it if we did an existence check before we render.

That all make sense? It's looking good though.

@paganotoni
Copy link
Member Author

@markbates great, i'll work in those changes and commit as i have these, i like the idea of loading and then storing into session at the end, thanks for that one.

@bketelsen
Copy link

so much excite!

@paganotoni
Copy link
Member Author

@markbates when checking the existence of a flash var, should we provide a helper just for that (something like {{ if flashSet "errors"}} ) or should it be something like: {{if flash "errors" }} that reuses the flash helper.

@bscott i'm very close, to have it :D #suspense.

@bscott
Copy link

bscott commented Jan 19, 2017

Nice!

I'm assuming flash will work for validation errors in models as in the Rails world?

@paganotoni
Copy link
Member Author

@markbates oh also, when you call {{flash "errors"}} and flash has multiple values, what should we render ?

@markbates
Copy link
Member

Ok, So I've given this some more thought. :)

I think we've been over thinking things a bit. Since flash is basically a wrapper around map[string][]string{} we basically always just need to loop. So...

{{#each flash.Errors as |e|}}
<div class="alert alert-danger" role="alert">{{e}}</div>
{{/each}}

That is all the template needs.

From the Go side it would look something like this:

type Flash struct {
	errors []string
}

func (f *Flash) Errors() []string {
	defer func() { f.errors = []string{} }()
	return f.errors
}

After Errors returns it's string array we clear it out.

With this approach, we don't really need a flashes helper, we can just leverage the existing each helper. We also don't need to check the existence, because since we're looping over an array we're either going to print out multiple chunks of html based on the number of messages we need to print or we're not going to print anything.

The each helper also supports else as well, so we can even print out stuff if there is nothing to loop over! :)

Does that make sense?

Also, that code above works if you have a Handler that looks like this:

func FlashMe(c buffalo.Context) error {
	flash := &Flash{
		errors: []string{"John", "Paul", "George", "Ringo"},
	}
	c.Set("flash", flash)

	return c.Render(200, r.HTML("flasher.html"))
}

@paganotoni
Copy link
Member Author

paganotoni commented Jan 20, 2017

Oh boy! thats way simpler and cleaner, just updated to that you suggested.

it works with:

{{#each flash.Errors as |error|}}
    {{error}}
{{else}}
    Nothing Found
{{/each}}

and

{{#each flash.All as |k flash|}}
    {{k}}:{{flash}}
{{else}}
    No Flash here!
{{/each}}

@paganotoni
Copy link
Member Author

@markbates should we add Notice and Success as well ?

@markbates
Copy link
Member

Can you add some tests that shows usage in the template?

I know that I can iterate using the Errors and All function, but I'm not sure the current implementation works with, let's a say, a key like noticeorwarning`.

@markbates
Copy link
Member

I think we are almost there with this!

@@ -102,6 +108,11 @@ func (d *DefaultContext) Render(status int, rr render.Renderer) error {
data["params"] = pp
bb := &bytes.Buffer{}
err := rr.Render(bb, data)

if d.Flash() != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be moved after the err check from rr.Render.

@paganotoni
Copy link
Member Author

paganotoni commented Jan 20, 2017

@markbates do you think {{#each (flash.Get "errors") as |error|}} should be the way to go on custom keys ? should we provide a helper for that ?

@markbates
Copy link
Member

Unfortunately {{#each (flash.Get "errors") as |error|}} doesn't work as a syntax. :(

If we change Flash from a struct to something like type Flash map[string][]string then we could use the syntax {{#each flash.errors as |error|}} in the template. I believe. :)

@markbates
Copy link
Member

I don't think we need predefined levels. Let's keep the code small for now. I, however, like the idea of purging the flash after a render. If you don't use it, you loose it. I can't think of a use case, other than redirect, where someone would need to persist a flash across many pages before displaying it.

@paganotoni
Copy link
Member Author

@markbates updated!, now flash for the view is map[string][]string to allow us to do flash.errors or any other key.

@paganotoni
Copy link
Member Author

@markbates something else to add/change here ?

@markbates
Copy link
Member

@apaganobeleno I'm in a class now. When I get back to the hotel I'all pull it down and play with it

@paganotoni
Copy link
Member Author

@markbates Thank you sir!

@markbates
Copy link
Member

Thank you! I can't wait to try it out!


//Persist the flash inside the session.
func (f *Flash) Persist(session *Session) {
for k := range session.Session.Values {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can clean all of this up by marshaling the flash and put just one thing into the session. Perhaps using json.


if session.Session != nil {
for k := range session.Session.Values {
sessionName := k.(string)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use json to marshal the flash in and out of the session and this gets a lot cleaner.

@markbates
Copy link
Member

@apaganobeleno I made a few changes to the PR. can you review? I think this is ready to merge.

@paganotoni
Copy link
Member Author

@markbates changes look great, thanks for that Mark.

i noticed an error being thrown when the each is iterating on a non-set value of the flash:

{{#each flash.errors as |k flash|}}
    {{k}}:{{flash}}
{{else}}
    Nothing Found
{{/each}}

causes :

error rendering show.html:
reflect: call of reflect.Value.Len on struct Value
github.com/gobuffalo/velvet.(*evalVisitor).evalHelper.func1
	/Users/antoniopagano/go/src/github.com/gobuffalo/velvet/eval.go:224
runtime.call32
	/usr/local/Cellar/go/1.7.4/libexec/src/runtime/asm_amd64.s:479
runtime.gopanic
	/usr/local/Cellar/go/1.7.4/libexec/src/runtime/panic.go:458
reflect.Value.Len
	/usr/local/Cellar/go/1.7.4/libexec/src/reflect/value.go:1014
github.com/gobuffalo/velvet.eachHelper
	/Users/antoniopagano/go/src/github.com/gobuffalo/velvet/each_helper.go:17

but

{{#each flash as |k flash|}}
    {{k}}:{{flash}}
{{else}}
    Nothing Found
{{/each}}

does not, i'm thinking this should be handled in velvet

@paganotoni
Copy link
Member Author

paganotoni commented Jan 25, 2017

@markbates i tried the same by doing:

//on my actions
func GetFlashHandler(c buffalo.Context) error {
	c.Set("myvar", map[string][]string{})
	return c.Render(200, r.HTML("show.html"))
}

And on my view:

All:
{{#each myvar.errors as |k dat|}}
    {{k}}:{{dat}}
{{else}}
    Nothing Found
{{/each}}

And same happens, would you accept a PR on velvet for this ?, basically on https://github.com/gobuffalo/velvet/blob/master/each_helper.go#L17 we should first check for val.IsValid() like:

if val.Kind() == reflect.Struct || val.Len() == 0 {

thoughts ?

@markbates
Copy link
Member

So with the fix to velvet, do we feel good about merging this @apaganobeleno?

@paganotoni
Copy link
Member Author

Feeling good about it, lets merge it :) 🚀 🚀

@markbates
Copy link
Member

Woot!! Yay!!

@markbates markbates merged commit dee71d6 into master Jan 25, 2017
@markbates markbates deleted the features/flash branch January 25, 2017 21:40
@markbates
Copy link
Member

Merged!!

@markbates markbates mentioned this pull request Jan 25, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants