Assign random value to form - forms

I am using this code to assign a default random value to a form field ("token"):
val userForm = Form(
mapping(
"token" -> default(text, (randomString("0123456789abcdef")(40))),
"username" -> optional(text),
"email" -> email,
"password" -> nonEmptyText,
"gender" -> nonEmptyText
)(User.apply)(User.unapply)
)
It seems like the "token" random value is generated only once and never changes after that. Any way of solving this issue?

Create your own Mapping that takes a thunk. The following is inspired by the Forms source:
def defaultThunk[A](mapping: Mapping[A], value: =>A): Mapping[A] =
OptionalMapping(mapping).transform(_.getOrElse(value), Some(_))
As value is used in a anonymous function it should be getting called every time, giving a different random number.
So instead of using
"token" -> default(text, (randomString("0123456789abcdef")(40))),
use instead:
"token" -> defaultThunk(text, (randomString("0123456789abcdef")(40))),

It is like this because your form is immutable.
As #Kigyo suggest in comment, I also think that you can try change it to function, but it will be not efficient when you want bind form data from request after that.
Another solution is to use fill method on form, something like that:
userForm.fill(User((randomString("0123456789abcdef")(40)), None, "", "")
It will return new form with filled data. That form you can put to your view template.
However, I am not sure if it is the best solution...

Alternatively you could write in your template as
#inputText(userForm("token").copy(value=Some(randomString("0123456789abcdef")(40))))
or pass the randomString as parameter to template and use as
#(userForm: Form[_], randStr)
#inputText(userForm("token").copy(value=Some(randStr)))

Related

Play Framework 2 template Form None.get

Im new to Play 2 and Scala, and im getting a strange Exception in my template:
Execution exception
-------------------
[NoSuchElementException: None.get]
In /home/nic/workspaces/scala-ide/scims/app/views/persons/detailTabs/personal.scala.html at line 4.
1. #(personId: Long, personDetailTabForm: Form[dto.PersonDetailTab])(implicit formOptions: dto.PersonFormOptions)
2. #implicitFieldConstructor = #{ helper.FieldConstructor(support.bs3HorizField.f) }
3.
4. #persons.detail("personal", personDetailTabForm.get.firstName) {
The personDetailTabForm is an empty form object defined as:
val personalDetailTabForm: Form[PersonDetailTab] = Form(
mapping(
"firstName" -> text.verifying(nonEmpty),
"middleName" -> text,
"lastName" -> text.verifying(nonEmpty),
"gender" -> text,
"dateOfBirth" -> jodaDate("yyyy-MM-dd"),
"ethnicity" -> text,
"maritalStatus" -> text,
"password" -> text
)(PersonDetailTab.apply)(PersonDetailTab.unapply)
)
Any ideas as to what's wrong here?
I was under the impression a variable would have to be an Option to get a None?
Cheers
NFV
You are calling get on personDetailTabForm - Looking up it's ScalaDoc: http://www.playframework.com/documentation/2.2.x/api/scala/index.html#play.api.data.Form - it seems that .get returns the PersonDetailTab value that the form holds - IF, as the docs say, 'the submission was a success'.
You're seeing the None.get exception because most likely play.api.data.Form[T] simply uses Option[T] and get returns Some[T] when the form holds a valid value and None otherwise.
So on your line 4, in the scala template, you have something like
personDetailTabForm.get.firstName
That's a String, but you can expect a value only when the form's underlying PersonDetailTab itself has a value. I am not sure what you want to do, but you're dealing with a case where a value you want to render in a template might not be there, for whatever reason. In which case:
#personDetailTabForm.value.map{ personDetailTab =>
#persons.detail("personal", personDetailTab.firstName) // { ... whatever else
// anything else you want to render
} getOrElse { // errors in the form; personDetailTabForm cannot yield a valid personDetailTab
<h3> oops, what went wrong here? </h2>
}
It all depends on what you want to do in personal.scala.html. Form[T] is a good way
to deal with input and validation of some T thing, but if you are just displaying it,
and if you have a T (in your case PersonDetailTab) just pass that to the template as it is. If your PersonDetailTab may or may not exist, then just use Option[PersonDetailTab] instead Form[PersonDetailTab].

Only bind part of the Form mappings from request

