milkncookiez's avatar

Pass value to URL - REST style

<h1>Edit page of {{ $user->username }}</h1>
{{ Form::open(['route' => 'user.store']) }}
... the rest of the view

This is in my login view. The related code in the store method in the controller looks like this:

if (Auth::attempt(Input::only('username', 'password'))) {
     $user = Auth::user();
     return Redirect::route('user.show', ['user' => $user]);
}

and the show method:

public function show($user)
{
   return View::make('user.edit', ['user' => $user]);
}

And I get .../user/%7Buser%7D as URL (and I want it to be, eg. .../user/exampleusername) and also an exception: ErrorException: Trying to get property of non-object.

When I dd($user) in the show method (or in the view, doesn't matter), I get simply string[6] {user}, which means I do not pass the $user successfully to the user.show route.

The official docs give this example: return Redirect::route('profile', array('user' => 1)); which seems relevant to my case, which I think should look like this in my code: return Redirect::route('user.show', ['user' => $user]);?

Funny, though, if in the show method I try to take the user object from the session (Auth::user()), and dump it, as here:

public function show($user)
{
    $user = Auth::user();
    dd($user);
    ...

it will still be NULL, but if I dump it in the index method:

public function index()
{
    if (Auth::check()) {
    dd(Auth::user());
    ...

, then it returns correct object, full of parameters and values... I have no idea what's going on and why in one method I have the session object, but in the other I don't.

Any suggestions on how to go around this problem?

UPDATE: I narrowed it down to this implementation in the store method:

return Redirect::route('user.show')->with('user', $user);

and in the show method:

$user = Session::get('user');
return View::make('user.edit', ['user' => $user]);

Because apparently the only place where you can pass an array that will explode into single variables is in View::make, whereas in Redirect::to, Redirect::action and Redirect::route, etc., you must use the ->with('key', $value) function. Those values then will be available in the Session singleton.

Nevertheless, I still get .../%7Buser%7D in the URL. And I don't know how to get out of this...

0 likes
6 replies
foxted's avatar

If I get it right, you are trying to redirect to the show method after you store method. If you are using resource controllers, the show method is suppose to receive an id parameter like so:

return Redirect::route('user.show', ['id' => $id]);

This way you don't have to pass the user variable through the session.

thepsion5's avatar

You can't pass objects as route parameters, as far as I'm aware. You'd typically pass the ID and then reload the relevant object using the ID. The with() method adds the specified value as a session flash key, which has no problem with objects.

pmall's avatar

Resources routes take the id of the resource as parameter. Two possibilities :

You use a resource route and use the id of the user

Route::resource('users', 'UsersController'); // I prefer always puralize the resource urls but it is a matter of taste
route('users.show', [$user]) // When passing a model as parameter its id is used in the url. It is a shorthand
public function show($user_id)
{
  $user = User::findOrFail($user_id); // You have to get the user from its id.
}

If you want to put the username in the url, you'd better manualy define all the routes.

Route::get('users/{username}', ['as' => 'users.show', 'uses' => 'UsersController@show']);
route('users.show', [$user->username]) // You have to manually pass the username to the url generator
public function show($username)
{
  $user = User::where('username', '=', $username)->firstOrFail(); // Get the user from the username
}
adnan's avatar

You can use Route Model Binding and a resource controller.

Route::model('users', 'User');

Route::resource('users', 'UsersController');
1 like
nolros's avatar

@milkncookiez not sure I understand your question, but I wouldn't pass the user object around like you are doing unless I'm missing something? Are you attempting to return the users own object or another users object? Same user is much simpler and seems to be what you are trying to accomplish.

btw, I don't pass parameters inside of controllers to controllers methods, I believe they need to stand and act alone as if they are always being accessed from a client which is really their purpose. So you can redirect, but don't pass parameters. So in my case I would say do the follow: check if use is auth if not then send to login, if auth then redirect to roles (as an example), but it is always just return redirect('/');

If you are attempting to return the users own information then just make a GET call to method in controller, the method will check if the user making the request is auth and then return that users info. I also wouldn't pass back the entire user object for security reasons so I will have a another user query with a select filter as I don't need the id for example, but that is a minor point.

Return same users information:

    public function login()
    {
        if (Auth::attempt(Input::only('username', 'password')))
        {
            return redirect('/getUserInfo');
        }
    }

    public function getUserInfo()
    {       
        if (Auth::check())
        {
            return view('user.show')
                ->with('user', Auth::user());
        }
    }
1 like
milkncookiez's avatar

With great help from @pmall 's answer I managed to do what I was aiming for, and even without using Route-Model binding (which is good, I guess..., because it really simplifies the logic, at least for my understandings). Following is the code, if someone has the same problem.

routes.php:

Route::resource('user', "UsersController",
    ['except' => ['create', 'store', 'show']]);

Route::get('user/register', [
    'as'   => 'user.create',
    'uses' => "UsersController@create"
]);
Route::post('user/register', [
    'as'   => 'user.register',
    'uses' => "UsersController@register_user"
]);
Route::post('user', [
    'as'   => 'user.login',
    'uses' => "UsersController@login_user"
]);
Route::get('user/{username}', [
    'as'   => 'user.show',
    'uses' => "UsersController@show"
])->before('auth');

and then in the controller, I redirect like this:

return Redirect::route('user.show', [Auth::user()->username]);

and the show function:

public function show($username)
    {
        $user = User::where('username', '=', $username)->first();

        return View::make('user.profile', ['user' => $user]);
    }

Please or to participate in this conversation.