Question

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?

Was it helpful?

Solution

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.

OTHER TIPS

It seems you don't have your add.ctp view created for the Review.

It doesn't make sense to add a condition if you are not planning to do anything special. You always want to user to return to the product view right? It doesn't mind if it validates or not.

When you use the condition and it doesn't validate, the controller won't redirect you to the view action of products controller and it will load by default the add.ctp view.

Just keep using the redirection to go back to the form.

Use your first add action. It is correct. You can add a error message if you want:

public function add() {
if ($this->request->is('post')) {
    if(!$this->Review->save($this->request->data)({ 
        $this->Session->setFlash(__('There was a problem adding the product. Please try again.'));
    }
    $this->redirect(array('controller' => 'products', 'action' => 'view', $this->request->data['Review']['product_id'], '#' => 'reviews'));
}

Notice the redirection is there always.

It might not show the red error boxes on each input because you are using a 'redirect' instead of the default view for the action. Not quite sure anyway.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top