I am using Play 2.1.2 and I have a Form with the following mapping:
Form(
mapping(
"id" -> ignored(NotAssigned: Pk[Long]),
"name" -> nonEmptyText,
"stock" -> number(min = 0),
"initialAmount" -> number(min = 0),
"distUnitId" -> longNumber,
"categoryId" -> longNumber
)
(BarItem.apply)
(BarItem.unapply)
)
In the view, I want to use a form helper to edit only part of the values. In particular, the "initialAmount" value is meant to be only set once - when creating an item - and not be allowed to change on edit. So I just do not want to display it in the form and "keep" its previous value after form submission.
Currently the interesting part of the edit view looks like this:
#form(routes.Application.update(id), 'class -> "form-inline") {
<fieldset>
#inputText(barItemEditForm("name"), '_label -> "Produktbezeichnung")
#inputText(barItemEditForm("stock"), '_label -> "Lagermenge")
#select(
barItemEditForm("distUnitId"),
distUnits,
'_label -> "Einheit"
)
#select(
barItemEditForm("categoryId"),
categories,
'_label -> "Kategorie"
)
When navigating to the edit view, I fill the form with the fill() method of the Form class:
BarItem.findById(id).map {
item =>
Ok(html.edit(id, barItemEditForm.fill(item), DistUnit.selectOptions, Category.selectOptions))
}.getOrElse(NotFound)
In the action, that handles the form submission I bind the Form from request like so:
...
implicit request =>
barItemEditForm.bindFromRequest.fold(
formWithErrors => BadRequest(html.edit(id, formWithErrors, DistUnit.selectOptions, Category.selectOptions)),
item => {
...updateStuff...
}
)
...
So the problem is now, that as I do not have an input field for "initialAmount" in the view, I get an error when binding from request, saying it has no value.
Is it somehow possible to only apply part of the values from request and keep this one value from the call to fill() before?
Or can anyone suggest a proper way to handle this kind of "partial editing"?
I'm really looking forward to any suggestions!
Since you want to keep the value, that probably means a hidden input when you rerender the form. If the previous value comes from elsewhere, e.g. the database, you could define another form with an ignored mapping for that field.

Setting the property of an object using a variable value in scala

I'm trying to create a restful method to update data in the database, I'm using Scala on Play! framework. I have a model called Application, and I want to be able to update an application in the database. So the put request only requires the id of the application you want to update, then the optional properties you want to update.
So in my routes I have this:
PUT /v1/auth/application controllers.Auth.update_application(id: Long)
The method I currently have is this:
def update_application(id: Long) = Action { implicit request =>
var app = Application.find(id)
for((key, value) <- request.queryString) {
app."$key" = value(0)
//app.name = value(0)
}
val update = Application.update(id, app)
Ok(generate(
Map(
"status" -> "success",
"data" -> update
)
)).as("application/json")
}
In the method above I am looping through the request and the app object as a map instance, then updating the app model to be updated using the model. I know there is an easier way is to create the request string as map and just iterate through the object, but I am doing it this way for learning purposes. I'm new to Play! and Scala, barely a week new.
Is there a way to set a property using a variable dynamically that way? In the above method at the end of the loop that is how I would update a object's property in Groovy. So I'm looking for the equivalent in Scala. If Scala can't do this, what is the best way about going about accomplishing this task? Reflection? I don't want to over-complicate things
Play! provides play.api.data.Forms which allows creating a Form that uses the apply() and unapply() methods of a case class. Then you can call form.fill(app) to create a form with the initial state, bindFromRequest(request) to update the form with the request parameters, and get() to obtain a new instance with updated fields.
Define the form only once:
val appForm = Form(
mapping(
"field1" -> text,
"field2" -> number
)(Application.apply)(Application.unapply)
)
Then in your controller:
val app = appForm.fill(Application.find(id)).bindFromRequest(request).get
val update = Application.update(id, app)
Check out Constructing complex objects from the documentation.

Play 2: idiomatic approach to binding a form to List[Model]

