Robert Young
Robert Young

Reputation: 563

Why can I not save a post with a user ID field to a database using Laravel?

I am working on a management-style application using Laravel 5, which has a login/logout feature and a facility for users to create their own posts (in this example they are called 'bookings'). I want each user to be able to create their own bookings that are unique to them - i.e. only visible when they are logged in with their username and password. In order to achieve this I have created a column in the 'bookings' table (which stores all the bookings) for user_id. When a logged in user creates a booking, I want his/her own user id to be stored in the user_id column. So at the moment I am passing the user_id (ascertained using auth()->user()) into the 'bookings.store' function as an additional parameter in the route (url). However, I keep on receiving the message: "No query results for model [App\Booking]" when submitting the form, instead of being redirected back to the bookings page with the new booking saved as expected.

Here is some of my code: // BookingsController.php:

<?php

namespace App\Http\Controllers;

use App\Http\Requests;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Redirect;

use Illuminate\Http\Request;

use View;

use App\Model;

use App\User;

use App\Booking;

use App\BookingItem;

use App\Http\Controllers\Validator;

use Input;

class BookingsController extends Controller
{

    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        $bookings = \App\Booking::all();
        return View::make('bookings.index')->with('bookings', $bookings);
            // $user = auth()->user()->id;
            // $bookings = auth()->user()->bookings()->get();
            // return view('bookings.index')->with('bookings', $bookings);

    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        $user = auth()->user();
        return View::make('bookings.create')->with('user', $user);
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request, $user_id)
    {
        // define rules
        $rules = [
            'name' => 'between:2,255',
        ];

         $this->validate($request, [
            'name' => 'required|unique:bookings|max:255',
        ]);


        $name = $request->get('name');
        $description = $request->get('description');
        $booking->name = $name;
        $booking->user_id = $user_id;
        $booking->description = $description;
        $booking->save();
        return Redirect::route('bookings.index')->withMessage('Booking Was Created');
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        $booking = \App\Booking::findorFail($id);
        $items = $booking->BookingItems()->get();        
        return View::make('bookings.show')
        ->withBooking($booking) // will allow us to see our bookings, by id.
        ->withItems($items);

    }
}

?>

// Create.blade.php

@extends('layouts.main')
@section('content')
<div class="container">
    <div class="row">
        <div class="small-6 columns">
            <div class="panel panel-default">
                <div class="panel-heading"><h2>Add a new booking</h2></div>
                <div class="panel-body">
                    {{ var_dump($user->id) }}
                    <form class="form-horizontal" role="form" method="POST" action="{{ route('bookings.store', $user->id) }}">
                        <input name="_method" type="hidden" value="PUT">
                        {!! csrf_field() !!}
                        @include('bookings.partials._form');
                        <div class="form-group">
                            <div class="col-md-6 col-md-offset-4">
                                <button type="submit" class="btn btn-primary">
                                    <i class="fa fa-btn fa-briefcase"></i>Add Booking
                                </button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>

@stop

// web.php (my routes)

    Route::get('/', 'BookingsController@index');
    Route::resource('bookings', 'BookingsController');
    Route::resource('bookings.items', 'BookingItemController', ['except' => ['index', 'show']]);
    Route::resource('agents', 'UsersController');
    Route::get('/bookings/{bookings}/items/{items}/complete', ['as' => 'bookings.items.complete', 'uses' => 'BookingItemController@complete']);
    Auth::routes();

Route::get('/home', 'HomeController@index');
Route::get('/logout', function(){
    Auth::logout();
    return Redirect::route('bookings.index')->withErrors('You Are Logged Out!');
});
Route::post('/bookings/{id}', ['uses' => 'BookingsController@store', 'as' => 'bookings.store']);

My bookings table contains the following columns:

id (pk) user_id (fk) name description created_at updated_at

If anyone has any advice or could help, that would be great. At the moment, I think it might be defaulting to the show route.

Regards,

Robert London, Uk

Current routes:

