I need to create a review form. I have 2 models and 2 controllers – Products and Reviews with 'Products' hasMany 'Reviews' relationship, the review form will be displayed on the current product page (Products controller, 'view' action), and this form will be use another controller (Reviews).
Also I need validation for this form with validation errors being displayed.
In my Products controller view.ctp I have:
// product page stuff...
echo $this->Form->create($model = 'Review', array('url' => '/reviews/add'));
echo $this->Form->input('name', array('label' => 'Your name:'));
echo $this->Form->input('email', array('label' => 'Your e-mail:'));
echo $this->Form->input('message', array('rows' => '6', 'label' => 'Your message:'));
echo $this->Form->hidden('product_id', array('default' => $product['Product']['id']));
echo $this->Form->end('Send');
echo $this->Session->flash();
ReviewsController -> add:
public function add() {
if ($this->request->is('post')) {
$this->Review->save($this->request->data);
$this->redirect(array('controller' => 'products', 'action' => 'view', $this->request->data['Review']['product_id'], '#' => 'reviews'));
}
}
Somehow this horrible code works.. in part. Review saves, but validation errors are not displaying.
If I add If statement to this action:
ReviewsController -> Add:
public function add() {
if ($this->request->is('post')) {
if ( $this->Review->save($this->request->data) ){
$this->redirect(array('controller' => 'products', 'action' => 'view', $this->request->data['Review']['product_id'], '#' => 'reviews'));
}}
}
and if form have errors and didn't validates I get MissingView error: Missing View
Error: The view for ReviewsController::add() was not found.
My question is how to properly deal with this situation to achieve functionality that I need? Should I use elements with request action or I should move action for adding reviews to the ProductsController?
One of your problems is that you are only doing the redirect if the save is successful, so if it fails you don't have a Review/add.ctp so it is giving you a missing view error. You need to do the redirect regardless of the save working or not, so that you always get taken back to the products page.
And the reason you won't get the errors on the fields would be because you are doing a redirect, so the errors get lost. You could just pass the errors through to the products controller as another parameter of the action.
ReviewsController
public function add() {
if (!empty($this->request->data)) {
$errors = null;
if (!$this->Review->save($this->request->data)) {
$errors = $this->Review->validationErrors;
}
// Always redirect
$this->redirect(array('controller' => 'products', 'action' => 'view', $this->request->data['Review']['product_id'], 'errors' => $errors, '#' => 'reviews'));
}
}
ProductsController
public function view($product_id, $errors = null) {
if (!empty($errors)) {
$this->Review->validationErrors = $errors;
}
}
Of course I don't know what all of your code looks like, and this is untested, but the idea is to pass the Review model's validation errors to the product controller and then assign them manually back to the Review model again on the products page.