MassAssignmentException trong Laravel


108

Tôi là một người mới Laravel. Tôi muốn gieo vào cơ sở dữ liệu của mình. Khi tôi chạy lệnh hạt giống, tôi nhận được một ngoại lệ

  [Illuminate\Database\Eloquent\MassAssignmentException]
  username



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

Tôi đang làm gì sai. Lệnh tôi sử dụng là:

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

Lớp hạt giống của tôi như sau:

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'
            ]);
    }
}

Câu trả lời:


231

Đọc phần này của tài liệu Laravel: http://laravel.com/docs/eloquent#mass-assignment

Theo mặc định, Laravel cung cấp một biện pháp bảo vệ chống lại các vấn đề bảo mật phân công hàng loạt. Đó là lý do tại sao bạn phải xác định thủ công những trường nào có thể được "gán hàng loạt":

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

Cảnh báo: hãy cẩn thận khi bạn cho phép gán hàng loạt các trường quan trọng như passwordhoặc role. Nó có thể dẫn đến vấn đề bảo mật vì người dùng có thể cập nhật các giá trị trường này khi bạn không muốn.


7
-1 Trong khi điều này hoạt động, giải pháp từ Pascalculator tốt hơn ở chỗ nó chỉ bỏ bảo vệ khi cần gán khối lượng chứ không phải cho thời gian tồn tại của ứng dụng.
emragins

1
Bạn nói đúng, trong bối cảnh cụ thể của việc seeding cơ sở dữ liệu, tốt hơn là chỉ nên hủy chuẩn bị trong quá trình seeding. Nhưng, vì câu trả lời này dường như trở thành một chủ đề tham khảo MassAssignmentExceptionvà vì nó nghĩ rằng câu trả lời của tôi là một giải pháp chung chung tốt, nên tôi sẽ giữ nguyên nó.
Alexandre Butynski

Alexandre, tôi thấy khó theo logic của bạn. Nếu bạn đồng ý, bạn cũng có thể thay đổi câu trả lời của chính mình, thậm chí nhiều hơn thế vì nó đang trở thành một chủ đề tham khảo. Câu trả lời bạn đã đề xuất thực sự sẽ hoạt động, nhưng không tuân thủ quy ước Laravel.
Pascalculator

4
Tôi giữ nguyên câu trả lời của mình vì tôi nghĩ rằng đó là một mẫu chung tốt (tôi sử dụng nó trong các dự án của mình) và vì tôi nghĩ rằng nó không ít nhiều tuân thủ quy ước Laravel hơn câu trả lời của bạn (xem tài liệu). Nhưng, bởi vì đa số ý kiến là rất tốt và bởi vì giải pháp của bạn có thể được tốt như tôi, tôi bỏ phiếu tán nó và tôi khuyến khích người khác đọc nó :)
Alexandre Butynski

'mật khẩu' => bcrypt ( '45678')
Douglas.Sesar

31

Tôi đang sử dụng Laravel 4.2.

lỗi bạn đang thấy

[Illuminate\Database\Eloquent\MassAssignmentException]
username

thực sự là do cơ sở dữ liệu được bảo vệ khỏi việc lấp đầy hàng loạt, đó là những gì bạn đang làm khi thực hiện trình gieo hạt. Tuy nhiên, theo ý kiến ​​của tôi, không cần thiết (và có thể không an toàn) để khai báo trường nào có thể điền vào mô hình của bạn nếu bạn chỉ cần thực thi trình gieo hạt.

Trong thư mục gieo hạt của bạn, bạn có lớp DatabaseSeeder:

