I'm currently learning Laravel 5.8 and creating instagram clone app and I've been having an issue with updating my profile details. Whenever I hit "Update profile", it gives off an error - "Call to a member function update() on null". The issue seems to be in public function update(). I've looked up other threads and can't seem to fix this issue, so any help would be greatly appreciated!
Here's my code:
View:
#section('content')
<div class="container">
<form action="/profile/{{ $user->id }}" enctype="multipart/form-data" method="post" >
#csrf
#method('PATCH')
<div class="row">
<div class="col-8 offset-2">
<div class="row pb-3">
<h1>Edit profile</h1>
</div>
<div class="form-group row">
<label for="title" class="col-form-label"><strong>Title</strong></label>
<input id="title" type="text" class="form-control #error('title') is-invalid #enderror" name="title" value="{{ old('title') ?? $user->profile['title'] }}" required autocomplete="title" autofocus>
#error('title')
<span class="invalid-feedback" role="alert">
<strong>{{ $title }}</strong>
</span>
#enderror
</div>
<div class="form-group row">
<label for="description" class="col-form-label"><strong>Description</strong></label>
<input id="description" type="text" class="form-control #error('description') is-invalid #enderror" name="description" value="{{ old('description') ?? $user->profile['description']}}" required autocomplete="description" autofocus>
#error('description')
<span class="invalid-feedback" role="alert">
<strong>{{ $description }}</strong>
</span>
#enderror
</div>
<div class="row">
<label for="photo" class="col-form-label">Select Profile Picture</label>
<input type="file" class="form-control-file" id="photo" name="photo">
#error('photo')
<strong>{{ $message }}</strong>
#enderror
</div>
<div class="row pt-3">
<button class="btn btn-primary">
Update Profile
</button>
</div>
</div>
</div>
</form>
</div>
#endsection
Route:
Auth::routes();
Route::get('/profile/{user}', 'ProfileController#index')->name('profile.show');
Route::get('/profile/{user}/edit', 'ProfileController#edit')->name('profile.edit');
Route::patch('/profile/{user}', 'ProfileController#update')->name('profile.update');```
Controller:
<?php
namespace App\Http\Controllers;
use App\User;
use App\Profile;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class ProfileController extends Controller
{
public function index(User $user){
return view('profile.index', [
'user' => $user,
]);
}
public function edit(User $user){
return view('profile.edit', [
'user' => $user,
]);
}
public function update(User $user){
$data = request()->validate([
'title' => 'required',
'description' => 'required',
'photo' => '',
]);
auth()->user()->profile->update($data);
return redirect("/storage/ {$user->id}");
}
}
Thank you in advance!
try passing the user you are editing as you have passed them in the routes., The error means you want to update a user but you haven't specified which user you are updating.
try doing something like this:
public function validateUser(){
return request()->validate([
'title' => 'required',
'description' => 'required',
'photo' => '',
]);
}
then in the update function do something like this:
public function update($user_id){
return User::where('id',$user_id)->update($this->validateUser());
}
public function update(User $user){
$data = request()->validate([
'title' => 'required',
'description' => 'required',
'photo' => '',
]);
$user->profile()->update($data);
return redirect("/storage/".$user->id);
}
Update Or Insert
Sometimes you may want to update an existing record in the database or create it if no matching record exists. In this scenario, the updateOrInsert method may be used.
User::where('id',$id)->updateOrInsert($data);
Related
I am working on a Laravel application that requires user registration and login.
Alter registration, a user should have the possibility to add more info to his/her profile.
For this purpose, I did the following:
In routes/web.php I have the necessary routes, including update:
Auth::routes();
Route::get('/dashboard', [App\Http\Controllers\Dashboard\DashboardController::class, 'index'])->name('dashboard');
Route::get('/dashboard/profile', [App\Http\Controllers\Dashboard\UserProfileController::class, 'index'])->name('profile');
Route::post('/dashboard/profile/update', [App\Http\Controllers\Dashboard\UserProfileController::class, 'update'])->name('update');
In the newly created Controllers\Dashboard\UserProfileController.php I have:
namespace App\Http\Controllers\Dashboard;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Auth;
use App\Models\UserProfile;
class UserProfileController extends Controller
{
public function index(UserProfile $user)
{
return view('dashboard.userprofile',
array('current_user' => Auth::user())
);
}
public function update(Request $request, $id)
{
$id = Auth::user()->id;
$request->validate([
'first_name' => ['required', 'string', 'max:255'],
'last_name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
]);
$current_user = User::find($id);
$current_user->first_name = $request->get('first_name');
$current_user->last_name = $request->get('last_name');
$current_user->email = $request->get('email');
$current_user->bio = $request->get('bio');
$current_user->avatar = $request->get('avatar');
$current_user->update();
return redirect('/dashboard/profile')->with('success', 'User data updated successfully');
}
}
In the view file that holds the form (resources\views\dashboard\userprofile.blade.php) I have:
<form action="{{ route('dashboard/profile/update') }}" enctype='multipart/form-data' method="post" novalidate>
{{csrf_field()}}
<div class="form-group">
<input type="text" id="first_name" name="first_name" placeholder="First name" class="form-control" value="{{$current_user->first_name}}">
#if ($errors->has('first_name'))
<span class="errormsg text-danger">{{ $errors->first('first_name') }}</span>
#endif
</div>
<div class="form-group">
<input type="text" id="last_name" name="last_name" placeholder="Last name" class="form-control" value="{{$current_user->last_name}}">
#if ($errors->has('first_name'))
<span class="errormsg text-danger">{{ $errors->first('last_name') }}</span>
#endif
</div>
<div class="form-group">
<input type="text" id="email" name="email" placeholder="E-mail address" class="form-control" value="{{$current_user->email}}">
#if ($errors->has('email'))
<span class="errormsg text-danger">{{ $errors->first('email') }}</span>
#endif
</div>
<div class="form-group">
<textarea name="bio" id="bio" class="form-control" cols="30" rows="6">{{$current_user->bio}}</textarea>
#if ($errors->has('bio'))
<span class="errormsg text-danger">{{ $errors->first('bio') }}</span>
#endif
</div>
<label for="avatar" class="text-muted">Upload avatar</label>
<div class="form-group d-flex">
<div class="w-75 pr-1">
<input type='file' name='avatar' id="avatar" class="form-control border-0 py-0 pl-0 file-upload-btn">
#if ($errors->has('file'))
<span class="errormsg text-danger">{{ $errors->first('avatar') }}</span>
#endif
</div>
<div class="w-25">
<img class="rounded-circle img-thumbnail avatar-preview" src="{{asset('images/avatars/default.png')}}" alt="{{$current_user->first_name}} {{$current_user->first_name}}">
</div>
</div>
<div class="form-group mb-0">
<input type="submit" name="submit" value='Save' class='btn btn-block btn-primary'>
</div>
</form>
The problem:
For a reason I was unable to figure out, whenever I am on the dashboard/profile route (in the browser), Laravel throws this error:
Route [dashboard/profile/update] not defined. (View: Path\to\views\dashboard\userprofile.blade.php)
What am I missing?
The route() function accepts a name, not a URL: https://laravel.com/docs/8.x/routing#generating-urls-to-named-routes
So you should have used route('update'). Though seeing your code, you might not realize the ->name() method should accept a unique route name. So you should make sure you don't have any other route named 'update'.
Some people do this: ->name('dashboard.profile.update'). You can see if you like this convention.
I applied an easy fix, thanks to the info received from the community:
I replaced <form action="{{ route('dashboard/profile/update') }}" enctype='multipart/form-data' method="post" novalidate> with:
<form action="{{ route('update') }}" enctype='multipart/form-data' method="post" novalidate>
I am trying to allow users to create and add category tags to a post when creating that post in the form.
I would further want those tags to appear in the profile view and function as filter buttons to show posts according to the tag names they possess.
However, in my attempt to achieve this overall result, I am stuck because everytime I submit a post with tags, the tags array keeps showing up empty in the view.
My post table is:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreatePostsTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id');
$table->string('caption');
$table->string('url');
$table->string('image');
$table->text('tags');
$table->timestamps();
$table->index('user_id');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('posts');
}
}
My Post Model is:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Carbon\Carbon;
class Post extends Model
{
use \Conner\Tagging\Taggable;
use HasFactory;
protected $fillable = ['caption','url','image', 'tags'];
public function user()
{
return $this->belongsTo(User::class);
}
protected $dates = [
'created_at',
'updated_at',
];
}
My create and store methods in PostsController are:
public function create()
{
return view('posts.create');
}
public function store(Request $request)
{
$data = request()->validate([
'caption' => 'required',
'url' => 'required',
'image' => ['required', 'image'],
'tags' => 'required',
]);
$tags = explode(", ", $request->tags);
$imagePath = request('image')->store('uploads', 'public');
auth()->user()->posts()->create([
'caption' => $data['caption'],
'url' => $data['url'],
'image' => $imagePath,
'tags' => $data['tags'],
]);
return redirect('/users/' . auth()->user()->id);
}
My form to create post is:
<form action="/posts" enctype="multipart/form-data" method="post">
#csrf
<div class="form-group">
<label for="caption" class="create_caption_label">Post Caption</label>
<div class="create_caption_div">
<input id="caption"
type="text"
class="form-control #error('caption') is-invalid #enderror"
name="caption"
value="{{ old('caption') ?? '' }}"
autocomplete="caption" autofocus>
#error('caption')
<div class="invalid-feedback-div">
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
</div>
#enderror
</div>
</div>
<div class="form-group">
<label for="tags" class="create_tags_label">Tags</label>
<div class="create_tags_div">
<input id="tags"
type="text"
data-role="tagsinput"
class="form-control #error('tags') is-invalid #enderror"
name="tags"
value="{{ old('tags') ?? '' }}"
autocomplete="tags" autofocus>
#error('tags')
<div class="invalid-feedback-div">
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
</div>
#enderror
</div>
</div>
<div class="form-group">
<label for="url" class="edit_title_label">URL</label>
<div class="edit_url_div">
<input id="url"
type="text"
class="form-control #error('url') is-invalid #enderror"
name="url"
value="{{ '' }}"
autocomplete="url" autofocus>
#error('url')
<div class="invalid-feedback-div">
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
</div>
#enderror
</div>
</div>
<div class="create_post_image_div">
<label for="image" class="create_image_label">Post Image</label>
<input type="file" class="form-control-file" id="image" name="image">
#error('image')
<div class="invalid-feedback-div">
<strong>{{ $message }}</strong>
</div>
#enderror
<div class="create_post_btn_div">
<button class="create_post_btn">Save Post</button>
</div>
</div>
</form>
Finally, my view is: (This is where the tags array shows up empty after submitting a post)
#foreach( $user->posts as $post )
<div class="carousel_posts_container">
<div class="post_date_and_edit_div">
<div class="posted_date_div">
<p class="posted_date">posted: {{ $post->created_at->diffForHumans() }}</p>
</div>
<div class="post_edit_div">
<form action="/posts/{{$post->id}}/edit">
<input class="post_edit_btn" type="submit" value="• • •">
</form>
</div>
</div>
<div class="post_counter_div">
<p class="post_counter">1 like</p>
</div>
<div class="post_counter_div">
<p class="post_counter">1 comment</p>
</div>
<div class="carousel_post_img_div">
<img src="/storage/{{ $post->image }}" class="carousel_img_placeholder">
</div>
<div class="like_comment_view_container">
<div class="view_btn_div">
<form action="{{$post->url}}">
<input class="like_comment_view_btns" type="submit" value="( View Post )">
</form>
</div>
<div class="like_btn_div">
<button type="button" class="like_comment_view_btns">( Like )</button>
</div>
<div class="comment_btn_div">
<button type="button" class="like_comment_view_btns">( Comment )</button>
</div>
</div>
<div class="carousel_caption_container">
<div class="carousel_caption_div">
<p class="carousel_caption_username">{{$user->username}} - {{$post->caption}}</p>
<p class="carousel_caption">{{$post->caption}}</p>
</div>
<div class="post-tags mb-4">
<strong>Tags : </strong>
#foreach($post->tags as $tag)
<span class="badge badge-info">{{$tag->name}}</span>
#endforeach
</div>
</div>
</div>
#endforeach
How can I resolve this issue?
And furthermore, how can I allow the tags to function as filter buttons to show posts according to the tag names they possess?
You can save tags as json array in db. Then cast to array in model, so it will be automatically array when you will retrieve. When saving you will pass tags as array then it will automatically convert to json string.
protected $casts = [
'tags' => 'array',
];
Whenever I try to only save profile changes for the profile description and url in the edit form, I get an error because I didn't choose an image file also.
I would like to be able to update a profile with current image when an image file is not chosen in the edit form.
The error I keep getting is:
Call to a member function store() on null
...that error is referring to this line in the update method of my UserController:
$imagePath = request('image')->store('uploads', 'public');
This is the entire update method in my UserController:
public function update(User $user, Request $request)
{
$data = request()->validate([
'description' => 'nullable',
'url' => 'nullable',
'image' => 'nullable',
]);
$imagePath = request('image')->store('uploads', 'public');
auth()->user()->profile()->update([
'description' => $data['description'],
'url' => $data['url'],
'image' => $imagePath,
]);
return redirect('/users/' . auth()->user()->id);
}
Finally, this is the form in my edit-profile.blade.php file:
#section('content')
<body class="home_body">
<div class="home_container_div">
<div class="home_container">
<div class="home_box_div">
<form action="{{('/users/' . auth()->user()->id)}}" enctype="multipart/form-data" method="post">
#csrf
#method('PATCH')
<div class="form-group">
<label for="description" class="edit_description_label">Description</label>
<div class="edit_description_div">
<input id="description"
type="text"
class="form-control #error('description') is-invalid #enderror"
name="description"
value="{{ old('description' ) ?? auth()->user()->profile->description }}"
autocomplete="description" autofocus>
#error('description')
<div class="invalid-feedback-div">
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
</div>
#enderror
</div>
</div>
<div class="form-group">
<label for="url" class="edit_title_label">URL</label>
<div class="edit_url_div">
<input id="url"
type="text"
class="form-control #error('url') is-invalid #enderror"
name="url"
value="{{ old('url' ) ?? auth()->user()->profile->url }}"
autocomplete="url" autofocus>
#error('url')
<div class="invalid-feedback-div">
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
</div>
#enderror
</div>
</div>
<div class="create_post_image_div">
<label for="image" class="create_image_label">Profile Image</label>
<input type="file" class="form-control-file" id="image" name="image">
#error('image')
<div class="invalid-feedback-div">
<strong>{{ $message }}</strong>
</div>
#enderror
<div class="create_post_btn_div">
<button class="create_post_btn">Save Profile</button>
</div>
</div>
</form>
</div>
</div>
</div>
</body>
#endsection
How can I resolve this issue?
You can skip the image upload part if the user has not selected any image file, like this:
public function update(User $user, Request $request)
{
$data = request()->validate([
'description' => 'required',
'url' => 'required',
'image' => 'nullable',
]);
$updateData = [
'description' => $data['description'],
'url' => $data['url'],
];
if (request('image')) {
$imagePath = request('image')->store('uploads', 'public');
$updateData['image'] = $imagePath;
}
auth()->user()->profile()->update($updateData);
return redirect('/users/' . auth()->user()->id);
}
I am working on a pet registration platform, but when I click on the submit button to save the info to my database, I seem to get this error:
SQLSTATE[23000]: Integrity constraint violation: 19 NOT NULL constraint failed: pets.user_id (SQL: insert into "pets" ("nickname", "species", "date_of_birth", "user_id", "updated_at", "created_at") values (Tom, Male, 2009-07-30, ?, 2020-12-13 09:59:07, 2020-12-13 09:59:07))
This is the Pets Controller:
<?php
namespace App\Http\Controllers;
use App\Models\Pet;
use App\Models\User;
class PetsController extends Controller
{
public function create()
{
return view('create');
}
public function store(User $user)
{
Pet::create([
'nickname' => request('nickname'),
'species' => request('species'),
'date_of_birth' => request('date_of_birth'),
'color' => request('color'),
'description' => request('description'),
'user_id' => $user->id
]);
return redirect('/');
}
}
This is the Model for User:
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name',
'email',
'username',
'phone',
'password',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
public function pets()
{
return $this->hasMany(Pet::class);
}
This is the model for Pets:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Pet extends Model
{
protected $fillable = ['nickname','species','date_of_birth','gender','user_id'];
public function users()
{
return $this->belongsTo(User::class);
}
}
This is the form view:
#extends('layouts.app')
#section('content')
<div class="container py-5">
<form action="/create" enctype="multipart/form-data" method="post">
#csrf
<div class="row">
<div class="col-10">
<div class="row justify-content-center">
<h1><strong>Add A Pet</strong></h1>
</div>
<div class="form-group row py-4">
<label for="nickname" class="col-md-4 col-form-label text-md-right">Nickname</label>
<div class="col-md-6">
<input id="nickname" type="text" class="form-control #error('nickname') is-invalid #enderror"
name="nickname"
value="{{ old('nickname') }}"
placeholder="Enter the name of the animal"
required autocomplete="nickname" autofocus>
#error('nickname')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
#enderror
</div>
</div>
<div class="form-group row">
<label for="species" class="col-md-4 col-form-label text-md-right">Species</label>
<div class="col-md-6">
<select id="species" class="form-control #error('species') is-invalid #enderror"
name="species"
value="{{ old('species') }}"
required autocomplete="species" autofocus>
<option disabled selected>Select species</option>
<option>Dog</option>
<option>Domestic cat</option>
<option>other</option>
</select>
#error('species')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
#enderror
</div>
</div>
<div class="form-group row py-4">
<label for="date_of_birth" class="col-md-4 col-form-label text-md-right">Date of birth</label>
<div class="col-md-6">
<input id="date_of_birth" type="date" class="form-control #error('date_of_birth') is-invalid #enderror"
name="date_of_birth"
value="{{ old('date_of_birth') }}"
placeholder="yyyy-mm-dd"
required autocomplete="date_of_birth" autofocus>
#error('date_of_birth')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
#enderror
</div>
</div>
<div class="form-group row justify-content-center" style="padding-left:108px">
<div class="form-group col-md-3">
<label for="gender">Gender</label>
<select id="species" class="form-control #error('species') is-invalid #enderror"
name="species"
value="{{ old('species') }}"
required autocomplete="species" autofocus>
<option>Unknown</option>
<option>Male</option>
<option>Female</option>
</select>
#error('species')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
#enderror
</div>
<div class="form-group col-md-3">
<label for="color">Color</label>
<input id="color" type="text" class="form-control #error('color') is-invalid #enderror"
name="color"
value="{{ old('color') }}"
placeholder="Select color"
required autocomplete="color" autofocus>
#error('color')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
#enderror
</div>
</div>
<div class="form-group row py-4">
<label for="description" class="col-md-4 col-form-label text-md-right">Description</label>
<div class="col-md-6">
<textarea name="description" id="description" rows="3"
class="form-control #error('description') is-invalid #enderror"
value="{{ old('description') }}"
placeholder="Enter a description of the animal"></textarea>
#error('description')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
#enderror
</div>
</div>
<div class="row col-md-6" style="margin-left:300px">
<button class="btn btn-primary btn-lg btn-block">Finish</button>
</div>
<div class="row col-md-6 py-4" style="margin-left:430px">
<u><h4>Add Pet Later</h4></u>
</div>
</div>
</div>
</form>
</div>
#endsection
And finally the migration for pets table:
public function up()
{
Schema::create('pets', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id');
$table->string('nickname');
$table->string('species');
$table->date('date_of_birth');
$table->string('gender');
$table->string('color')->nullable();
$table->text('description')->nullable();
$table->timestamps();
});
}
Been struggling with this for quite a while now!
Here is the routes file:
<?php
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
return view('welcome');
});
Auth::routes();
Route::get('/register/create', [App\Http\Controllers\PetsController::class, 'create']);
Route::post('/create', [App\Http\Controllers\PetsController::class, 'store']);
$user injected in method store() is empty User model without attributes, like after $user = new User;.
You could retrieve current user id with 2 ways:
First: from request.
public function store()
{
Pet::create([
'nickname' => request('nickname'),
'species' => request('species'),
'date_of_birth' => request('date_of_birth'),
'color' => request('color'),
'description' => request('description'),
'user_id' => request()->user()->id
]);
return redirect('/');
}
Second: from auth.
public function store()
{
Pet::create([
'nickname' => request('nickname'),
'species' => request('species'),
'date_of_birth' => request('date_of_birth'),
'color' => request('color'),
'description' => request('description'),
'user_id' => auth()->id()
]);
return redirect('/');
}
Does the pet belong to the user who is logged in? It is not clear where the User instance comes from, in the form action I don't see a user id.
If the pet belongs to the logged in user, why don't you get the id of the user with:
Auth::user()->id; or Auth::id(); or auth()->user()->id;
I am trying to make a Laravel application that allows a logged-in user to edit one of their memorial pages. The edit view works, but as soon as the changes are saved, it throws a Call to a member function update() on null error. I am new to Laravel, so I apologize if this is a stupid question.
Controller:
public function edit(Memorial $memorial)
{
$this->authorize('update', $memorial);
return view('memorials.edit', compact('memorial'));
}
public function update(Memorial $memorial)
{
$this->authorize('update', $memorial);
$data = request()->validate([
'fname' => 'required',
'lname' => 'required',
'bio' => '',
]);
auth()->user()->memorial->update($data);
return redirect("/memorial/{$memorial->id}");
}
View:
<div class="container pt-5">
<form action="/memorial/{{ $memorial->id }}" enctype="multipart/form-data" method="POST">
<legend>Edit Memorial</legend>
#csrf
#method('PATCH')
<div class="form-group">
<div class="form-row">
<div class="col-6">
<input id="fname" type="text" class="form-control #error('fname') is-invalid #enderror" name="fname" placeholder="First Name" value="{{ old('fname') ?? $memorial->fname }}" autofocus>
#error('fname')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
#enderror
</div>
<div class="col-6">
<input id="lname" type="text" class="form-control #error('lname') is-invalid #enderror" name="lname" placeholder="Last Name" value="{{ old('lname') ?? $memorial->lname }}">
#error('lname')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
#enderror
</div>
</div>
</div>
<div class="form-group">
<div class="form-row">
<div class="col-6">
<input id="bio" type="text" class="form-control #error('bio') is-invalid #enderror" name="bio" placeholder="Biography" value="{{ old('bio') ?? $memorial->bio }}">
#error('bio')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
#enderror
</div>
</div>
</div>
<div class="form-group">
<div class="form-row">
<div class="col-12">
<button class="btn btn-primary">Save</button>
</div>
</div>
</div>
</form>
Policy:
/**
* Determine whether the user can update the memorial.
*
* #param \App\User $user
* #param \App\Memorial $memorial
* #return mixed
*/
public function update(User $user, Memorial $memorial)
{
return $user->id == $memorial->user_id;
}
There are a few things that may be causing this error. I think the first place to investigate is on your relationship vs. what you are trying to update.
Your User model has many memorials:
public function memorials(){
return $this->hasMany(Memorial::class);
}
Your controller is trying to update one memorial:
auth()->user()->memorial->update($data);
To fix, I suggest you try to directly update the memorial in question, rather than through the user relationship. I assume there is a user_id key on the memorial - just add that in as you update the memorial that you have already injected into the update method.
Your relation is incorrect...You don't have memorial relation in User model. So it returns null
You can easily edit one memorial as below code:
public function update(Memorial $memorial)
{
$this->authorize('update', $memorial);
$data = request()->validate([
'fname' => 'required',
'lname' => 'required',
'bio' => '',
]);
$memorial->update($data);
return redirect("/memorial/{$memorial->id}");
}
because in authorize you check the privacy when you edit $memorial that is what you need
so I see the reason is:
in User model you define the memory relation:
public function memorials()
{
return $this->hasMany(Memorial::class);
}
in function update() you call:
auth()->user()->memorial->update($data);
you are calling a model, and it has proposed to get property of Memorial model.
you need to call like this:
in function update():
auth()->user()->memorials()->update($data)
in User model
/**
* Eloquent:User
*
* //relation
* #property Collection|Memorial[] $memorials
*/
class User extends Model
Provided you've set your relationships correctly
Means that your had no memorial at all, i.e no memorial record which linked to that user_id, so nothing to update, thats what we say that relationship is null means its not existing.
You would never know if user have a relationship to memorial record or not so the trick is to create it if its not existing, or updating it if it exists with below simple eloquent code
auth()->user()->memorial->updateOrCreate($data);