+--------+-----------+--------------------------------------------+-------------------------+------------------------------------------------------------------------+--------------+
| Domain | Method    | URI                                        | Name                    | Action                                                                 | Middleware   |
+--------+-----------+--------------------------------------------+-------------------------+------------------------------------------------------------------------+--------------+
|        | GET|HEAD  | /                                          |                         | App\Http\Controllers\BookingsController@index                          | web          |
|        | GET|HEAD  | agents                                     | agents.index            | App\Http\Controllers\UsersController@index                             | web          |
|        | POST      | agents                                     | agents.store            | App\Http\Controllers\UsersController@store                             | web          |
|        | GET|HEAD  | agents/create                              | agents.create           | App\Http\Controllers\UsersController@create                            | web          |
|        | GET|HEAD  | agents/{agent}                             | agents.show             | App\Http\Controllers\UsersController@show                              | web          |
|        | DELETE    | agents/{agent}                             | agents.destroy          | App\Http\Controllers\UsersController@destroy                           | web          |
|        | PUT|PATCH | agents/{agent}                             | agents.update           | App\Http\Controllers\UsersController@update                            | web          |
|        | GET|HEAD  | agents/{agent}/edit                        | agents.edit             | App\Http\Controllers\UsersController@edit                              | web          |
|        | GET|HEAD  | api/user                                   |                         | Closure                                                                | api,auth:api |
|        | POST      | bookings                                   | bookings.store          | App\Http\Controllers\BookingsController@store                          | web          |
|        | GET|HEAD  | bookings                                   | bookings.index          | App\Http\Controllers\BookingsController@index                          | web          |
|        | GET|HEAD  | bookings/create                            | bookings.create         | App\Http\Controllers\BookingsController@create                         | web          |
|        | GET|HEAD  | bookings/{bookings}/items/{items}/complete | bookings.items.complete | App\Http\Controllers\BookingItemController@complete                    | web          |
|        | DELETE    | bookings/{booking}                         | bookings.destroy        | App\Http\Controllers\BookingsController@destroy                        | web          |
|        | PUT|PATCH | bookings/{booking}                         | bookings.update         | App\Http\Controllers\BookingsController@update                         | web          |
|        | GET|HEAD  | bookings/{booking}                         | bookings.show           | App\Http\Controllers\BookingsController@show                           | web          |
|        | GET|HEAD  | bookings/{booking}/edit                    | bookings.edit           | App\Http\Controllers\BookingsController@edit                           | web          |
|        | POST      | bookings/{booking}/items                   | bookings.items.store    | App\Http\Controllers\BookingItemController@store                       | web          |
|        | GET|HEAD  | bookings/{booking}/items/create            | bookings.items.create   | App\Http\Controllers\BookingItemController@create                      | web          |
|        | DELETE    | bookings/{booking}/items/{item}            | bookings.items.destroy  | App\Http\Controllers\BookingItemController@destroy                     | web          |
|        | PUT|PATCH | bookings/{booking}/items/{item}            | bookings.items.update   | App\Http\Controllers\BookingItemController@update                      | web          |
|        | GET|HEAD  | bookings/{booking}/items/{item}/edit       | bookings.items.edit     | App\Http\Controllers\BookingItemController@edit                        | web          |
|        | POST      | bookings/{id}                              | bookings.store          | App\Http\Controllers\BookingsController@store                          | web          |
|        | GET|HEAD  | home                                       |                         | App\Http\Controllers\HomeController@index                              | web,auth     |
|        | GET|HEAD  | login                                      | login                   | App\Http\Controllers\Auth\LoginController@showLoginForm                | web,guest    |
|        | POST      | login                                      |                         | App\Http\Controllers\Auth\LoginController@login                        | web,guest    |
|        | POST      | logout                                     |                         | App\Http\Controllers\Auth\LoginController@logout                       | web          |
|        | GET|HEAD  | logout                                     |                         | Closure                                                                | web          |
|        | POST      | password/email                             |                         | App\Http\Controllers\Auth\ForgotPasswordController@sendResetLinkEmail  | web,guest    |
|        | GET|HEAD  | password/reset                             |                         | App\Http\Controllers\Auth\ForgotPasswordController@showLinkRequestForm | web,guest    |
|        | POST      | password/reset                             |                         | App\Http\Controllers\Auth\ResetPasswordController@reset                | web,guest    |
|        | GET|HEAD  | password/reset/{token}                     |                         | App\Http\Controllers\Auth\ResetPasswordController@showResetForm        | web,guest    |
|        | GET|HEAD  | register                                   |                         | App\Http\Controllers\Auth\RegisterController@showRegistrationForm      | web,guest    |
|        | POST      | register                                   |                         | App\Http\Controllers\Auth\RegisterController@register                  | web,guest    |
+--------+-----------+--------------------------------------------+-------------------------+------------------------------------------------------------------------+--------------+

