Short url with Ruby on Rails routes - ruby-on-rails

I am trying to create short url links for books in Ruby on Rails. I want to get something like this: www.domain.com/book123, where book is the controller name (or custom controller name) and 123 is an id of the book.
Right now my routes look as follow:
resources :books, except: [:edit], path: "book" do
put :new, on: :new
member do
get ':id' => 'books#show'
get 'general' => 'books#general'
get 'additional' => 'books#additional'
get 'photos' => 'books#photos'
get 'map' => 'books#map'
end
resources :photos, only: [:create, :destroy]
end
This is what I get: http://localhost:3000/book/40 or www.domain.com/book/40.
I was trying to find similar questions and I found that the only way to achieve this is to use regex. I am new in Ruby on Rails and I want to find the right and efficient way of doing it.
Also, I might be wrong but I've noticed that some of the urls can affect on the website performance, so I don't want to have such problems.
Any help, information or examples will be highly appreciated. Thank you for your help and time.

You could try this route:
get 'book*id' => 'bookscontroller#show'
Check this article: https://www.railsmine.net/2014/10/route-globbing-in-ruby-on-rails.html

As #qdx47 has mentioned you'd better follow convention, but if you must not, I think you can override to_param on book model, like:
def to_param
"book#{id}"
end
and then define routes like
get ':id', to: 'books#show', constraints => { :book_id => /book[0-9]+/ }

I think you can give a try to below gem.
Friendly Id Gem
Then you will be able to generate slug that can be any unique string. By default it will be uuid but you can override it. Follow gem documentation. It will allow you generate routes like http://localhost:3000/books/book123.

In general, I think you would be going against convention and best practices by formatting your route in this way.
With that caveat, you should be able to define a route like so:
get(':book_id', 'books#show', constraints => { :book_id => /book[0-9]+/ })
You would then need to extract the id from the 'book' literal in the controller.

Related

How to change namespace URI in Ruby on Rails?

I'm newbie in RoR and I'd like a bit of help here.
I have the following URI:
http://localhost:3000/abouts/2
And the next in Route:
resources :abouts, only: [:show]
I'd like to show the information of "about/2" in another page, for example:
http://localhost:3000/new_about
Regards!
You can simply map the desired URL to your existing action:
get 'new_about', to: 'abouts#show', id: 2
You can add your own routes in rails. You'd do something like :
get "/new_about" => "controller#action"
I would suggest sticking to the Rails way of doing things though unless it's only a few number of pages and you specifically need them to be named differently.

how to change links to more SEO friendly rails

I have such links in my app
http://localhost:3000/lv/manufacturer_products?manufacturer=Komptech
http://localhost:3000/en/products?category=Shredders
But my friend said that these links are not SEO friendly, tht I have to change them, to
http://localhost:3000/en/manufacturer_products/Komptech
or similair to this
http://localhost:3000/en/products/category/Shredders
But how can I actually change the structure off link without help off any gem ? using routes ?
Thanx
See documentation for namespaces and also this answer on SO.
You could even just do named routes. something like this:
resources :products do
resources :manufacturers
end
which for the index action of manufacturers would return this:
product_manufacturers GET /products/:product_id/manufacturers(.:format) manufacturers#index
and you could then write in routes.rb
match '/:id/products/:name',
:to => 'manufacturers#index', :as => :manufacturers
and when you call it
<%= link_to #manufacturer.name, manufacturers_path({id: #manufacturer.product_id, name: #manufacturer.name}) %>
which would render http://localhost:3000/x/products/Komptech
There is a railscast by Ryan Bates for this and I always follow this,
http://railscasts.com/episodes/314-pretty-urls-with-friendlyid
I can not restrict me to share this ...Once I got an excellent help to optimize the SEO of my site
look into the link
http://complitech.net/seo-basics-high-benifit-for-ruby-on-rails-developer/
Look at the 3rd point got your answer for url
3) Improve your structure of URL
Generally in old fashion the url are unstructured and not directory wise , so make your URL are structured.
example:
www.herrybaseballcards.com/images/baseball/top-ten-baseballcards.html
so in routes
match '/:foldername/:products/:name',
:to => 'products#index', :as => :products
so ignore the Query Based URL Structures

How to shorten a single resourceful Rails route?

So, I have the following in routes.rb:
scope(path_names: { new: "register" }) do
resources :accounts
end
This works, as it generates a /accounts/register route, but would like to change it to simply say /register. I know I could use match "/register" => "accounts#new", but I am wondering if there is a better way to accomplish this, as this would still leave the /accounts/register route "open". I could probably rename it to something obscure by using {new: "pygmy_puff"}, but I am not confident if it's the right approach.
I'd really like to do this right.
Thanks
Try this:
match "/register" => "accounts#new"
# ...
scope(path_names: { new: "register" }) do
resources :accounts, :except => :new
end
In that order.
Personally, I wouldn't sweat the extra route, and use the extra match statement. Looking forward to rails 4, though I think it would be better written with the http method:
get "/register" => "accounts#new"

