Custom rails routes not using :id column - ruby-on-rails

I am attempting to create a custom rails route that allows me display information based upon the url. For example, I have products in a database with category_ids and country of origin fields. I would like to be able to type something like /products/(category_id)/canada or something to list items that match that category and country however my attempts have (obviously) been unsuccessful.
So far I've attempted
match 'products/:category_id/:country', to: "products#var_show"
and had no luck.
I've even just tried to make a route that shows the product via the serial code but rails seems to think I'm looking for an id even though I've specified the field in the route and in the controller.
match 'products/:serial', to: "products#show"
Can someone lead me in the right direction and show me what I'm doing incorrect? Thanks.
edit:
Rails seems to make the parameter :id no matter what I call it in the route and controller
Processing by ProductsController#show as HTML
Parameters: {"id"=>"481598745"}
Ideally that would be Parameters : {"serial" => "481598745"} in the second case I asked about.

Try this,
match 'products/:category_id/:country' => 'products#show',:as => :show

Related

How to get an organized search URL result with slashes orders (/)?

I want a search section on the "index" from books_controller with some filter options from different authors, categories and other attributes. For example, I can search for a category "romance" and max pages = 200. The problem is that I'm getting this (with pg_search gem)
http://localhost:3000/books?utf8=%E2%9C%93&query%5Btitle%5D=et&button=
but I want this:
http://localhost:3000/books/[category_name]/[author]/[max_pages]/[other_options]
In order that if I want to disable the "max_pages" from the same form, I will get this clean url:
http://localhost:3000/books/[category_name]/[author]/[other_options]
It'll work like a block that I can add and remove.
What is the method I should use to get it?
Obs: this website, for example, has this kind of behavior on the url.
Thank you all.
You can make a route for your desired format and order. Path parameters are included in the params passed to the controller like URL parameters.
get "books/:category_name/:author/:max_pages/:other_options", to: "books#search"
class BooksController < ApplicationController
def search
params[:category_name] # etc.
end
end
If other options is anything including slashes, you can use globbing.
get "books/:category_name/:author/:max_pages/*other"
"/books/history/farias/100/example/other"
params[:other]# "example/other"
So that gets you the basic form, now for the other you showed it could just be another path since the parameter count changed.
get "books/:category_name/:author/*other_options", to: "books#search"
params[:max_pages] # nil
If you have multiple paths with the same number of parameters, you can add constraints to separate them.
get "books/:category_name/:author/:max_pages/*other", constraints: {max_pages: /\d+/}
get "books/:category_name/:author/*other"
The Rails guide has some furth information, from "Segment Contraints" and "Advanced Constraints": http://guides.rubyonrails.org/routing.html#segment-constraints
If the format you have in mind does not reasonably fit into the provided routing, you could also just glob the entire URL and parse it however you wish.
get "books/*search"
search_components = params[:search].split "/"
#...decide what you want each component to mean to build a query
Remember that Rails matches the first possible route, so you need to put your more specific ones (e.g. with :max_pages and a constraint) first else it might fall through (e.g. and match the *other).

Rails routing sometimes replaces the id in url with id-name. How do I avoid problems?

Generally the url from my report page looks like this:
http://test-account.peter:3000/offices/7/reports/index
However, sometimes it looks like this:
http://test-account.peter:3000/offices/7-peters-office/reports/index
Why does this happen?
It was not really a problem until we changed the controller action from a GET to a POST and renamed it. We had to do this so we could pack more parameters in to the ajax request. Users still have this section of the site bookmarked and it throws errors all day long.
I have tried to redirect the route:
get '/offices/*all/reports/index' => 'offices#show'
get '/offices/:office_id/reports/index' => 'offices#show'
get '/offices/:office_name/reports/index' => 'offices#show'
Is there a way to catch the name? Or do I have to prevent the name from being added to the url in the first place?
In the controller, you would be able to parse the parameter to get just the first character and check if its an integer. However, it would be much better to debug how the parameter is getting assigned to different values and ensure only the id is used. If you're linking to that route in a view, check what is being passed in the link and confirm the value is what you expect it to be.
Rails does routing it does not look in your database for matched data. So without looking at data, your three routes are exactly the same, the variable (office_id & office_name) is just named different. If you get a request on example /offices/:office_name/reports/index, rails will just match the first one since both routes match the request.
You need something in the path that indicates its a name or id. If you will really never have a name and id with the same search, then you could just have one route and try to match a id or name from the DB in the controller.