Upvotes: 0

Views: 2570

Answers (2)

Eric Tucker
Eric Tucker

Reputation: 6335

You need to name the route something else because bookings.store is already defined in Route::resource('bookings', 'BookingsController');

I would recommend excluding this resource from the resource and defining your bookings.store with an optional {id?} parameter you can check if present so you can store a user's bookings or a normal one based on the presence of that parameter in the store method.

Also as @Steve Bauman recommended, remove <input name="_method" type="hidden" value="PUT"> from your form because with that there it is accessing your bookings.update method.

It should all fit together as follows:

    Route::get('/', 'BookingsController@index');

    Route::resource('bookings', 'BookingsController', ['excep'=> ['store']]);
    Route::post('/bookings/{id?}', ['uses' => 'BookingsController@store', 'as' => 'bookings.store']);

    Route::resource('bookings.items', 'BookingItemController', ['except' => ['index', 'show']]);
    Route::resource('agents', 'UsersController');
    Route::get('/bookings/{bookings}/items/{items}/complete', ['as' => 'bookings.items.complete', 'uses' => 'BookingItemController@complete']);
    Auth::routes();

Route::get('/home', 'HomeController@index');
Route::get('/logout', function(){
    Auth::logout();
    return Redirect::route('bookings.index')->withErrors('You Are Logged Out!');
});
Route::post('/bookings/{id}', ['uses' => 'BookingsController@store', 'as' => 'bookings.store']);

Then in your store method in your controller:

public function store(Request $request, $user_id = null)
{
    // define rules
    $rules = [
        'name' => 'between:2,255',
    ];

     $this->validate($request, [
        'name' => 'required|unique:bookings|max:255',
    ]);

    $booking->name = $request->get('name');
    $booking->description = $request->get('description');

    $booking->user_id = $user_id;

    $booking->save();

    return Redirect::route('bookings.index')->withMessage('Booking Was Created');
}

This way, it will handle the work for you if there is an id it will apply it and if not then it will be null

Upvotes: 0

Steve Bauman
Steve Bauman

Reputation: 8678

Why don't you just grab the authenticated users ID during the creation rather then sending it through the form? This could be a huge security issue as well since a user could modify the HTML of the page and submit a booking under a different user ID.

Here's a fix:

/**
 * Store a newly created resource in storage.
 *
 * @param  \Illuminate\Http\Request  $request
 *
 * @return \Illuminate\Http\Response
 */
public function store(Request $request)
{
    // define rules
    $rules = [
        'name' => 'between:2,255',
    ];
    $this->validate($request, [
        'name' => 'required|unique:bookings|max:255',
    ]);

    $booking = new Booking();

    $booking->name = $request->name;
    $booking->user_id = auth()->id();
    $booking->description = $request->description;
    $booking->save();

    return Redirect::route('bookings.index')->withMessage('Booking Was Created');
}

Edit:

You have this route here:

Route::post('/bookings/{id}', ['uses' => 'BookingsController@store', 'as' => 'bookings.store']);

But inside your HTML form you're initiating a PUT request when it should be just a standard POST:

<input name="_method" type="hidden" value="PUT">

Upvotes: 1

Related Questions