131

I know this question has been asked many times before but no one explains how to get the id when you're validating in the model.

'email' => 'unique:users,email_address,10'

My validation rule is in the model so how do I pass the ID of the record to the validation rule.

Here is my models/User

protected $rules_update = [
    'email_address' => 'required|email|unique:users,email_address,'.$id,
    'first_name' => "required",
    'last_name' => "required",
    'password' => "required|min:6|same:password_confirm",
    'password_confirm' => "required:min:6|same:password",
    'password_current' => "required:min:6"
];

models/BaseModel

    protected $rules = array();

public $errors;

/*
    * @data: array, Data to be validated
    * @rules: string, rule name in model 
*/

public function validate($data, $rules = "rules") {

    $validation  = Validator::make($data, $this->$rules);

    if($validation->passes()) {
        return true;
    }

    $this->errors = $validation->messages();

    return false;
}
3
  • I would also love to know how the $id is passed to the model. I'm using the way/database package and have the same issue. Commented Jul 6, 2014 at 14:26
  • I've added my answer below. Commented Jul 7, 2014 at 5:35
  • Me too, having the same issue Commented Jan 21, 2015 at 20:44

35 Answers 35

138

Just a side note, most answers to this question talk about email_address while in Laravel's inbuilt auth system, the email field name is just email. Here is an example how you can validate a unique field, i.e. an email on the update:

In a Form Request, you do like this:

public function rules()
{
  return [
      'email' => 'required|email|unique:users,email,'.$this->user->id,
  ];
}

Or if you are validating your data in a controller directly:

public function update(Request $request, User $user)
{
  $request->validate([
      'email' => 'required|email|unique:users,email,'.$user->id,
  ]);
}

Update: If you are updating the signed in user and aren't injecting the User model into your route, you may encounter undefined property when accessing id on $this->user. In that case, use:

public function rules()
    {
      return [
          'email' => 'required|email|unique:users,email,'.$this->user()->id,
      ];
    }

A more elegant way since Laravel 5.7 is:

public function rules()
{
    return [
        'email' => ['required', 'email', \Illuminate\Validation\Rule::unique('users')->ignore($this->user()->id)]
    ];
}

P.S: I have added some other rules, i.e. required and email, in order to make this example clear for newbies.

Sign up to request clarification or add additional context in comments.

7 Comments

I am using FormRequest, and this is exactly what I needed to do.
How should I access/provide $this->user() or other models in FormRequest? like $this->article() in ArticleFormRequest
@KrzysztofDziuba do you want to access signed in user?
Using \Illuminate\Validation\Rule::unique() it's really the most elegant way. For me, that was the best suggestion. Thanks
This great for unique validation. Now I want to validate the image for update but only if user uploads new on.
|
55

One simple solution.

In your Model

protected $rules = [
    'email_address' => 'sometimes|required|email|unique:users',
    ..
];

In your Controller, action:update

...
$rules = User::$rules;
$rules['email_address'] = $rules['email_address'] . ',id,' . $id;
$validationCertificate  = Validator::make($input, $rules); 

4 Comments

Cannot access protected property App\User::$rules
@SoubhagyaKumarBarik What version is your Laravel?
my laravel version is 7.x
@SoubhagyaKumarBarik My answer was in 2014, for version 4.x. So, I think for version 7 you have a different solution. Check the other answers below, or create a new question on Stack overflow, and add the link here to us to help you.
40

There is an elegant way to do this. If you are using Resource Controllers, your link to edit your record will look like this:

/users/{user}/edit OR /users/1/edit

And in your UserRequest, the rule should be like this :

public function rules()
{
    return [
        'name' => [
            'required',
            'unique:users,name,' . $this->user
        ],
    ];
}

Or if your link to edit your record look like this:

/users/edit/1

You can try this also:

public function rules()
{
    return [
        'name' => [
            'required',
            'unique:users,name,' . $this->id
        ],
    ];
}

1 Comment

This answer is the best and most elegant. I have a question. Link to my edit record looks like /users/{user}/edit and I want to prevent my unique:users,name being able to be updated while other fields can be updated. How would I achieve it?
22

From Laravel 5.7, this works great

use Illuminate\Validation\Rule;

Validator::make($data, [
    'email' => [
        'required',
        Rule::unique('users')->ignore($user->id),
    ],
]);

Forcing A Unique Rule To Ignore A Given ID:

