how to change links to more SEO friendly rails - ruby-on-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

Related

Short url with Ruby on Rails routes

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.

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

Rails "pretty URLs", using entries/23 or 2011/07/some-post-slug-here for creating URLs via helpers

I'm attempting to create "pretty URLs" for linking to posts in a blog. I want to maintain access to the blog entries via entries/23 and 2011/07/some-post-slug-here as I only generate a slug once an entry has been published (just in case the title of the posts changes, and, though not a strict requirement, I would prefer to be able to edit/delete posts via the entries/23 style URL. Currently, the appropriate part of what I have in my config/routes.rb:
root :to => 'entries#index'
resources :entries
match ':year/:month/:slug' => 'entries#show', :constraints => {
:year => /[0-9][0-9][0-9][0-9]/,
:month => /[0-9][0-9]/,
:slug => /[a-zA-Z0-9\-]+/
}, :as => :vanity_entry
and I use this (in my application helper) function for creating the links:
def appropriate_entry_path entry
if entry.published
vanity_entry_path entry.published_on.year.to_s, entry.published_on.month.to_s, entry.slug
else
entries_path entry
end
end
def appropriate_entry_url entry
if entry.published
vanity_entry_url entry.published_on.year.to_s, entry.published_on.month.to_s, entry.slug
else
entries_url entry
end
end
Basically, I check if the article is published (and therefore has a slug) and then use that URL/path helper, or otherwise use the default one.
However, when trying to use this, I get the following from Rails:
No route matches {:slug=>"try-this-one-on-for", :month=>"7", :controller=>"entries", :year=>"2011", :action=>"show"}
I have tried a few different solutions, including overriding to_param in my Entry model, however then I would have to create match routes for the edit/delete actions, and I would like to keep my routes.rb file as clean as possible. Ideally, I would also love to lose the appropriate_entry_path/appropriate_entry_url helper methods, but I'm not sure that this is possible?
Is there any thing I am missing regarding routing that might make this easier and/or is there any specific way of doing this that is the cleanest?
Thanks in advance.
You might want to take a look at friendly_id. It's a gem for creating seo friendly slugs :)
I found the issue with what I had been doing, the regex for :month in the route wanted two numbers, whereas I was only passing in one number. Anyways, I decided that the URLs look nicer (in my opinion) without the month padded to 2 digits, so I updated my route accordingly.

Reducing redundancy in Rails routes and url helper

I want to add article's title to its url similarly to SO URLs. I was suggested to use the following setup in answer to my another question
# routes.rb
match '/articles/:id/:title' => 'articles#show', :as => :article_with_title
# articles/index.html.erb
link_to article.title, article_with_title_path(article, :title => article.title.downcase.gsub(/[^a-z0-9]+/,' ').strip.gsub(/\s+/,'-'))
It works, however I find it a bit redundant. Is there a way to make it nicer? What about an additional universal method to handle multiple routes?
match '/articles/:id/:title' => 'articles#show'
match '/users/:id/:name' => 'users#show'
etc.
Remarks:
Currently the following routes work fine: /article/:id/:action, /article/:id/:title with a condition that article cannot have titles edit, show, index, etc.
I believe friendly_id is unnecessary here, since the routes contain :id explicitly.
As I see, SO uses different routes for questions /question/:id/:title, /posts/:id/:action and for users /users/:id/:name, /users/:action/:id
Just override to_param in your models. Untested example from memory:
def to_param
self.id + "-" + self.name.parameterize
end
this approach means you don't have to change the router, and can also keep using Model.find(params[:id]) or similar.
Basically what the Railscast mentioned in another answer does, and the core of what friendly_id does too.
Ryan Bates did an excellent screencast on using the model's name, or any other attribute, in the url instead of the id.

Rails 3 Routing resources scoped to a username

I have a basic understanding of rails routing, but nothing too advanced. So far I've gotten by using the RESTful resource based routes and a few custom named routes.
I am nearly done my app now though and I wanted to make some pretty urls.
In my app, each user has many pages. What's the best way to make the URL's look like www.sitename.com/username/page_name?
This will route to the pages controller's show action. Params hash includes :username and :page_name.
match "/:username/:page_name" => "pages#show"
Remember to put it last or it will match pretty much everything.
I'm not quite sure what you're using this for, but something like this might work in your routes file:
resources :users do
get 'page_name'
end
Which will produce: users/:id/page_name
You might want to check out the Railsguide on routing.
What you are looking for is a member route (section 2.9.1).
resources :users do
member do
get :cool_page
end
end
Will result in /users/:id/cool_page

Resources