MassAssignmentException no Laravel

108

Eu sou um novato no Laravel. Eu quero espalhar meu banco de dados. Quando executo o comando seed, obtenho uma exceção

  [Illuminate\Database\Eloquent\MassAssignmentException]
  username



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

O que estou fazendo de errado. O comando que uso é:

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

Minha classe inicial é a seguinte:

class UsersTableSeeder extends Seeder {
    public function run()
    {
            User::truncate();
            User::create([
                'username' => 'PaulSheer',
                'email' => '[email protected]',
                'password' => '45678'
            ]);

            User::create([
                'username' => 'Stevo',
                'email' => '[email protected]',
                'password' => '45678'
            ]);
    }
}
user1801060
fonte

Respostas:

231

Leia esta seção do documento do Laravel: http://laravel.com/docs/eloquent#mass-assignment

O Laravel fornece por padrão uma proteção contra problemas de segurança de atribuição em massa. É por isso que você deve definir manualmente quais campos podem ser "atribuídos em massa":

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

Aviso: tenha cuidado ao permitir a atribuição em massa de campos críticos como passwordou role. Isso pode levar a um problema de segurança porque os usuários podem ser capazes de atualizar os valores dos campos quando você não quiser.

Alexandre Butynski
fonte
7
-1 Embora isso funcione, a solução do Pascalculator é melhor porque desmarca apenas quando a atribuição em massa é necessária e não para o tempo de vida do aplicativo.
emragins
1
Você está certo, no contexto específico da propagação do banco de dados, deveria ser melhor desproteger apenas durante a propagação. Mas, como essa resposta parece se tornar um tópico de referência sobre MassAssignmentExceptione porque acho que minha resposta é uma boa solução genérica, vou mantê-la como está.
Alexandre Butynski,
Alexandre, Estou achando difícil seguir sua lógica. Se você concorda, é melhor mudar sua própria resposta, ainda mais porque está se tornando um tópico de referência. A resposta que você sugeriu realmente funcionará, mas não está de acordo com a convenção do Laravel.
Pascalculator
4
Eu mantenho minha resposta como está porque acho que é um bom padrão geral (eu uso em meus projetos) e porque eu acho que não está mais ou menos em conformidade com a convenção do Laravel do que sua resposta (veja o doc). Mas, como a pluralidade de opiniões é ótima e sua solução pode ser tão boa quanto a minha, votei positivamente e incentivo outros a ler :)
Alexandre Butynski
'senha' => bcrypt ('45678')
Douglas.Sesar
31

Estou usando o Laravel 4.2.

o erro que você está vendo

[Illuminate\Database\Eloquent\MassAssignmentException]
username

na verdade, é porque o banco de dados está protegido de encher em massa, que é o que você está fazendo quando está executando um semeador. No entanto, em minha opinião, não é necessário (e pode ser inseguro) declarar quais campos devem ser preenchidos em seu modelo se você só precisar executar um semeador.

Em sua pasta de propagação, você tem a classe DatabaseSeeder:

class DatabaseSeeder extends Seeder {

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

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

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

Esta classe atua como uma fachada, listando todos os seeders que precisam ser executados. Se você chamar o semeador UsersTableSeeder manualmente por meio do artisan, como fez com o php artisan db:seed --class="UsersTableSeeder"comando, você ignora esta classe DatabaseSeeder.

Nesta classe DatabaseSeeder, o comando Eloquent::unguard();permite atribuição temporária em massa em todas as tabelas, que é exatamente o que você precisa quando está propagando um banco de dados. Este método desprotegido só é executado quando você executa o php aristan db:seedcomando, portanto, é temporário em vez de tornar os campos preenchíveis em seu modelo (conforme declarado nas respostas aceitas e em outras).

Tudo o que você precisa fazer é adicionar o $this->call('UsersTableSeeder');ao método run na classe DatabaseSeeder e executar php aristan db:seedem sua CLI que, por padrão, executará DatabaseSeeder.

Observe também que você está usando um nome de classe plural Usuários, enquanto Laraval usa a forma singular Usuário. Se você decidir mudar sua classe para a forma singular convencional, você pode simplesmente descomentar o //$this->call('UserTableSeeder');que já foi atribuído, mas comentado por padrão na classe DatabaseSeeder.

Pascalculator
fonte
4
Para os paranóicos e os puristas: você também encontrará apreciação no uso \Eloquent::reguard();, para depois que suas atribuições para a missa forem concluídas.
CenterOrbit
10

Para tornar todos os campos preenchíveis , basta declarar em sua classe:

protected $guarded = array();

Isso permitirá que você chame o método de preenchimento sem declarar cada campo.

Tiago Gouvêa
fonte
7

Basta adicionar Eloquent::unguard();no início do método de execução ao fazer uma semente, não há necessidade de criar um $fillablearray em todos os modelos que você tem que distribuir.

Normalmente, isso já está especificado na DatabaseSeederclasse. No entanto, porque você está ligando UsersTableSeederdiretamente para o:

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

Eloquent::unguard(); não está sendo chamado e dá o erro.

bicicleta
fonte
4

Eu usei isso e não tenho problema:

protected $guarded=[];
Parastoo Amini
fonte
1

Eu estava recebendo o MassAssignmentException quando estendi meu modelo assim.

class Upload extends Eloquent {

}

Eu estava tentando inserir uma matriz assim

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

O problema foi resolvido quando criei o modelo de upload como

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

Referência https://github.com/aidkit/aidkit/issues/2#issuecomment-21055670

Amit Garg
fonte
1

Modelo adequado do usuário em seu arquivo de controlador.

<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\User;
Rahul Hirve
fonte
0

se você tiver tabela e campos no banco de dados, você pode simplesmente usar este comando:

php artisan db:seed --class=UsersTableSeeder --database=YOURDATABSE
DolDurma
fonte
0

Esta não é uma boa maneira quando você deseja semear o banco de dados.
Use faker em vez de hard coding e, antes de tudo isso, talvez seja melhor truncar tabelas.

Considere este exemplo:

    // 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);
Amin
fonte
0

Use o preenchível para informar ao laravel quais campos podem ser preenchidos usando uma matriz. Por padrão, o Laravel não permite que os campos do banco de dados sejam atualizados através de um array

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

O oposto de preenchível é guardável .

Sameer Shaikh
fonte
-1

Se você usar o método OOP de inserção, não precisa se preocupar com as propriedades de ação em massa / preenchimento:

$user = new User;
$user->username = 'Stevo';
$user->email = '[email protected]';
$user->password = '45678';
$user->save();
Mark Shust na M.academy
fonte