non resourceful routes with model attributes and url helpers

I have a problem with the helpers url and path helpers for a non-resourceful route,
There is a model Item that has, among other attributes, an sku attribute
so the default routing with
resources :items
creates the default index route
item GET /items/:id(.:format) items#show
But I want to override that route to match urls like:
/sku/:sku/id/:id
instead of the default urls:
/items/:id
So I created the following route and put it above resources :items to be matched first:
get "sku/:sku/id/:id" => "items#show", as: "item"
and it works correctly if I go to www.example.com/sku/2342/id/8484 it shows me the correct Item.
However, my problem is if I want to use the item_path or item_url helpers passing the object to them.
Instead of getting the desired path /sku/2342/id/8484 I am getting a path with the id of the item applied twice like /sku/8484/id/8484
I searched in google and here in StackOverflow for several minutes and I cant find the answer, I already read the Rails routing documentation but still no success, hope some one can help me, thanks.
Are you doing something like item_path(item, item). I'm not sure that will work. If you pass in the actual object, it grabs the id field.
Did you try item_path(item.sku, item)?

Remove controller_name from URL in Rails 3 and use custom string instead of id

Since the beginning I always hat this one problem with rails, short urls without the controller name.
For example, I have a blog and I don't want any dates or controller names in the url, I already have a Page model with a unique field url in my database. Rails works great with such urls:
jeena.net/pages/1
And when I modify the model I even can get it to use
jeena.net/pages/foo
But it seems not to matter what I do I can not get it to work with just:
jeena.net/foo
Of course I want the index page still to work with
jeena.net/pages
And I want creating new pages and updating old pages to work too in some was as well as the link_to()-method. All suggestions are appreciated.
To define that route, try adding the following to your routes.rb:
match '/:id' => 'your_controller#your_action'
This will pretty much match everything to the id of your model. And that's not very nice... You don't want to route youe_host/pages to the pages controller, with an id equal to 'pages'... To prevent that from happening, make sure to put that line on the end of the routes.rb file. The router uses the first route that matches the path received, so putting that line on the end of it will make sure that it will only match your route after it ran out of other meaningful options.
A better practice would be to pass regexp constraints to the router, so that it will only match ids with a specific format, like that:
match '/:id' => 'your_controller#your_action', :constraints => { :id => /your_regexp/ }
Refer to the guides if you have doubts about the rails rounting system. It is pretty well written and covers lots of important things.
Rails rounting - Official Guides
edit: to create a named route, one that you can call in your controllers and override the normal routes that you are probably creating with resource, you have to provide the :as => parameter in your routes.rb
match '/:id' => 'your_controller#your_action', :as => some_name
Then you'll be able to call it in your controller/views like this:
link_to some_name_path(#my_string_id)
Hope this helps. And take a time to read the guides, it has really lots of useful info, including more details about creating named routes.

Routing without the model name

Using this question and railscast 63 I've got my articles routed to articles/article_permalink.
I'd like them to be accessible without the model name in the url so my-domain.com/article_permalink routes directly to the article. I'd only want this to happen on the show action. Is this possible?
I think you need something like ...
(in routes.rb)
match '/:id' => 'articles#show', :via => 'get'
(needs to be last, or towards the end of the routes as it can match requests intended for other routes)
To change the article_path(...) helpers, "as" might help: http://guides.rubyonrails.org/routing.html#overriding-the-named-helpers
Or you can add a helper for that specific path.
If I understand your question, you want the model tied to the route "articles/article_permalink" to be dynamic based upon which is article is selected from a list?
Would you be open to appending a model ID to the end of the URL as a query string? A more complicated approach would be to have your links POST, with the model ID as a hidden input field. Your controller could determine if it was accessed via get/post, and handle it accordingly, but that doesn't feel right.
Regardless, when the controller action is fired up based upon a request to "articles/article_permalink", it has to know which model to fetch. With HTTP being stateless, something has to be passed in. You could get fancy and write JavaScript to fire one AJAX call, set a session var, and then fire the GET, but that's messy.
I hope I understood the question...

Resources