MassAssignmentException w Laravel


108

Jestem nowicjuszem Laravel. Chcę zasiać moją bazę danych. Kiedy uruchamiam polecenie seed, pojawia się wyjątek

  [Illuminate\Database\Eloquent\MassAssignmentException]
  username



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

Co ja robię źle. Polecenie, którego używam, to:

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

Moja klasa nasion jest następująca:

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

Odpowiedzi:


231

Przeczytaj tę sekcję dokumentu Laravel: http://laravel.com/docs/eloquent#mass-assignment

Laravel domyślnie zapewnia ochronę przed problemami związanymi z bezpieczeństwem przydziału masowego. Dlatego musisz ręcznie zdefiniować, które pola mogą być „przypisane masowo”:

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

Ostrzeżenie: bądź ostrożny, zezwalając na masowe przypisywanie krytycznych pól, takich jak passwordlub role. Może to prowadzić do problemów z bezpieczeństwem, ponieważ użytkownicy mogą aktualizować wartości tych pól, gdy nie chcą.


7
-1 Chociaż to działa, rozwiązanie z Pascalculator jest lepsze, ponieważ wyłącza ochronę tylko wtedy, gdy potrzebne jest przypisanie masy, a nie przez cały okres użytkowania aplikacji.
emragins

1
Masz rację, w konkretnym kontekście inicjowania bazy danych lepiej jest odblokować tylko podczas inicjowania. Ale ponieważ ta odpowiedź wydaje się być tematem odniesienia MassAssignmentExceptioni ponieważ wydaje mi się, że moja odpowiedź jest dobrym rozwiązaniem ogólnym, zachowam ją tak, jak jest.
Alexandre Butynski,

Alexandre, trudno mi postępować zgodnie z twoją logiką. Jeśli się zgodzisz, równie dobrze możesz zmienić swoją odpowiedź, tym bardziej, że staje się to tematem odniesienia. Odpowiedź, którą zasugerowałeś, rzeczywiście zadziała, ale nie jest zgodna z konwencją Laravel.
Pascalculator

4
Zachowuję swoją odpowiedź tak, jak jest, ponieważ uważam, że jest to dobry ogólny wzorzec (używam go w moich projektach) i ponieważ uważam, że nie jest on mniej więcej zgodny z konwencją Laravel niż twoja odpowiedź (patrz dokument). Ale ponieważ mnogość opinii jest świetna, a Twoje rozwiązanie może być równie dobre jak moje, zagłosowałem za nim i zachęcam innych do przeczytania :)
Alexandre Butynski 14.04.15

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

31

Używam Laravel 4.2.

błąd, który widzisz

[Illuminate\Database\Eloquent\MassAssignmentException]
username

w rzeczywistości jest tak, ponieważ baza danych jest chroniona przed masowym wypełnianiem, co robisz podczas wykonywania siewnika. Jednak moim zdaniem nie jest konieczne (i może być niebezpieczne) deklarowanie, które pola powinny być wypełnione w twoim modelu, jeśli potrzebujesz tylko wykonać siewnik.

W swoim folderze początkowym masz klasę DatabaseSeeder:

class DatabaseSeeder extends Seeder {

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

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

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

Ta klasa działa jak fasada, wymieniając wszystkie siewniki, które należy wykonać. Jeśli wywołasz siewnik UsersTableSeeder ręcznie przez rzemieślnika, tak jak w przypadku php artisan db:seed --class="UsersTableSeeder"polecenia, pominiesz tę klasę DatabaseSeeder.

W tej klasie DatabaseSeeder polecenie Eloquent::unguard();umożliwia tymczasowe przypisanie masy do wszystkich tabel, co jest dokładnie tym, czego potrzebujesz podczas wypełniania bazy danych. Ta metoda unguard jest wykonywana tylko po uruchomieniu php aristan db:seedpolecenia, dlatego jest tymczasowa, w przeciwieństwie do umożliwienia wypełniania pól w modelu (jak podano w zaakceptowanych i innych odpowiedziach).

Wszystko, co musisz zrobić, to dodać $this->call('UsersTableSeeder');do metody run w klasie DatabaseSeeder i uruchomić php aristan db:seedw swoim CLI, który domyślnie będzie wykonywał DatabaseSeeder.

Zauważ również, że używasz liczby mnogiej Users, podczas gdy Laraval używa liczby pojedynczej User. Jeśli zdecydujesz się zmienić klasę na tradycyjną liczbę pojedynczą, możesz po prostu odkomentować tę, //$this->call('UserTableSeeder');która została już przypisana, ale domyślnie zakomentowana w klasie DatabaseSeeder.


4
Dla paranoików i purystów: docenisz także używanie \Eloquent::reguard();, ponieważ po ukończeniu przydziałów masowych.
CenterOrbit

10

Aby umożliwić wypełnianie wszystkich pól , po prostu zadeklaruj w swojej klasie:

protected $guarded = array();

Umożliwi to wywołanie metody fill bez deklarowania każdego pola.


7

Po prostu dodaj Eloquent::unguard();na początku metody uruchamiania, gdy robisz ziarno, nie ma potrzeby tworzenia $fillabletablicy we wszystkich modelach, które musisz zasiać.

Zwykle jest to już określone w DatabaseSeederklasie. Jednak ponieważ dzwonisz UsersTableSeederbezpośrednio:

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

Eloquent::unguard(); nie jest wywoływana i podaje błąd.



1

Otrzymałem MassAssignmentException, gdy rozszerzyłem mój model w ten sposób.

class Upload extends Eloquent {

}

Próbowałem wstawić tablicę w ten sposób

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

Problem został rozwiązany, gdy utworzyłem Prześlij model jako

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

Odniesienie https://github.com/aidkit/aidkit/issues/2#issuecomment-21055670


1

Właściwy model użytkownika w pliku kontrolera.

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

0

jeśli masz tabelę i pola w bazie danych, możesz po prostu użyć tego polecenia:

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

0

To nie jest dobry sposób, gdy chcesz wypełnić bazę danych.
Użyj fakera zamiast twardego kodowania, a przed tym wszystkim może lepiej skrócić tabele.

Rozważmy ten przykład:

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

Użyj napełniane powiedzieć laravel które pola mogą być wypełnione przy użyciu tablicy. Domyślnie Laravel nie pozwala na aktualizację pól bazy danych za pośrednictwem tablicy

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

Przeciwieństwem można napełniać jest guardable .


-1

Jeśli używasz metody OOP wstawiania, nie musisz martwić się o właściwości masowe / wypełniane:

$user = new User;
$user->username = 'Stevo';
$user->email = 'steve@rute.co.za';
$user->password = '45678';
$user->save();
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.