I have several CRUD operations to perform, each one on a collection of models (e.g. game schedule, team roster, game result, game stats, etc.).
Up to this point in my Play experience (just a few months, 1 project live) I have been working with one-to-one form binding to model instance.
I know I can numerically index form field names, but then how to bind the posted form to List[Model]?
This is what my one-to-one binding looks like:
// abstract away bindFromRequest to make binding more concise in controllers
def bindForm[T](f: play.api.data.Form[T])(implicit r: play.api.mvc.Request[_]) =
f.bindFromRequest fold(e=> Left(e.errorsAsJson), Right(_))
and then in controllers:
val result = for {
model <- bindForm(form).right
id <- dao.create(model) as json
} yield id
what I would like to do is the same, but instead of model binding returning a single Model on success, have it return a List[Model], and pass on to overloaded DAO create/edit/delete operations.
I see that there is a list method that one can use as part of a Form mapping, but I have a feeling that that would wreak havoc with my JDBC query wrapper (ScalaQuery/Slick), whose case class/companion object mapping would likely not play well with collections properties.
For example, existing mapping of a game schedule looks like:
object CompositeForm {
import play.api.data.{Form, Forms}, Forms._
import utils.Validator.Bindings.jodaLocalTimeFormat
val mapper = mapping(
'id -> ignored(0),
'gameDate -> jodaDate,
'gameType -> optional(text),
'location -> optional(text),
'team1 -> number,
'team2 -> number
)(Composite.apply)(Composite.unapply)
val form = Form( mapper )
}
using list(gameDate), list(gameType) instead then means that form binding will return a single Composite instance whose properties are all collections -- maybe it will work, but doesn't seem nearly as clean/straightforward as working with a collection of model instances.
Ideas appreciated ;-)
The as yet documented seq() option in play form mapping was pointed out to me on Play google group by #Julien Richard-Foy
Using repeat() and seq() together allows one to repeat a form mapping, thus creating a collection of indexed foo.bar[n] formfield elements.
Example
object ScheduleForm {
import play.api.data.{Form, Forms}, Forms._
val mapper = mapping(
'composite -> seq(CompositeForm.mapper),
'note -> seq(ScheduleNoteForm.mapper)
)(Schedule.apply)(Schedule.unapply)
val form = Form( mapper )
}
and then in a view:
#repeat(_form("composite"), min=#numGames) { f=>
#inputDate(f("gameDate"), '_label-> "Game Date", 'class-> "required")
...
}

How to display ad hoc constraints form validation messages?

ScalaForms
In the example linked here there is this example about form validation:
// You can also define ad-hoc constraints on the fields:
val loginForm = Form(
tuple(
"email" -> nonEmptyText,
"password" -> text
) verifying("Invalid user name or password", fields => fields match {
case (e, p) => User.authenticate(e,p).isDefined
})
)
Via binding errors some constraints are displayed in my form. (Like the nonEmptyText, that gets a extra line behind the field stating This field is required. See:
loginForm.bindFromRequest.fold(
formWithErrors => // binding failure, you retrieve the form containing errors,
value => // binding success, you get the actual value
)
If I do a .toString to the formWithErrors i get this for the nonEmptyText constraint:
Form(ObjectMapping2(<function2>,<function1>,(Email adress,FieldMapping(,List(Constraint(Some(constraint.required),WrappedArray())))),(Password,FieldMapping(,List(Constraint(Some(constraint.required),WrappedArray())))),,List(Constraint(None,List()))),Map(Password -> test, Email adress -> ),List(FormError(Email adress,error.required,WrappedArray())),None)
The latter part is a FormError List: List(FormError(Email adress,error.required,WrappedArray())),None) which is a case class: case class FormError (key: String, message: String, args: Seq[Any]) where key is defined as: The error key (should be associated with a field using the same key)..
The FieldConstructor picks this up and makes the 'Email adress' input box go red and add the error message ('This field is required').
Displaying the ad hoc constraints?
So when the form fields are all filled the username and password are checked:
verifying("Invalid user name or password", fields => fields match {
case (e, p) => User.authenticate(e,p).isDefined
})
But i dont know how to display the 'Invalid user name or password' to the user. The .toString of the FormError List of formWithErrors is:
List(FormError(,Invalid user name or password,WrappedArray())),None)
The Key part is empty.
Question
How do i display the ad hoc error?
I even tried:
BadRequest( views.html.test( formWithErrors ) ).flashing( "error" -> "Invalid user name or password." ) },
but for some reason its not working via the Flash either :(. This #flash.get("error").getOrElse("no 'error'") gives me 'no error' each time.
Actually, a form can have errors attached to it, so then when a bind from request fails validating constraint, a new form is created based on the given one, but filled in with errors.
Such errors list is composed of FormError which refers a Form Field and overrides toString to show its embed message.
This way if you wish to show all messages at once, you can simply formWithErrors.errors.mkString("<br>") for instance (in you template or flashing it).
There are a lot of ways and some common ones are described here http://www.playframework.org/documentation/2.0.2/ScalaFormHelpers. You might define your own field constructor as well.
To conclude, my advice would be that you should use helpers amap (for instance #inputText and co) because they already contain the logic to show helpers, tips and errors when available.
Edit
I missed the hint about the flash problem... you've probably forgotten to add (implicit flash: Flash) to you template param list. (don't forget to flag the request as implicit as well in your action definition)