Comments

13

Test below code:

'email' => 'required|email|unique:users,email_address,'. $id .'ID'

Where ID is the primary id of the table

1 Comment

'email' => 'required|email|unique:users,email_address,'. $id .',user_id' worked for me. Here user_id is primary key of the table. Thanks.
9

If i understand what you want:

'email' => 'required|email|unique:users,email_address,'. $id .''

In model update method, for exemple, should receive the $id with parameter.

Sorry my bad english.

4 Comments

Does the $id parameter get passed into model. I've already tried'email' => 'unique:users,email_address,{{$id}}' with no luck'
{{$id}} works only in views with blade. So you shoud use string scape: 'unique:users,email_address,'. $id .'' or "unique:users,email_address,". $id .""
Doesn't work. Error below 1. Symfony\Component\Debug\Exception\FatalErrorException …/­app/­models/­User.php42 0. Illuminate\Exception\Handler handleShutdown <#unknown>0 Symfony \ Component \ Debug \ Exception \ FatalErrorException syntax error, unexpected '.', expecting ']'
You can show your model method or print a image from error page?
8

an even simpler solution tested with version 5.2

in your model

// validator rules
public static $rules = array(
    ...
    'email_address' => 'email|required|unique:users,id'
);

Comments

8

Here is the solution:

For Update:

public function controllerName(Request $request, $id)

{

    $this->validate($request, [
        "form_field_name" => 'required|unique:db_table_name,db_table_column_name,'.$id
    ]);

    // the rest code
}

That's it. Happy Coding :)

Comments

8

In Laravel 8.x you can use Rule::unique method as well

Forcing A Unique Rule To Ignore A Given ID:

use Illuminate\Validation\Rule;

public function update(Request $request, Post $post)
{
    $validatedData = $request->validate([
        'name' => ['required', 'max:60', Rule::unique('posts')->ignore($post->id)],
    ]);

    $post->update($validatedData);
    
    return redirect(route('posts.index'))->with('status', 'post updated successfully');
}

Comments

7
public function rules()
{

    switch($this->method())
    {
        case 'GET':
        case 'DELETE':
        {
            return [];
        }
        case 'POST':
        {
            return [
                'name' => 'required|unique:permissions|max:255',
                'display_name' => 'required',
            ];
        }
        case 'PUT':
        case 'PATCH':
        {
            return [                    
                'name' => 'unique:permissions,name,'.$this->get('id').'|max:255',
                'display_name' => 'required',
            ];
        }
        default:break;
    }    
}

3 Comments

Sometimes, the id could be part of the URL and so you will find it in the route parameters: $this->route({field_name}) eg: $this->route('id')
Its' always better to mention reference you copied the code from laracasts.com/discuss/channels/requests/…
you have to pass hidden field with id to use $this->get('id')
7

You can try this.

protected $rules_update = [
    'email_address' => 'required|email|unique:users,email_address,'. $this->id,
    'first_name' => "required",
    'last_name' => "required",
    'password' => "required|min:6|same:password_confirm",
    'password_confirm' => "required:min:6|same:password",
    'password_current' => "required:min:6"
];

Comments

7

The Best Option is here try just once no need more code when unique validation on updating data

'email' => 'unique:users,email_address,' . $userId,

hereemailis field name and users is table name and email_address is table attribute name which you want unique and $userid is updating row id

Comments

7

Do One step in controller

Works Fine with Laravel 9

$request->validate([
        'name'=>'required|unique:categories,name,'.$id,
    ]);

Comments

6

If you have a separate rules method. You can use easier the following syntax.

public function rules()
{
    return [
        'email' => "required|unique:users,email,{$this->id}"
    ]; 
}

Comments

5
$rules = [
    "email" => "email|unique:users, email, '.$id.', user_id"
];

In Illuminate\Validation\Rules\Unique;

Unique validation will parse string validation to Rule object

Unique validation has pattern: unique:%s,%s,%s,%s,%s'

Corresponding with: table name, column, ignore, id column, format wheres

/**
 * Convert the rule to a validation string.
 *
 * @return string
 */
public function __toString()
{
    return rtrim(sprintf('unique:%s,%s,%s,%s,%s',
        $this->table,
        $this->column,
        $this->ignore ?: 'NULL',
        $this->idColumn,
        $this->formatWheres()
    ), ',');
}

1 Comment

