Mysterious String Phenomena

Published 1 week ago by artmonger

I'm passing two variables from the index page to the create page. The output inserts white-space into the characters of the variable if I concatenate the two variables in the controller. Other times, it only gives me the last character, or the first characters and cuts off the last one.

Here's the part on my index page:

<li>
{{ $chicken->variety }} {{ $chicken->name }}
<a href="{{ route('/chickens/{variety}{name}/create', ['variety' => $chicken->variety, 'name' => $chicken->name]) }}">create</a>
</li>

Here's the Route:

Route::get('/chickens/{variety}{name}/create', [
    'as' => '/chickens/{variety}{name}/create', 
    'uses' => '[email protected]'
]);

With just one variable, it was working great. I could pass a breed name and I'd get it on the create page, such as "Create a new Sebright", etc.

However, I want to pass in a variety slug, such as "Create a new Golden Sebright" or "Create a new "Silver Sebright", etc.

Here's my controller method:

 public function create($variety, $name)
    {
        $variety;
        $name;
        
        return view('chickens.create', compact('variety', 'name');
    }

What do I get? Very strange things, like... "Create a New l" That's the last character in Aseel.

or if I click on an Ameraucana, I end up with "Create a New a" Again, the last letter.

I tried this, $breed = $variety. ' ' .$name; and then passing $breed to compact()...

But I get thinks like "American Buf f". Note, the space between the f's.

dd($breed); and I get two strings... One is the first word, the second is the last character of the breed name.

I've tried using with(); but I still find problems.

What do you think?

Best Answer (As Selected By artmonger)
Jaytee

Your original problem was with this line here: <a href="{{ route('/chickens/{variety}{name}/create', ['variety' => $chicken->variety, 'name' => $chicken->name]) }}">create</a>.

When you use the route() method, you give it a name instead of the URL. You were passing the whole route AND the wildcards which is a no no and a recipe for disaster (which happened).

When you use the as key on the route or when you chain on ->name('some.name'); is when a route becomes a named route.

So for example, to use the route() method:

Route::get('/', '[email protected]')->name('home');
Route::get('/', ['uses' => '[email protected]', 'as' => 'home']); 

// both of them are the same
// Then i'd do something like

<a href="{{ route('home') }}">a link</a>

// if i need to pass one parameter, i would pass it as the second argument
<a href="{{ route('home', $user->username) }}">a link</a>

// if i need to pass more than one parameter, i would pass an array as the second argument

<a href="{{ route('home', [$user->username, $article->slug]) }}">a link</a>

// You can also do route model binding where you just pass the whole object to the second argument

<a href="{{ route('home', $user) }}">a link</a>

P.S: you don't need to declare arguments from a function/method within the function/method.

This is what you were doing:

public function create($variety, $name)
    {
        $variety;
        $name;
        return view('chickens.create', compact('variety','name'));
    }

You can just do:

public function create($variety, $name)
    {
        return view('chickens.create', compact('variety','name'));
    }
ftrillo
ftrillo
1 week ago (12,140 XP)

You should probably separate both variables in the url with a slash. Also, you don't have to repeat the route again in the 'as'. That parameter is for naming the route.

// Like this
 Route::get('/chickens/{variety}/{name}/create', [ 'as' => 'chickens.create', 'uses' => '[email protected]' ]);

// Or this if you have an up to date version of Laravel
 Route::get('/chickens/{variety}/{name}/create', '[email protected]')->name('chickens.create'); // The name isn't mandatory
artmonger

I tried this:

Route::get('/chickens/{variety}/{name}/create', '[email protected]');

and I changed my route method to,

create

but I'm getting an error Exception,

Route[/chickens/{variety}/{name}/create] not defined... How is that possible? The strings, match.

artmonger

The route() method requires named routing. when I use named routing, I get my page dumping all my chickens. But when I select the create link I only get the last letter of the breed name. That's just strange.

Jaytee
Jaytee
1 week ago (96,465 XP)

Yeah something is going wrong somewhere.

Can you show me the controller and view please.

Also, if you can show me where you're passing the parameters for the URL (e.g: a form or button).

Alternatively, what you could do is just have a generic /chickens/create route and have a couple of select boxes which a user selects for the variety and name.

Snapey
Snapey
1 week ago (647,375 XP)

Named routing should have nothing to do with it.

Please can you use three backticks ``` before and after your code blocks so we can actually see what you are doing.

Please list your routes and your controller.

artmonger

I came up with another solution:

        @foreach($chickens as $chicken)
            <li>
                @if($chicken->is_bantam == true)
                    <label>bantam</label>
                @endif
                {{ $chicken->variety }} {{ $chicken->name }}
                <a href="{{ route('/chickens/{kind}/create', ['kind' => $chicken->variety."-" .$chicken->name]) }}">create</a>
            </li>
        @endforeach
    </ul>

I changed the two slugs to just one and added a "-" in the array passed as the second argument to the route() method.

I updated my Route to this,

Route::get('/chickens/{kind}/create', [
    'as' => '/chickens/{kind}/create', 
    'uses' => '[email protected]'
]);

and my Controller method,

   public function create($kind)
    {
        $kind;
        return view('chickens.create', compact('kind'));
    }

However, this doesn't allow me split the breed $variety and $name variables up, and I didn't figure out the missing character part.

Here's what I used to have...

Old Index:

    <ul>
        @foreach($chickens as $chicken)
            <li>
                @if($chicken->is_bantam == true)
                    <label>bantam</label>
                @endif
                {{ $chicken->variety }} {{ $chicken->name }}
                <a href="{{ route('/chickens/{variety}{name}/create', ['variety' => $chicken->variety, 'name' => $chicken->name]) }}">create</a>
            </li>
        @endforeach
    </ul>

Old Controller:

    public function create($variety, $name)
    {
        $variety;
        $name;
        //dd($name);
        return view('chickens.create', compact('variety','name'));
    }

Old Route:

Route::get('/chickens/{variety}{name}/create', [
    'as' => '/chickens/{variety}{name}/create', 
    'uses' => '[email protected]'
]);

` and whether id die&dumped the variables passed to the Controller, or passed them through to the compact() method, I would get broken strings.

For example, a Golden Wyandotte, would end up as a "Golden e".

Or if I tried doing this, in the controller $breed = $variety. ' '.$name; I would end up with "Golden Wyandot te". with a space inbetween the t's.

Also, when I would insert "-", instead of a space, such as $variety.'-'.$name, I could get "Golden Wyandot-te".

LOL. So, mysterious!

Jaytee
Jaytee
1 week ago (96,465 XP)

Your original problem was with this line here: <a href="{{ route('/chickens/{variety}{name}/create', ['variety' => $chicken->variety, 'name' => $chicken->name]) }}">create</a>.

When you use the route() method, you give it a name instead of the URL. You were passing the whole route AND the wildcards which is a no no and a recipe for disaster (which happened).

When you use the as key on the route or when you chain on ->name('some.name'); is when a route becomes a named route.

So for example, to use the route() method:

Route::get('/', '[email protected]')->name('home');
Route::get('/', ['uses' => '[email protected]', 'as' => 'home']); 

// both of them are the same
// Then i'd do something like

<a href="{{ route('home') }}">a link</a>

// if i need to pass one parameter, i would pass it as the second argument
<a href="{{ route('home', $user->username) }}">a link</a>

// if i need to pass more than one parameter, i would pass an array as the second argument

<a href="{{ route('home', [$user->username, $article->slug]) }}">a link</a>

// You can also do route model binding where you just pass the whole object to the second argument

<a href="{{ route('home', $user) }}">a link</a>

P.S: you don't need to declare arguments from a function/method within the function/method.

This is what you were doing:

public function create($variety, $name)
    {
        $variety;
        $name;
        return view('chickens.create', compact('variety','name'));
    }

You can just do:

public function create($variety, $name)
    {
        return view('chickens.create', compact('variety','name'));
    }
Snapey
Snapey
1 week ago (647,375 XP)

Some good feedback there. Also, to understand 'strange String Phenomena'

You were hoping to set '/chickens/{variety}{name}/create' as your route

You have two variables next to each other with no means to separate them

So, if you requested this route;

Create a new Golden Sebright Laravel router its trying to assign some part of the string to variety and some to name with no way to delimit them. It might do

$variety = 'Create a new Golden Sebrigh' and $name='t'

or

$variety = 'Create a new G' and $name='olden Sebright'

or

$variety = 'C' and $name='reate a new Golden Sebright'

Laravel has no way of knowing what was in your head about where the split should be.

Assume for some SEO reason you want to pass a 'slug' to the controller then just do that but you will need to split it down again which you can do in your route.

        @foreach($chickens as $chicken)
            <li>
                @if($chicken->is_bantam == true)
                    <label>bantam</label>
                @endif
                {{ $chicken->variety }} {{ $chicken->name }}
                <a href="{{ route('chickens.create', $chicken->variety."-" .$chicken->name) }}">create</a>
            </li>
        @endforeach
    </ul>

Route should be like;

Route::get('/chickens/{variety}-{name}/create', [
    'as' => 'chickens.create', 
    'uses' => '[email protected]'
]);

Note that the delimiter is in the route, separating the parts.

Then in controller you will get both variables passed

public function create($variety, $name)
{

Please sign in or create an account to participate in this conversation.