2013-06-21 6 views
4

Я использую Play Framework, и у меня есть общий прецедент, чтобы обновить модель с помощью формы в действии контроллера. Но у меня есть некоторые проблемы, которые понимают концепцию, потому что это просто работает, если у вас есть форма, которая включает в себя ВСЕ свойства модели. Если у вас есть только частичная форма, например. редактируя только пароль пользовательской модели, этот метод уничтожает модель, поскольку он устанавливает другие свойства модели в значение null. Есть ли «официальное» решение этой проблемы? В любом случае Слушайте обновления только существующих свойств?Play Framework Обработка частичной формы

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()); 
    } 
} 

Возможно, решение лежит как-то в том, что метод bindFormRequest() может быть вызван с дополнительными параметрами, как и струнными или Карта струнных? Но я не могу понять цель этого. Некоторое понимание этого было бы замечательно. Спасибо большое!

ответ

7

В недавнем проекте мне понадобилась такая функция, и мне пришлось переопределить класс Form (на основе оригинальной формы воспроизведения), чтобы разрешить дополнительный параметр для метода bindFromRequest().

Принимая код в качестве примера, он стал бы что-то вроде этого:

Model model = Model.findById(id); 
Form<Model> filledForm = CustomForm.form(Model.class).bindFromRequest(model); 

Идея заключается в том, чтобы изменить только поля, определенные в форме и сохранить другие поля модели неизмененными.

Чтобы разрешить это специфическое связывание, вы должны переопределить метод bind(Map<String,String> data, String... allowedFields) (наряду с bindFromRequest) с чем-то вроде этого:

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)); 
      } 
     } 
    } 

Вместо создания DataBinder с blankInstance() как стандартный класс Play Форма делает, вы создаете его с помощью экземпляра модели как аргумент конструктора.

+0

Это отличный общий подход.Но где именно вы его реализовали? В вашем конкретном проекте или непосредственно в ядре Play? И знаете ли вы, какова цель уже существующего параметра метода bindFromRequest? – linsenfips

+1

Я создал класс CustomForm в своем конкретном проекте, который расширяет класс формы для чтения. Поэтому мне просто нужно использовать свой класс CustomForm вместо того, чтобы играть в ядро, когда мне нужна эта функция частичного привязки. Параметр 'data' содержит данные из запроса (посмотрите на ядро ​​воспроизведения' Form.bindFromRequest() 'source, он создает карту данных и передает ее методу' bind() '). 'AllowedFields' является необязательным параметром, используемым для ограничения привязанных данных (это функция Spring DataBinder). – mguillermin

+0

Думаю, я ошибаюсь, но не ограничиваю привязанные данные тем, что хочу? – linsenfips

1

Существует решение. Я бы сделал это более ориентированное на обслуживание приложение. Где вы создаете формы и модели для конкретных действий: updateUserPassword, updateUserEmail и т. Д. И в вашей модели реализуют эти простые методы.

+0

Хорошо, это было бы решением. Но тогда я должен сделать все вручную: получение конкретных данных формы с помощью bindFromRequest(). Data(). Get («password») и выполнение проверки, потому что я предполагаю, что hasErrors mehtod больше не может быть применен. – linsenfips

+0

Все, что вам нужно сделать, это создать модель, которая соответствует вашей форме. Если вы только обновляете пароль, создайте модель UpdateUserPassword и файл UpdateUserPasswordForm. Таким образом, вы можете сохранить всю свою валидацию, но на своей модели, а не на сущности. –

+1

Разве это не что-то вроде накладных расходов? Создание для каждого случая модели приведет к большому избыточности, поскольку свойства могут перекрываться. – linsenfips

0

Я предлагаю вам взглянуть на направлении лестницы, как вы можете объединить оба Scala и Java в одном проекте, с Скале вашей формой, может быть tuple, например:

val someForm = Form(tuple("user_id" -> number, "password"->text)), а затем из вашего запроса, вы можете использовать его для вашего обновления модели: