Axel Jose Mosquito
Axel Jose Mosquito
Laravel
Comparte:

No guarda el mensaje en base de datos.

62. Eloquent: Guardar relaciones
HasOne y HasMany - minuto 6:00
Tu guardas el nombre, email y msj de un usuario ya autenticado.
Yo tengo el MessagesController igual que lo haces en ese minuto y la vista create.blade de messages tambien esta igual, pero al momento de autenticarme como moderador, e intentar enviar un msj me muestra el error...
Tengo todo igual, busque en las respuestas de la pagina de udemy y ninguna me funciono, quisiera saber si pudieses ayudarme, que no logro pasar de esa parte.
Gracias.
Jorge Davila
Jorge Davila (838 xp)
Podrias mostrar el error que te arroja?
Axel Jose Mosquito
Axel Jose Mosquito (52 xp)
SQLSTATE[HY000]: General error: 1364 Field 'nombre' doesn't have a default value (SQL: insert into `messages` (`mensaje`, `updated_at`, `created_at`) values (prueba de moderador, 2019-08-22 08:19:49, 2019-08-22 08:19:49))
Previous exceptions
  •  SQLSTATE[HY000]: General error: 1364 Field 'nombre' doesn't have a default value (HY000)


    Intente enviar un msj con moderador.
Jorge Davila
Jorge Davila (838 xp)
De  acuerdo, primero que nada ese error se presenta por que le intentas pasar un valor nulo a un campo que no puede tener un valor nulo. Si puedes mostrarme tus modelos y donde estas guardando para ver si podemos resolver ese error.

Un ejemplo de como detonar este error seria teniendo una tabla algo así:

