Writing a Blog in Laravel: Create a Post — Part 2

Continuing the previous post, Let’s continue on to the next step of creating the post. We need to save the post to database now. We have three posts with the steps to create a feature in laravel already. We should have gotten used to the flow now. I am just going to do this without mentioning the steps now.

We need to create a route to post the data to create a post. So in routes/web.php. We add the following line

Route::post('posts','PostController@store');

So, in app/Http/Controllers/PostController.php. We need to add method store

public function store(Request $request)
{

}

To save a post, we would need to have title, content and author. Title and content is in the form that we can input, but there is not author field in the form. That is because we need to figure out the currently logged in user and create a post for that user. We have done the login part here.

There are few ways to create a post. But the way I like to do it is through Eloquent relations because that makes it clearer as to what is actually happening. Let me show you the code and explain further.

Laravel provides a fluent way to define relation. To indicate the relation between a user and a post. We just create a function and mention what the relation is. In our case, this is what it should be. We write this code in app/User.php

public function posts()
{
return $this->hasMany(Post::class);
}

This means that a user has many posts.

Defining relations might be confusing to some people. A simple way to remember this is that, if
If the a table has a foreign key in it, it means that the entity that the foreign key represents hasMany of the entity the current table represents. In our case, because posts table, that represents the Post model, has user_id foreign key, which, represents the User model, the relation from User to Post is hasMany.
The opposite of belongs to is hasMany. So defining the same relation in Post model would be. Add this method to app/Post.php.
public function user()
{
 return $this->belongsTo(User::class);
}
This mean a post belongs to a user

We have defined the relation a user to posts. Now we can use this.

In store method of PostController we can use the relation like this,

Let’s break the code down.

//this gives us the currently logged in user
$user = $request->user();
//this fetches all the post data from the form
//we can post all the data from post and not get an error
// because laravel handles this in Post model through fillable array
//Laravel will only save the data from the key that is in the fillables array

$formData = $request->all();
// we need a seo bot readable url, this will create a slug based on title
$formData['slug'] = str_slug($request->get('title'));
//this creates posts based on the relation from user to post
//meaning the id of user is automatically populated and saved in the user_id column of posts table

$user->posts()->create($formData);

and the fillables array in the Post model should look like this in app/Post.php

protected $fillable = ['title', 'content','slug'];

Now we need to update our url in the action attribute of create posts form in resources/posts/create.blade.php. we also need to a add a CSRF field to prevent Cross Site Request Forgery in our application.

CSRF prevention means that we are stopping requests that are not coming from a form inside our application. If someone hits the posts create url from outside our application, we will not create the posts.
<form action="{{ url('posts') }}" class="form" method="post">
{{ csrf_field() }}

After all this is done. We should be able to create a post after we login to our application. Since we are not letting a user post without logging into our application, it makes sense to stop the user that have not logged in to our application to not show the create form at all. Laravel makes this super easy. We can use the default auth middleware from Laravel. To use this we can assign a middleware to our route.

Middlewares are basically layers that sits between a request and a response. You can choose to intercept the request before it gets to a controller, process something from the request, add somethings to request and send it to controller for processing or you can get the response from the controller add some parameter to the said response, and send back to the user or do both. We will cover middleware in a different post in detail

So after adding our middleware to create form of the post, it would look like this

Route::get('posts/create', 'PostController@create')->middleware('auth');
Route::post('posts','PostController@store')->middleware('auth');

After this if you access the url http://blog.local/posts/create , the url we created to display the create post form, it would redirect to login page, if you are not logged in.

When you are redirected you will see an error screen

Error screen you will see if you are not logged in

This is because laravel expects us to have a route named login. We will come back to named routes in later posts. We can override this behavior in app/Exceptions/handler.php

Laravel’s default function to handle this exception can be found at vendor/laravel/framework/src/Illuminate/Foundation/Exceptions/Handler.php and it looks like

We can override this to our requirement. At the moment, we just need the user to go to login url if they are not authenticated. So the code that we override in app/Exceptions/Handler.php looks like this

public function unauthenticated($request, AuthenticationException $exception)
{
return redirect()->to('login');
}
Note: we should override this in our app/Exceptions/Handler.php NOT in vendor file because vendor files MUST not be altered and will be overridden when we do composer update or install. And the reason this would work is our app Handler class extends the core laravel ExceptionHandler class

For this post, we would like to redirect user to create post form after login, so the code to AuthController, the code that handles postLogin process, needs to change as well.

Now when you save the post it will show you a page with message “Post saved Successfully” and a post in the database. The changes that were made during this post are here.

There are many things missing in this post.

  1. Validation: there is not validation at all
  2. We do not check slug for uniqueness meaning that if you post the same title, it will give you a database error.
  3. We are not redirecting user properly on successful post submit.
  4. The urls are hardcoded, we can use named routes, so that if the url changes at one place, it will change everywhere.

We will do all this in our next post.

Like what you read? Give Naren Chitrakar a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.