class DatabaseSeeder extends Seeder {

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

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

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

Lớp này hoạt động như một mặt tiền, liệt kê tất cả các trình gieo hạt cần được thực thi. Nếu bạn gọi trình gieo hạt UsersTableSeeder theo cách thủ công thông qua thủ công, giống như bạn đã làm với php artisan db:seed --class="UsersTableSeeder"lệnh, bạn sẽ bỏ qua lớp DatabaseSeeder này.

Trong lớp DatabaseSeeder này, lệnh Eloquent::unguard();cho phép gán khối lượng tạm thời trên tất cả các bảng, đây chính xác là những gì bạn cần khi tạo cơ sở dữ liệu. Phương thức không chuẩn này chỉ được thực thi khi bạn chạy php aristan db:seedlệnh, do đó nó chỉ tạm thời thay vì làm cho các trường có thể điền vào mô hình của bạn (như đã nêu trong các câu trả lời được chấp nhận và các câu trả lời khác).

Tất cả những gì bạn cần làm là thêm $this->call('UsersTableSeeder');phương thức chạy trong lớp DatabaseSeeder và chạy php aristan db:seedtrong CLI của bạn, phương thức này theo mặc định sẽ thực thi DatabaseSeeder.

Cũng lưu ý rằng bạn đang sử dụng Tên lớp số nhiều Người dùng, trong khi Laraval sử dụng Người dùng dạng số ít. Nếu bạn quyết định thay đổi lớp của mình thành dạng số ít thông thường, bạn có thể chỉ cần bỏ ghi chú //$this->call('UserTableSeeder');mà đã được gán nhưng được nhận xét theo mặc định trong lớp DatabaseSeeder.


4
Đối với những người hoang tưởng và những người theo chủ nghĩa thuần túy: bạn cũng sẽ thấy được sự đánh giá cao trong việc sử dụng \Eloquent::reguard();, sau khi Bài tập khối lượng của bạn hoàn thành.
CenterOrbit

10

Để làm cho tất cả các trường có thể điền được , chỉ cần khai báo trên lớp của bạn:

protected $guarded = array();

Điều này sẽ cho phép bạn gọi phương thức điền mà không cần khai báo từng trường.


7

Chỉ cần thêm Eloquent::unguard();vào đầu phương thức chạy khi bạn tạo hạt giống, không cần tạo một $fillablemảng trong tất cả các mô hình bạn có hạt giống.

Thông thường, điều này đã được chỉ định trong DatabaseSeederlớp. Tuy nhiên, vì bạn đang gọi UsersTableSeedertrực tiếp:

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

Eloquent::unguard(); không được gọi và báo lỗi.


4

Tôi đã sử dụng cái này và không có vấn đề gì:

protected $guarded=[];

1

Tôi đã nhận được MassAssignmentException khi tôi mở rộng mô hình của mình như thế này.

class Upload extends Eloquent {

}

Tôi đã cố gắng chèn mảng như thế này

Upload::create($array);//$array was data to insert.

Vấn đề đã được giải quyết khi tôi tạo Mô hình tải lên bằng

class Upload extends Eloquent {
    protected $guarded = array();  // Important
}

Tham khảo https://github.com/aidkit/aidkit/issues/2#issuecomment-21055670


1

Người dùng thích hợp mô hình trong tệp bộ điều khiển của bạn.

<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\User;

0

nếu bạn có bảng và các trường trên cơ sở dữ liệu, bạn có thể chỉ cần sử dụng lệnh này:

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

0

Đây không phải là một cách tốt khi bạn muốn seeding cơ sở dữ liệu.
Sử dụng faker thay vì viết mã cứng, và trước hết có lẽ tốt hơn nên cắt bớt các bảng.

Hãy xem xét ví dụ này:

    // 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

Sử dụng các fillable nói laravel mà lĩnh vực có thể được lấp đầy bằng một mảng. Theo mặc định, Laravel không cho phép các trường cơ sở dữ liệu được cập nhật thông qua một mảng

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

Ngược lại với fillable là có thể bảo vệ được .


-1

Nếu bạn sử dụng phương pháp chèn OOP, bạn không cần phải lo lắng về các thuộc tính mass-action / fillable:

$user = new User;
$user->username = 'Stevo';
$user->email = 'steve@rute.co.za';
$user->password = '45678';
$user->save();
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.