Schema::create('posts',function(Blueprint $table)
{
    $table->bigIncrements('id');
    $table->longText('message');
    $table->string('title');
    $table->timestamps();
}
Y en nuestro controlador tenemos lo siguiente:

public function store()
{
   Post::create([
     'message'=>$request->message,
     'title'=>$request->title
   ]);
}

Aquí tendríamos 3 posibilidades por las que podría arrojar error:

1.- El campo  "title" en nuestro modelo no esta definido en la propiedad $fillable ,por lo que eloquent jamás va a intentar guardar ese campo.

2.-$request->title  devuelve un nulo;

3-En tu formulario el campo "title" no tiene la propiedad name="title"(es básicamente lo mismo que el error 2).

Axel Jose Mosquito
Axel Jose Mosquito (52 xp)
Este es mi modelo Message:

class Message extends Model
{
    protected $fillable = [
    'nombre',
    'email',
    'mensaje'
    ];

Este es mi controlador de MessagesController:

public function store(Request $request)
    {
        $message = Message::create($request->all());

        // if (auth()->check())
        // {
        //     auth()->user()->messages()->save($message);
        // }

        $message->user_id = auth()->id();
        $message->save;

y de ninguna de esas dos formas, inserta el nombre, aclaro que el modelo y el controlador, estan iguales que como lo escribe en el video Jorge.
Jorge Davila
Jorge Davila (838 xp)
Que le estas pasando en el request? Ejecuta lo siguiente al inicio del metodo "store":

 dd($request->all());

Axel Jose Mosquito
Axel Jose Mosquito (52 xp)
array:2 [▼
  "_token" => "3F7dRUhrIu3nNyUrrTt3phMJjyctT9vIuiXuqoDu"
  "mensaje" => "ssss"
]

al parecer no toma ni el nombre ni el mail del usuario autenticado ):

Jorge Davila
Jorge Davila (838 xp)
Ahi esta tu problema. Revisa en tu formulario que tengas tus input o selects de la siguiente manera:

<input name='nombre'>
Si no tiene la propiedad name,no encontraras dicho campo en tu request.
Axel Jose Mosquito
Axel Jose Mosquito (52 xp)
<form method="POST" action="{{route('mensajes.store')}}">
 {!! csrf_field() !!}

 @if(auth()->guest())

          <p><label for="nombre">
           Nombre
          <input class="form-control" type="text" name="nombre" value="{{ old ('nombre')}}">
          {!! $errors->first('nombre','<span class=error>:message</span>') !!}
  </label></p>

         <p><label for="email">
          Email
         <input class="form-control" type="text" name="email" value="{{ old ('email')}}">
          {!! $errors->first('email','<span class=error>:message</span>') !!}
 </label></p>



pues si lo tengo en los dos, por eso es que no encuentro el porque no guarda.
Jorge Davila
Jorge Davila (838 xp)
Intenta descargar postman o si ya lo tienes utilízalo para enviar un request por medio del mismo y simplemente has un dd($request) a ver si así si recibe los parametros. Otra cosa,deberías usar un form request para validar que el nombre y el email sean requeridos,y a su vez agregar la propiedad "required" a tus input para evitar que se pueda enviar el formulario si están vacíos dichos campos.

De igual manera puedes pasarme tu proyecto por wetransfer para revisarlo y ayudarte a encontrar el error,aunque lo mejor seria que tu lo encontraras para que  sepas bien por que se dio :p
Axel Jose Mosquito
Axel Jose Mosquito (52 xp)
Ya tengo un CreateMessageRequest.php que tiene nombre,email y mensaje.
en el video lo muestras asi, luego en el formulario de crear, haces un if para quitar los campos de nombre y mail para un usuario validado y cuando tu en el video envias el msj si te funciona y lo hago igual y a mi no xd jajajaja
que triste llevo varios dias cambiadole, agragandole y no funciona, a que correo te podria enviar el proyecto, ya necesito seguir no he pasado de esa parte.
Jorge Davila
Jorge Davila (838 xp)
Ah vale. primero que nada cabe aclarar que no soy el instructor, simplemente tenemos un nombre parecido.  Para rápido utiliza este servicio  https://wetransfer.com/ y selecciona el método por link para que agregues aquí el link así los demás miembros de la comunidad pueden ayudar a responder.

Axel Jose Mosquito
Axel Jose Mosquito (52 xp)
oh pense que eras el instructor, pero de igual manera muchas gracias por haberte tomado el tiempo, de verdad te lo agradezco mucho.

este es el link de wetransfer: https://we.tl/t-PWmwAg4qaZ

Gracias de nuevo.
Jorge Davila
Jorge Davila (838 xp)
Que tal,estube revisando tu codigo y parece estar funcionando bien : https://prnt.sc/owa7un

Intenta correr lo siguiente en tu consola:

php artisan cache:clear
y tambien

composer dump-autoload -o
Por cierto,revisa tu migracion de  create_assigned_roles ,tienes un error en el nombre de la tabla.

Te recomiendo agregar esta validacion a tu metodo store:

$this->validate($request,[    'mensaje'=>'required',
    'email'=>'required|email',
    'nombre'=>'required'
]);
Y tambien cambia la sintaxis de tu vista messages.create a la siguiente(en los errores):


@error('email')
<span class="error">{{$message}}</span>
@enderror
Tambien puedes usar esto,que si bien hace lo mismo ,es mas "expresivo"
@if($errors->has('email'))

   <span class="error">{{$errors->first('email'}}</span>

@endif
Ambas hacen basicamente lo mismo,simplemente es cuestion de elegir cual te gusta mas. 

Jorge Davila
Jorge Davila (838 xp)
Vale ya encontre tu error.Te  hago una lista a continuacion de los cambios a hacer:

1.- Modelo  Message

cambia esto

 public function messages()
{
    return $this->hasMany(Messages::class);
}
por esto


 public function messages()
{
    return $this->hasMany(Message::class);
}
Estas pasandole un modelo que no existe,por lo que al intentar guardar esto fallara.

2.- Controllador MessagesController

debe quedar asi


public function store(Request $request)
{

        $this->validate($request, [
            'mensaje' => 'required|string',
            'email' => 'sometimes|email',
            'nombre' => 'sometimes|string'
        ]);

        $user_data=[
          'mensaje'=>$request->mensaje,
          'nombre'=>$request->has('nombre')?$request->nombre:auth()->user()->id,
          'email'=>$request->has('email')?$request->email:auth()->user()->email
        ];
        $message = Message::create($user_data);

         if (auth()->check())
         {
             auth()->user()->messages()->save($message);
         }

    return redirect()->route('mensajes.create')->with('info','Hemos recibido su mensaje.');
}
Estoy usando una ternaria para  si el request no tiene el nombre (si estas autenticado no llenas el campo nombre ni email) lo extraiga del helper auth(), eso lo puedes ver dentro del array $user_data.

Tambien puedes hacerlo alterando la vista messages.create de la siguiente manera:


@guest
<p><label for="nombre">
   Nombre
   <input class="form-control" type="text" name="nombre" value="{{ old ('nombre')}}">
                 @error('nombre')
                 <span class=error>{{$message}}</span>
                 @enderror
</label></p>
<p><label for="email">
   Email
   <input class="form-control" type="text" name="email" value="{{ old ('email')}}">
                 @error('email')
                 <span class=error>{{$message}}</span>
                 @enderror
</label></p>
      @else
         <input class="form-control hidden" type="text" name="nombre" value="{{auth()->user()->id}}">
         <input class="form-control hidden" type="text" name="email" value="{{auth()->user()->email}}">

     @endif
Aunque esto no es recomendable,por no decir que debe evitarse a toda costa,ya que desde la consola se podria acceder a esa informacion,y en la mayoria de los casos no es algo que quieras que se pueda hacer,por lo cual recomiendo que no realizes esta modificacion en dicha vista.

Ahora permite explicarte bien que esta pasando.

En tu vista messages.create tienes lo siguiente :


@guest/@if(auth()->guest()) (ambas representan lo mismo)<p><label for="nombre">
   Nombre
   <input class="form-control" type="text" name="nombre" value="{{ old ('nombre')}}">
                 @error('nombre')
                 <span class=error>{{$message}}</span>
                 @enderror
</label></p>
<p><label for="email">
   Email
   <input class="form-control" type="text" name="email" value="{{ old ('email')}}">
                 @error('email')
                 <span class=error>{{$message}}</span>
                 @enderror
</label></p>

@endif
De esta manera le estas indicando  a php que los campos nombre y correo electronico solo seran visibles si el usuario esta como invitado, es decir, si el usuario tiene sesion iniciada no tienes estos valores, pero de donde sacarlos entonces?? Y como validar dichos campos??. 
Aqui es donde entra la validacion que acabo de agregar(puedes usar un form request si gustas)


$this->validate($request, [
    'mensaje' => 'required|string',
    'email' => 'sometimes|email',
    'nombre' => 'sometimes|string'
]);
Esto esta validando que el campo mensaje siempre sea enviado.Ademas de esto esta validando que si el email esta siendo enviado  sea de tipo email. En el caso del nombre valida que sea de tipo string si esta enviando. En resumen con esa regla de validacion (sometimes) le indicamos a nuestro controlador que  esos campos a veces van a existir y a veces no.

Una vez hecho esto tenemos que "reemplazar" el valor que le vamos a pasar a  nuestra funcion create si el usuario esta autenticado:

Esto lo hacemos de la manera mas simple,creando un arreglo y pasando lo siguiente:
 

$user_data=[
  'mensaje'=>$request->mensaje,
  'nombre'=>$request->has('nombre')?$request->nombre:auth()->user()->id,
  'email'=>$request->has('email')?$request->email:auth()->user()->email
];
Esto en el indice nombre e email verifica que dichos campos hayan sido enviados por nuestro formulario,caso contrario los reemplaza por los datos del usuario autenticado.

Ahora simplemente queda reemplazar lo que se le esta pasando a la funcion create de la siguiente manera:


$message = Message::create($user_data);
 Y listo,ya es funcional.Lamento la tardanza pero no note que estabas intentando hacerlo con un usuario autenticado hasta que fue demasiado tarde XDD.



1
Axel Jose Mosquito
Axel Jose Mosquito (52 xp)
wow!

En el video no se hace todo eso, y pues con TODA LA RAZON no funcionaba mi proyecto ):

(pero todo lo que hiciste es para una version de laravel mas reciente se supone entonces)

Y si, era con un usuario autenticado.

No se como agradecerte eso, de verdad <3 
Dios te bendiga jajajaja lo intentare de una vez.
Jorge Davila
Jorge Davila (838 xp)
No es necesario agradecer, y no te preocupes ,cosas como estas con parte del proceso de aprendizaje. Es mas fácil dar con los errores cuando lo miras desde fuera. Respecto a tu pregunta, si hay cosas que son de versiones mas avanzadas de Laravel y otras son de PHP. Realmente eso te podría funcionar en cualquier versión de laravel revisando la sintaxis de lo que hice en dicha versión. Si mal no recuerdo la versión que esta manejando el instructor es 5.4 y yo use sintaxis del 5.7 en ciertos casos. Otras cosas como los operadores ternarios son cosas que tiene muchos lenguajes de programación, Un operador ternario es básicamente un "shorthand" para un if/else ,algo así:

if($item1>=$item2)
{
  return $item1;
}
else
{
  return $item2;
}


Toda esa sintaxis la puedes  "acortar" usando un operador ternario:

return $item1>=$item2?$item1:$item2;
Donde lo que esta después del signo  "?" es lo que va a hacer si la condición se cumple, y lo que esta después de ":" será lo que va a hacer si no.
Si mal no recuerdo el instructor resolvió ese problema de una manera similar, tendría que revisar el video para confirmar.


SI quieres acortar la sintaxis del controlador puedes también hacer lo siguiente:  

publica función store(Request $request)
{
    if(auth()->check())
   {
        $request->add(['nombre'=>auth()->user()->id]);
        $request->add(['email'=>auth()->user->email]);
   }
}

Solo asegúrate de hacer estas asignaciones antes de proceder a validar tu request o retornara un error ya que dichos campos no existen en el request si estas autenticado.
1
Eduard Ramos
Eduard Ramos (442 xp)
Esto fue como una clase personalizada  :)
1
Jorge Davila
Jorge Davila (838 xp)
Se hace lo que se puede :)