Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Play framework 2 : How to pass object between routes, views, and controller?

I'm trying to pass a book object from views to routes, and then send it to calculate in a controller. My code is following:

bookList.scala.html

@(books: java.lang.Iterable[Book])

@main("BookList"){
    <div class="row">
        @for(book <- books.iterator()){
            <div class="col-sm-6 col-md-4">
                <div class="thumbnail" style="height: 435px">
                         ...
                        <p><a href="@routes.Application.buy(book)" class="btn btn-primary" role="button"
                              style="vertical-align:bottom">Order now!</a>
                    </div>
                </div>
            </div>
        }
    </div>

}

routes

...
GET     /order                      controllers.Application.buy(book: models.Book)
...

However, It gave me an error : No QueryString binder found for type models.Book. Try to implement an implicit QueryStringBindable for this type.

I tried to change the routes as :

    GET     /order                      controllers.Application.buy(book)

It also returned an error :

type mismatch; found : String required: models.Book
like image 369
lvarayut Avatar asked Dec 11 '22 06:12

lvarayut


1 Answers

That's not how Play routing works. The Play router parses variables from the URL or query string, and converts them to native types via the QueryBindable typeclass. You should have something more like this:

routes

GET /order/:bookid           controllers.Application.buy(bookid: String)

And the action should be like:

Application.scala

def buy(bookid: String) = Action { request =>
    // Look up book by id here.
   Ok(views.html.thanks("you bought a book!"))
}

And the template like this:

bookList.scala.html

@for(book <- books.iterator()) {
    ...
    <a href="@routes.Application.buy(book.id)" class="btn btn-primary"         
}

Of course if your model's ID is other than String you need to modify the route's param type

Update -- alternative using form/POST

A form with a POST method is a better solution, or the user will buy another book each time they click the URL, and the id will be exposed. Check out the forms documentation. Your template would be like this:

@for(book <- books.iterator()) {
    ...
    <form method="post">
      <div>@book.name</div>
      <input type="hidden" value="@book.id"/><button type="submit">buy</button>
    </form>
}
like image 68
Richard Close Avatar answered May 18 '23 15:05

Richard Close