laravel / framework

The Laravel Framework.
https://laravel.com
MIT License
32.39k stars 10.98k forks source link

Model->fill() ignores $fillable property in unit tests #9322

Closed rvignacio closed 9 years ago

rvignacio commented 9 years ago

Following #1181, #6816, #8399 and so on... I used @taylorotwell proposed solution to explicitly call the boot method on setUp().

I have a user controller with the following validation rules:

public function store(Request $request)
{
    ...
    $this->validate($request, [
        'name' => 'required',
        'email' => 'email|required|unique:users',
        'password' => 'confirmed|max:32|min:8|required',
        'roles' => 'exists:roles,id|required',
    ]);

    $user = new User();
    $user->fill($request->all());
   ...
}

My User.php model defines the fillable properties as:

protected $fillable = ['name', 'email'];

To pass the confirmed validation, I have to send both password and password_confirmation fields in the POST request.

During development everything works fine, but in unit tests I'm getting a database error. It tries to insert data into a password_confirmation column. It's like it ignores the $fillable array. Is there some other model method I have to call (like the boot() function) before running the tests?

Thanks!

Edit

Reading the Model.php source, I've found that someone is calling Model::unguard() https://github.com/laravel/framework/blob/5.1/src/Illuminate/Database/Eloquent/Model.php#L2180 after the setUp() function and before the test. If I call User::reguard() at the beggining of the test it passes, but (I don't know why), the unguard() and reguard() functions get called multiple times and the test gets really slow.

yasinkocak commented 9 years ago

Try to use $guarded. The $guarded property should contain an array of attributes that you do not want to be mass assignable.

http://laravel.com/docs/master/eloquent#mass-assignment

rvignacio commented 9 years ago

I tried using $guarded but with same results (also $guarded isn't a good idea since it will try to add everything in the POST request unless it is blacklisted there).

The problem is that somewhere there's a call to Model::unguard() but I haven't been able to find when and why.

rvignacio commented 9 years ago

Found the problem: the base seeder in v5.0.x only called Model::unguard() (https://github.com/laravel/laravel/blob/v5.0.22/database/seeds/DatabaseSeeder.php#L15) while v5.1.x was updated and added a call to Model::reguard() (https://github.com/laravel/laravel/blob/v5.1.0/database/seeds/DatabaseSeeder.php#L19) (I was using v5.0.22).