Topic: Split a string by keywords (catch-all routes)

Hi all,

I am playing about with catch-all routes, but I want to take that a little further than in Ryans Railscast.

The purpose is a search that has different parameters depending on what to search for. The URL should look something like this:
"/find/manager" or "/find/manager+worker"

This can be extended with:
"/find/manager/tagged/teamwork" or "/find/manager+worker/tagged/teamwork"

I hope you can see that there are 2 keywords in this example: "find" and "tagged". There will be more later on, but let's keep is simple for now. What I need to do now is to search the URL for the keywords I defined (find, tagged) and get the element after this to place my search variables.

I don't really know which way is the best to go now. Should I treat params[:path] as array or string?

If I treat it as array I can look for the occurance of my keyword and get the array element after this. If I treat it as string I'll have to use regular expressions to fetch the value between the keyword and the next "/" of the URL. Anyone has experience with what I am trying to do and could lead me into the right direction?

Any help is much apprechiated.

Re: Split a string by keywords (catch-all routes)

If you do this:

search_hash = HashWithIndifferentAccess[*params[:path].split("/") - [""]]

You should get a hash like this:
{:find => "manager", :tagged => "teamwork"}

Which might help a bit wink


Re: Split a string by keywords (catch-all routes)

wow Alex, thanks! I'll try that out right away.

What is the difference between *params[:path] and params[:path] by the way?

Re: Split a string by keywords (catch-all routes)

The star tells the method about the number of arguments you're passing. By default, the method enforces an even number of arguments to be passed like so:

HashWithIndifferentAccess["a", 1, "b" 2]

If you break that form, an error will be thrown. However by prefixing the star your telling Rails that you know your passing a non-standard number of arguments, and want it to carry on anyway.


Re: Split a string by keywords (catch-all routes)

Hi Alex,

I finally got around to test this out. I don't know if I did something wrong, but HashWithIndifferentAccess[*params[:path].split("/") - [""]] does not really work. It throws the "odd number of arguments for Hash" argument error.

After a 5-minute-trial-and-error attempt I got it down to merely HashWithIndifferentAccess[*params[:path]] and it now works the way it was intended - the hash is created correctly. I would have never figured this out myself without knowing the HashWithIndifferentAccess class, so thanks for your help.

Nonetheless, I was not sure what's the ' - [""]' stands for in your example. If you could tell me what it does, that would be great :-)

Re: Split a string by keywords (catch-all routes)

I'm guessing the code isn't needed because of the format of the url. If you try doing:

"/find/manager".split "/"

You'll get an array like:
["", "find", "manager"]

The extra "" is created by the trailing /. So the - [""] just gets rid of that empty string.

However I'm guessing the urls are actually in the format "find/manager", which makes that line unneccessary (although I'm not sure why it would cause that error).

Hope that clears it up wink.


Re: Split a string by keywords (catch-all routes)

There's no need for the extra [""]. find/manager and find/manager/ create the same array.

Another thing I just got a little stuck with: It all breaks when I use an odd array, like find/manager/tagged, even though I apply the *params[:path] for the HashWithIndifferentAccess sad

Re: Split a string by keywords (catch-all routes)

I meant leading slash, not trailing slash sorry wink.

I maybe should have been clearler about the *. It will stop the method from failing immediately, but if its simply has one too few/many arguments it will still fail. You need to tell it what to do, as it doesn't know by itself. Something like this:

split_array << nil if split_array.length.odd?

should sort it out.


Re: Split a string by keywords (catch-all routes)

Thanks again for the clarification, Alex.

I've just done it like this before I read your post:

search_array.pop if search_array.size.odd?

So, I kick the last element out completely, as it is of no use without value.

Mind me asking how you know about the * and such things? I have The PickAxe (Programming Ruby) 2nd Ed and AWDR 1st Ed. I've often seen similar syntax, but never found the explanation for this. Perhaps I should read the Ruby book on long journeys rather than some other entertaining lecture wink

Re: Split a string by keywords (catch-all routes)

I'm not completely sure where I read about the *. Maybe in Programming Ruby, that was really the only big Ruby book I've gone through properly (I must say, it was very good).