Rails 3 Finding the right :id in a controller using a specific route

I have my routes arranged so that when visiting the site the :id is displayed before the slug like so
match "/causes/:id/:slug" => "causes#show", :as => :cause, :via => 'get'
But I also have a nested attribute called "post" that belongs to causes like so
match "/causes/:id/:slug/posts" => "causes#posts", :via => 'get', :as => :posts
When I use this, everything works great for the causes, but not for the posts.
If I use
#post = Post.find(params[:id])
in causes or posts controller it always looks for the ID of the causes, and not the :id of the posts. So if the post :id is 9, and the cause :id is 1, and I use
#post = Post.find(params[:id])
it will always look for post[1] and not 9 or whatever the post id really is.
What am I doing wrong? Is there a way to make this work in the routes, or maybe a different way to find the id of a nested object in the controller?
I need the route to be the way I have it set up, :id/:slug...
rake routes information:
cause GET /causes/:id/:slug(.:format) causes#show
edit_cause GET /causes/:id/:slug/edit(.:format) causes#edit
PUT /causes/:id/:slug(.:format) causes#update
posts GET /causes/:id/:slug/posts(.:format) causes#posts
POST /causes/:id/:slug/posts(.:format)
PUT /causes/:id/:slug/posts(.:format) causes#update_post
DELETE /causes/:id/:slug/posts(.:format) causes#destroy_post
causes GET /causes(.:format) causes#index
POST /causes(.:format) causes#create
Any help would be great.
To solve your immediate problem, you'll want to add something like this to routes.rb
# config/routes.rb
match "/causes/:cause_id/:slug/post/:id" => "causes#update_post", :via => 'put', :as => :update_post
And then you can generate the URL in your views like this...
link_to 'Update this post', update_post_path(#cause, #post)
...and access the parameters in your controller as params[:id] (for the post) and params[:cause_id] (for the cause).
More generally, though, the way you are specifying your routes is pretty cumbersome, and I suspect you're making your life harder than it needs to be. If this were me, I would do something like
# config/routes.rb
resources :causes do
resources :posts
end
This would accomplish something pretty close to what you have now, the main difference being that it wouldn't contain slugs. I'm not sure why you need to have both slugs and IDs, maybe you could just identify your causes by their slugs? Stringex is a good gem for generating slugs, and you can set it so that slugs are guaranteed to be unique.
Here is the section of the Rails guide on nested resources
http://guides.rubyonrails.org/routing.html#nested-resources
And here is a Railscast about using slugs with nested resources
http://railscasts.com/episodes/314-pretty-urls-with-friendlyid?view=comments
Hope this helps.
This is because you're using the id of the cause, and if you're doing /causes/:id/posts shouldn't you be doing #posts = #cause.postsanyway?
I would look into the new router syntax for rails 3 if I were you, as there is a nicer way to nest resources http://guides.rubyonrails.org/routing.html
edit:
use the friendly_id gem and nest your resources, to avoid confusion follow REST best practises that resource in question is at the end so
/causes/:slug/posts/:slug

Router for nested resources in a "not usual" Ruby on Rails way

I am using Ruby on Rails 3.0.7 and I am trying to set nested resource routing to make it to work in a "not regular" RoR way.
In my routes.rb file I have
resources :articles do
resources :categories, :only => [:index], :controller => 'articles/categories' # The related controller is Articles::CategoriesController
end
so that I can browse following URLs:
<my_site>/articles/1/categories
<my_site>/articles/2/categories
...
What I would to do is to access new, edit and show controller actions for categories by using the same articles/categories controller used for the nested resource stated above (that is, Articles::CategoriesController) and by accessing these URLs:
<my_site>/articles/categories/new
<my_site>/articles/categories/edit
<my_site>/articles/categories/1
<my_site>/articles/categories/2
...
How can I do that? How I must code the router?
Maybe I can do something by using the router collection method like this
resources :articles do
collection do
# match something here for the Articles::CategoriesController...
end
resources :categories, :only => [:index], :controller => 'articles/categories'
end
but I don't know how to do that.
I'm not real sure what you're trying to do with those routes, so I'm not quite sure how to answer your questions. If your intent is to be able to add a new category for a particular article, or edit all the categories for a particular article, you have to pass an ID for the article. If you're trying to create a new article and a new category all at once, you don't need category in the route, just the article and you can do something like form_for([#article,#category]) in your form and use the build method in your controller. If you can clarify, I might be able to help you further (in other words, it's not hard to construct those routes -- but it depends on what you want to do with them.

Resources