I like where you got there. But I'm just not sure on how to apply this to a model's rules. Where should I replace {{$id}}?
4

i would solve that by doing something like this

public function rules()
{
    return [
         'name' => 
            'required|min:2|max:255|unique:courses,name,'.\Request::get('id'),
    ];
}

Where you get the id from the request and pass it on the rule

1 Comment

The Laravel docs warn of this technique as it can introduce a security vulnerability. Imagine an attacker can modify the rules by supplying anything to the id parameter. laravel.com/docs/5.8/validation#rule-unique
4

There is a simple and elegant way to do this. If you are passing the user_id in a body request or through a query parameter. e.g

/update/profile?user_id=

Then in your request rules

  public function rules(Request $request)
    {
        return [
            'first_name' => 'required|string',
            'last_name' => 'required|string',
            'email' => ['required','email', 'string', Rule::unique('users')->ignore($request->user_id )],
            'phone_number' => ['required', 'string', Rule::unique('users')->ignore($request->user_id )],
        ];
    }

Better Still, you can pass in auth->id() in place of $request->user_id to get the login user id.

Comments

3

Found the easiest way, working fine while I am using Laravel 5.2

public function rules()

{

switch ($this->method()) {
    case 'PUT':
        $rules = [
            'name'                  => 'required|min:3',
            'gender'                => 'required',
            'email'                 => 'required|email|unique:users,id,:id',
            'password'              => 'required|min:5',
            'password_confirmation' => 'required|min:5|same:password',
        ];
        break;

    default:
        $rules = [
            'name'                  => 'required|min:3',
            'gender'                => 'required',
            'email'                 => 'required|email|unique:users',
            'password'              => 'required|min:5',
            'password_confirmation' => 'required|min:5|same:password',
        ];
        break;
}

return $rules;
}

2 Comments

In my case, I couldn't pull the id using ":id", so I did something like this: if (in_array($this->method(), ['PUT', 'PATCH'])) { $rules['order'] .= ",{$this->route('videos')->id}"; }
"id,:id" Not worked for me dear in edit/update mode. Thanks.
3

You can also use model classpath, if you don't want to hard code the table name.

function rules(){
    return [
        'email' => ['required','string',
         Rule::unique(User::class,'email')->ignore($this->id)]
    ];
}

Here $this->id is either 0 or the record Id to be updated.

Comments

3

Most answers to this question refer to email_address, but in Laravel's inbuilt authentication system, the email field name is just email. Here is an example of validating a unique field, i.e. an email on the update:

Form Requests look like this:

public function rules()
    {
      return [
          'email' => [ 'required','email', Rule::unique('users')->ignore($this->id ?? 0)]];
    }

?? 0 If you use this then if hare id does not exist this request will not give you an error

Save Whenever you access the id property of $this->user, you may encounter an undefined property if you haven't injected the User model into your route. If that is the case, use:

public function rules()
    {
      return [
          'email' => 'required|email|unique:users,email,'.$this->user()->id ?? 0,
      ];
    }

?? 0 If you use this then if hare id does not exist this request will not give you an error

Comments

2

Use for Laravel 6.0

use Illuminate\Validation\Rule;

public function update(Request $request, $id)
    {
        // Form validation
        $request->validate([
            'category_name'   =>  [
                'required',
                'max:255',
                 Rule::unique('categories')->ignore($id),
            ]
        ]);
}

Comments

2

After researching a lot on this laravel validation topic including unique column, finally got the best approach. Please have a look

In your controller

    use Illuminate\Http\Request;
    use Illuminate\Support\Facades\Validator;

    class UserController extends Controller
    {
         public function saveUser(Request $request){
                $validator = Validator::make($request->all(),User::rules($request->get('id')),User::$messages);
                if($validator->fails()){
                    return redirect()->back()->withErrors($validator)->withInput();
                }
            }
    }

saveUser method can be called for add/update user record.

In you model

class User extends Model
{
    public static function rules($id = null)
    {
        return [
            'email_address' => 'required|email|unique:users,email_address,'.$id,
            'first_name' => "required",
            'last_name' => "required",
            'password' => "required|min:6|same:password_confirm",
            'password_confirm' => "required:min:6|same:password",
            'password_current' => "required:min:6"
        ];
    }
    public static $messages = [
        'email_address.required' => 'Please enter email!',
        'email_address.email' => 'Invalid email!',
        'email_address.unique' => 'Email already exist!',
        ...
    ];
}

