How to get id of child record (case class) in Play Framework (2.4.0) using forms

I'm afraid I don't see it yet.

There must be a way, using the tools as they are meant to be used, to get the child record id (many-to-one typical relational database stuff) of a series of "items"

I can create a "shape" (mapping) in the parent's case class with no problem.

lazy val aForm = Form( mapping( "ID" -> ignored(id), "firstName" -> nonEmptyText, "lastName" -> nonEmptyText, "listOfEmails" -> seq(email), "statusID" -> ignored(0l), "roleID" -> default(longNumber, roleID), "timezoneID" -> default(longNumber, timezoneID) (User.apply) (User.unapply) )

Now we can break it down a bit and have this:

lazy val aForm = Form( mapping( "ID" -> ignored(id), "firstName" -> nonEmptyText, "lastName" -> nonEmptyText, "listOfEmails" -> mapping( "email" -> email, "userID" -> ignored(id), "emailTypeID" -> longNumber) (UserEmail.apply)(UserEmail.unapply), "statusID" -> ignored(0l), "roleID" -> default(longNumber, roleID), "timezoneID" -> default(longNumber, timezoneID) (User.apply) (User.unapply) )

The above uses the "helper" form to ensure that the minimum amount of spaces is ready for new entries.

And we can even get a little more creative (DRY) and do this:

lazy val aForm = Form( mapping( "ID" -> ignored(id), "firstName" -> nonEmptyText, "lastName" -> nonEmptyText, "listOfEmails" -> seq(UserEmail.EMPTY.form(id).mapping), "statusID" -> ignored(0l), "roleID" -> default(longNumber, roleID), "timezoneID" -> default(longNumber, timezoneID) (User.apply) (User.unapply) )

where the form within the case class is UserEmail

"reused" instead of being "repeated" in the parent case class. EMPTY is just an object that I use as a constant for each case class.

Note that although this creates "blank" form entries, they are filled out on the form / screen. Thanks, in no small part, to this little helper (repeatWithIndex - https://gist.github.com/benoit-ponsero/4484313 ), which everyone says is unnecessary! (???)

What I haven't been able to find yet is how I take Seq[UserEmail]

(which is of course available inside the parent class of the class User

) and propagate its ID down the food chain and back and forth back and forth by POST on the controller?

Currently I can do this funky thing with zip

and create a duplicate list and merge the bit back to server side foreach

, but it just "feels yucky".

Depending on the data (I want to do this for all types of objects, much more complex than simple email addresses), it can be difficult to establish with certainty if any given record is an addition, a change, or a delete. Even assuming it was possible, it is a lot of work to implement one-to-one work on an individual basis (and a lot of unnecessary (?) Debt inherited to boot!)

Has anyone else hacked this nut and shared it?

0


source to share


1 answer


Ok - I have one firing solution.

I first reworked the temple to include hidden fields (yuck!) For each item.

Then, inside the application, I added logic like this:

def apply( id: Long, firstName: String, lastName: String, emails: Seq[UserEmail], statusID: Long, roleID: Long, timezoneID: Long) = { trace("emails: {}", emails) emails foreach { x => x.writeDB trace(x) } new User(id, firstName, lastName, statusID, roleID, timezoneID) }

and then in the method unapply

def unapply(x: User): Option[(Long, String, String, Seq[UserEmail], Long, Long, Long)] = Some(x.id, x.firstName, x.lastName, x.tkEmails, x.statusID, x.roleID, x.timezoneID)



It looks like magic is happening between the two methods. Note the asymmetry here, which I don't have Seq[UserEmail]

as val

in the constructor of the case class. It is silently discarded unapply

and processed apply

.

The "internal" form userEmail

should be implemented as follows:

def form(userID: Long) = Form( mapping( "ID" -> default(longNumber, id), "userID" -> default(longNumber, userID), "address" -> optional(email) )(UserEmail.apply)(UserEmail.unapply) )

It's time to go to hell, I knew it for a long time!

It's too far from elegant (there is a lot of code I have to take into account - this is a radically stripped-down example to show the relevant concept), but at least it's workable - would still love to see something much more "play-ish" if possible!

0


source







All Articles