Reputation: 718
I'm using the Play Framework and I've got the common use case to update a model with a form in a controller action. But I've some issues understanding the concept behind it because this is just working if you have a form which includes ALL of the properties of the model. If you have a just a partial form, e.g. editing just a password of a user model, this method destroys the model, because it sets the other properties of the model to null. Is there any "official" solution to that problem? Any way Play updates just the existing properties?
public static Result update(Long id) {
Model model = Model.findById(id);
Form<Model> filledForm = modelForm.bindFromRequest();
if (filledForm.hasErrors()) {
return badRequest(edit.render(filledForm));
} else {
model.update();
flash("message", "Created new Model!");
return ok(index.render());
}
}
Probably the solution lays somehow in the fact that the bindFormRequest() method can be called with additional parameters, like Strings or a Map of Strings? But I can not find out the purpose of that. Some insight into that would be great as well. Thanks a lot!
Upvotes: 5
Views: 2290
Reputation: 1237
I suggest you taking a look at scala direction, as you can merge both scala and java in one project, with scala your form maybe a tuple
for example:
val someForm = Form(tuple("user_id" -> number, "password"->text))
and then from your request you can use it to perform your model update:
someForm.bindFromRequest.fold(
formWithErrors => {
BadRequest
},
data => {
// update method takes two parameters user_id and password to update
User.updatePassword(data._1,data._2)
Ok("...")
}
)
Upvotes: 0
Reputation: 4181
On a recent project, I needed this kind of feature and I had to reimplement the Form class (based on the original Play Form) to allow an additional parameter to the bindFromRequest()
method.
Taking your code as an example, it would become something like this :
Model model = Model.findById(id);
Form<Model> filledForm = CustomForm.form(Model.class).bindFromRequest(model);
The idea is to only modify the fields defined in your form and keep the other fields of your model unmodified.
To allow this specific binding, you have to redefine the bind(Map<String,String> data, String... allowedFields)
method (along with the bindFromRequest
) with something like this :
public Form<T> bind(T instance, Map<String,String> data, String... allowedFields) {
DataBinder dataBinder = null;
Map<String, String> objectData = data;
if(rootName == null) {
dataBinder = new DataBinder(instance);
} else {
dataBinder = new DataBinder(instance, rootName);
objectData = new HashMap<String,String>();
for(String key: data.keySet()) {
if(key.startsWith(rootName + ".")) {
objectData.put(key.substring(rootName.length() + 1), data.get(key));
}
}
}
Instead of creating the DataBinder
with blankInstance()
as the standard Play Form class does, you create it with you model instance as the constructor argument.
Upvotes: 8
Reputation: 10404
There is a solution. What I would do is make a more service oriented application.
Where you create forms and models for specific actions : updateUserPassword
, updateUserEmail
, etc. and in your model implement those simple methods.
Upvotes: 1