Laravel中的MassAssignmentException


108

我是Laravel新手。我想播种我的数据库。当我运行seed命令时,出现异常

  [Illuminate\Database\Eloquent\MassAssignmentException]
  username



db:seed [--class[="..."]] [--database[="..."]]

我究竟做错了什么。我使用的命令是:

php artisan db:seed --class="UsersTableSeeder"

我的种子类如下:

class UsersTableSeeder extends Seeder {
    public function run()
    {
            User::truncate();
            User::create([
                'username' => 'PaulSheer',
                'email' => 'psheer@rute.co.za',
                'password' => '45678'
            ]);

            User::create([
                'username' => 'Stevo',
                'email' => 'steve@rute.co.za',
                'password' => '45678'
            ]);
    }
}

Answers:


231

阅读Laravel文档的这一部分:http ://laravel.com/docs/eloquent#mass-assignment

Laravel默认情况下提供针对批量分配安全问题的保护。这就是为什么您必须手动定义哪些字段可以“大量分配”的原因:

class User extends Model
{
    protected $fillable = ['username', 'email', 'password'];
}

警告:当您允许批量分配关键字段(例如password或)时,请务必小心role。这可能会导致安全问题,因为用户可以在不需要时更新此字段的值。


7
-1虽然可行,但Pascalculator的解决方案更好,因为它仅在需要进行质量分配时才取消保护,而在应用程序的整个生命周期中均不提供保护。
Emragins

1
您是对的,在数据​​库播种的特定上下文中,最好仅在播种期间不加保护。但是,由于此答案似乎已成为参考主题,MassAssignmentException并且因为它认为我的答案是一个很好的通用解决方案,因此我将保持原样。
Alexandre Butynski 2015年

亚历山大,我发现很难遵循你的逻辑。如果您同意,也可以更改自己的答案,甚至更多,因为它正在成为参考主题。您提出的答案确实可以,但是不符合Laravel约定。
Pascalculator 2015年

4
我将答案保持原样是因为我认为这是一个很好的通用模式(我在项目中使用了它),并且因为我认为它不比Laravel约定或多或少地符合Laravel约定(请参阅文档)。但是,由于意见多元化,而且您的解决方案可以像我的一样好,因此我投票赞成,并鼓励其他人阅读:)
Alexandre Butynski 2015年

'password'=> bcrypt('45678')
Douglas.Sesar 2015年

31

我正在使用Laravel 4.2。

您看到的错误

[Illuminate\Database\Eloquent\MassAssignmentException]
username

确实是因为保护数据库免于大量填充,而这是您在执行播种器时所执行的操作。但是,我认为,如果您只需要执行一个播种器,则不必(并且可能是不安全的)声明哪些字段应在模型中可填充。

在种子文件夹中,具有DatabaseSeeder类:

class DatabaseSeeder extends Seeder {

    /**
    * Run the database seeds.
    *
    * @return void
    */

    public function run()
    {
        Eloquent::unguard();

        //$this->call('UserTableSeeder');
    }
}

此类用作外观,列出了需要执行的所有播种机。如果像通过php artisan db:seed --class="UsersTableSeeder"命令那样通过工匠手动调用UsersTableSeeder播种器,则会绕过此DatabaseSeeder类。

在此DatabaseSeeder类中,该命令Eloquent::unguard();允许在所有表上进行临时批量分配,这正是在为数据库添加种子时所需要的。此unguard方法仅在您运行php aristan db:seed命令时执行,因此它是临时的,与使字段可填充到模型中相反(如已接受的答案和其他答案所述)。

您需要做的就是将添加$this->call('UsersTableSeeder');到DatabaseSeeder类的run方法中,并php aristan db:seed在您的CLI中运行,默认情况下,它将执行DatabaseSeeder。

还要注意,您使用的是复数的类名User,而Laraval使用的是单数形式的User。如果决定将类更改为常规的单数形式,则只需取消注释//$this->call('UserTableSeeder');已经分配但默认情况下已在DatabaseSeeder类中将其注释掉的注释。


4
对于偏执狂和纯粹主义者:\Eloquent::reguard();在完成“大规模分配”后,您还会发现使用的赞赏。
CenterOrbit


7

Eloquent::unguard();做种子时,只需在run方法的顶部添加,无需$fillable在所有必须种子的模型中创建数组。

通常,这已在DatabaseSeeder类中指定。但是,因为您要UsersTableSeeder直接致电:

php artisan db:seed --class="UsersTableSeeder"

Eloquent::unguard(); 没有被调用并给出错误。





0

如果数据库中有表和字段,则可以简单地使用以下命令:

php artisan db:seed --class=UsersTableSeeder --database=YOURDATABSE

0

要播种数据库时,这不是一个好方法。
使用伪造者而不是硬编码,并且在此之前最好截断表。

考虑这个例子:

    // Truncate table.  
    DB::table('users')->truncate();

    // Create an instance of faker.
    $faker = Faker::create();

    // define an array for fake data.
    $users = [];

    // Make an array of 500 users with faker.
    foreach (range(1, 500) as $index)
    {
        $users[] = [
            'group_id' => rand(1, 3),
            'name' => $faker->name,
            'company' => $faker->company,
            'email' => $faker->email,
            'phone' => $faker->phoneNumber,
            'address' => "{$faker->streetName} {$faker->postCode} {$faker->city}",
            'about' => $faker->sentence($nbWords = 20, $variableNbWords = true),
            'created_at' => new DateTime,
            'updated_at' => new DateTime,
        ];
    }

    // Insert into database.
    DB::table('users')->insert($users);

0

使用可填写告诉laravel使用数组哪些字段即可充满。默认情况下,Laravel不允许通过数组更新数据库字段

Protected $fillable=array('Fields you want to fill using array');

可填充的相反是可以警惕的


-1

如果使用OOP插入方法,则无需担心质量作用/填充属性:

$user = new User;
$user->username = 'Stevo';
$user->email = 'steve@rute.co.za';
$user->password = '45678';
$user->save();
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.