Comments

1

This is what I ended up doing. I'm sure there is a more efficient way of doing this but this is what i came up with.

Model/User.php

protected $rules = [
    'email_address' => 'sometimes|required|email|unique:users,email_address, {{$id}}',
];

Model/BaseModel.php

public function validate($data, $id = null) {


      $rules = $this->$rules_string;

     //let's loop through and explode the validation rules
     foreach($rules as $keys => $value) {

        $validations = explode('|', $value);

        foreach($validations as $key=>$value) {

            // Seearch for {{$id}} and replace it with $id
            $validations[$key] = str_replace('{{$id}}', $id, $value);

        }
        //Let's create the pipe seperator 
        $implode = implode("|", $validations);
        $rules[$keys] = $implode;

     }
     ....

  }

I pass the $user_id to the validation in the controller

Controller/UserController.php

public function update($id) { 

   .....

    $user = User::find($user_id);

    if($user->validate($formRequest, $user_id)) {
      //validation succcess 
    } 

    ....


}

2 Comments

I ended up just using watson/validating
Thanks, I'll have a look at it too.
1

While updating any Existing Data Write validator as following:

'email' => ['required','email', Rule::unique('users')->ignore($user->id)]

This will skip/ignore existing user's id's unique value matching for the specific column.

Comments

1

Test below code:

$validator = Validator::make(
            array(
              'E-mail'=>$request['email'],
             ),
            array(
              'E-mail' => 'required|email|unique:users,email,'.$request['id'],
             ));

1 Comment

Try not to use request parameters directly in your validation rules. An attacker can modify the parameters supplied to the controller (even let the id parameter be 0|nullable or worse). laravel.com/docs/5.8/validation#rule-unique
1

Since you will want to ignore the record you are updating when performing an update, you will want to use ignore as mentioned by some others. But I prefer to receive an instance of the User rather then just an ID. This method will also allow you to do the same for other models

Controller

    public function update(UserRequest $request, User $user)
    {
        $user->update($request->all());

        return back();
    }

UserRequest

    public function rules()
    {
        return [
            'email' => [
                'required',
                \Illuminate\Validation\Rule::unique('users')->ignoreModel($this->route('user')),
            ],
        ];
    }

update: use ignoreModel in stead of ignore

Comments

1

Very easy to do it ,

Write it at your controller

$this->validate($request,[
     'email'=>['required',Rule::unique('yourTableName')->ignore($request->id)]
]);
Note : Rule::unique('yourTableName')->ignore($idParameter) , here $idParameter you can receive from get url also you can get it from hidden field.
Most important is don't forget to import Rule at the top.

Comments

1

If a login user want to update the email then auth() helper function will give us the login user id auth()->user()->id

Laravel helpers#method-auth

   Validator::make($data, [
'email' => [
    'required',
    Rule::unique('users')->ignore(auth()->user()->id),
],

]);

if Admin want to change the specific user information from User list then validation will be like this :

 Validator::make($data, [
'email' => [
    'required',
    Rule::unique('users')->ignore($request->user),
],

Laravel validation#rule-unique

$request object contain the current route related model objects. Which gives the model.

Try dd($request)

Comments

1

The PUT/PATCH request doesn't support multipart/form-data and will not populate $_FILES so If you are using POST method on UPDATE then use the route name in switch method.

public function rules()
{
    switch ($this->route()->getName()) {
    case 'users.update':
        $rules = [
        'name'                  => 'required|min:3',
        'gender'                => 'required',
        'email'                 => 'required|email|unique:users,id,:id',
        'password'              => 'required|min:5',
        'password_confirmation' => 'required|min:5|same:password',
        ];
        break;

    default:
        $rules = [
            'name'                  => 'required|min:3',
            'gender'                => 'required',
            'email'                 => 'required|email|unique:users',
            'password'              => 'required|min:5',
            'password_confirmation' => 'required|min:5|same:password',
        ];
        break;
    }

    return $rules;
}

Comments

0

My solution:

$rules = $user->isDirty('email') ? \User::$rules : array_except(\User::$rules, 'email');

Then in validation:

$validator = \Validator::make(\Input::all(), $rules, \User::$messages);

The logic is if the email address in the form is different, we need to validated it, if the email hasn't changed, we don't need to validate, so remove that rule from validation.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.