A question on SO has this url structure:
http://stackoverflow.com/questions/18474799/changing-the-input-value-in-html5-datalist
If we assume that the number section is the ID, the first two sections (after the domain extension) are obtained by simply using the following in routes.rb
resources :questions
The question is already identified by it's ID, so how do we add the (optional) decorating slug in the simplest of manners? Do we need to use a new link helper (and including additional params) or can the 3-section url be resolved elsewhere?
Update:
To focus this question more on the route-handling, let's presume there is already a slug saved on the object (upon creation) as an attribute, e.g. #question.slug
It would really be an advantage if a rule in routes.rb or/and in the controller could enable and handle the optional slug, instead of having to write long link helpers in all views.
resources :questions do
member: title
end
for slug use friendly_id and yes don't forget to have a look at Rails Routing
You might be able to use the to_param method to create a "friendly id".
Something like this:
class Question < ActiveRecord::Base
def to_param
[id, name.parameterize].join("/")
end
end
More info in this gist
If you just want to handle the GET requests in that manner, it's easy to do:
get '/questions/:id/:title' => 'questions#show', as: :question_with_title
resources :questions
This way you can handle incoming URLs with or without the title (just as StackOverflow can -- try it!). You can create urls dynamically with something like:
question_with_title_path(#question.id, #question.title.to_s.downcase.gsub(/ /, '-')
# probably will want to use a method for processing titles into url-friendly format
More at http://guides.rubyonrails.org/routing.html#static-segments
Related
I have a site that currently has URLS that look like this
http://localhost:3000/public/category/1?category_id=1
That the SEO guy has requested be changed to this
http://localhost:3000/(:category_name)-leasing
where (:category_name) is the name of the category referenced by category_id=1 and is appended with "-leasing"
Is it possible to set this up without creating a new column in my category model for a permalink.
Currently I also have this in my routes.rb file:
get ':permalink', :to => 'public#show'
which displays items from the category mentioned above as
http://localhost:3000/item-name-from-permalink
Is this going to prevent a category using the same url structure? will rails be able to distinguish between a :permalink and a (:category_name)-leasing url or will the url need to something like:
http://localhost:3000/category/(:category_name)-leasing
Thanks in advance
class Category < ActiveRecord::Base
def to_param
"#{self.id}-#{self.title.parameterize}"
end
end
will produce url like http://localhost:3000/categories/1-some-good-title
I am little bit confused in using rails route. I need some suggestion about customizing my url.
This is my current url
http://localhost:3000/posts/product/41?product_id=2
and
http://localhost:3000/posts/product/41?model_id=24&product_id=2
This is my link
<%= link_to product_model.name, controller: :posts,action: :product,product_id: params[:product_id],model_id: product_model.id
Logically product should come first in url. But why model prefers first here.
And i need my url something like this
http://localhost:3000/posts/product/41/mobile
and
http://localhost:3000/posts/product/41/mobile/nokia
Since i am not familiar with rails route i didn't write any special coding in my route
Here is the simple route exist
resources :posts
Ok your question here actually contains two different problems, so i will give suggestions to both.
1. Nested resources
Your first problem is to use "nested routes". Rails guide has a long and good article about routes and how to write and use them, including nested routes. You can check it out here: http://guides.rubyonrails.org/routing.html#nested-resources.
However in your situation would the solution look something like this:
resources :category do
resources :sub_category do
resources :products do
resources :models
end
end
end
You can now greate links like this
<%= link_to product_model.name, category_sub_category_product_model_path(#category, #sub_category, #product, product_model) %>
You can see that i have removed posts, see 3. Refactor design to see why. If you really want this as a action on posts, should you however do something like this (but would recommend this!):
get "posts/product/:category_id/:subcategory_id/:product_id/:model_id", to "posts#product", as: :posts_product
This would be used like this in your views:
<%= link_to product_model.name, posts_product_path(#category, #sub_category, #product, product_model) %>
2. Pretty URL's
Your second problem is to use model names instead of id's in your urls. The simpels solution for this is having a unique attribute on your model that you can use instead of id, and then just add a to_param method. Fx for product could we do something like this:
class Product < ActiveRecord::Base
def to_param
name
end
end
Ryan Bates have made a good screencast about this: http://railscasts.com/episodes/63-model-name-in-url-revised. If you want something more flexible should you use the gem Friendly Id. And again does Ryan comes to the rescue with another great RailsCast: http://railscasts.com/episodes/314-pretty-urls-with-friendlyid.
3. Change design
Ok well so this is just my opinion, feel free to ignore it. But their is some bad practices and signs in your examples, so let me just quickly go through what i think you should improve on.
Restful actions
You should, when possible always avoid creating controller actions that is not restful (simply put is the base actions index, show, new, create, edit, update and destroy the only restful actions). In your example does this mean that the product action of the posts controller should be changed to something restful. Why not move it to the product model controller and call it "show"?
Deeply nested resources
You should avoid nesting your routes to deeply. Is it really important to show both the category, the sub category, the product AND the model in your url? Maybe that's how your models are associated internally in your application but why should the user know this? If you don't have a list of subcategories at "/posts/product" and a list of products at "posts/product/41" is there no reason to have so long a route. A rule of thumb is "nest no deeper then two levels", ie. ":category/:sub_category". Further more does short routes mean better SEO.
As i said, feel free to ignore these suggestions, your application would work without these changes. However changing these things would greatly help you structure you code, and keep your codebase clean and maintainable. These rules and principles is not something i have just conjured out of nothing, but very accepted principles in the Rails community. You can google each of these principles or patterns and see a lot of articles and posts on why it's a good idea to follow them, especially when you work with Rails.
Resources
Rails Routing from the Outside In — Ruby on Rails Guides
norman/friendly_id - Github
#314 Pretty URLs with FriendlyId - RailsCasts
#63 Model Name in URL (revised) - RailsCasts
Take a look at the friendly-id gem
There's a great RailsCast about it
Add this to your model inmodel.rb
def to_param
name
end
and then add
#model = Model.find_by_name(params[:id]) to your show method, then you can get the url as you mentioned above.
PS: You Should have name field for Model table in your schema.
I think you are looking for nested routes. Please refer this link http://guides.rubyonrails.org/routing.html#nested-resources
and use to_param method in the model if you want to display model_name instead of id as explained by #Ajay Kumar
def to_param
name
end
where name is the model attribute for that specific model.
Why not a namespace?
namespace :posts do
resources :products
end
This should do I think..
Namespace does not include restful ids into the scope..
I have a question about browser string in rails.
For example i have rails app with routes:
resources :posts
and this resource create :
post/:id
post/21
post/167
post/356
but i create a simple blog and i want to rename ':id' to
post/some-name
post/another-name
post/another-different-name
in post i have title, text field
but i dont know how do this
I know that this can be achieved through manipulation of the :id
can you post some link with detailed answer on this question, or some simple example
You can of course put anything you want in the URL and actually there is railcast about it:
http://railscasts.com/episodes/63-model-name-in-url
It is preferable (read: easier) to also keep model.id in the URL, or it means that post name MUST be unique, otherwise you can put anything you want:
/post/2465-my-pretty-post-name
Also, there is a gem friendly_id and related railcast:
http://railscasts.com/episodes/314-pretty-urls-with-friendlyid
Hope that helps.
Why do you want to change /post/:id ?
You can achieve something like /post/:id/comments
You can do that using nested resources like this in your routes.rb
resources :posts do
resources :comments
end
Check here for more details
http://guides.rubyonrails.org/getting_started.html
If you add the to_param method to the model then you can use that within your URL system.
class SomeModel < ...
def to_param
self.title
end
end
Then inside your controller, setup a filter to fetch the model using the title attribute instead of the ID attribute which is used for the find method.
before_filter :setup_record
def setup_record
#record ||= Record.find_by_title(params[:id])
end
You will have to ensure that your title stays unique and if you change it then you will either have to discard all other previous URLS or keep a history of older names.
Using Rails 3.1.1 and the gem acts_as_tree. I have googled the issue and checked similar questions here at SO (the answers are too old, or irrelevant).
I have a model called articles with a route that today looks like:
resources :articles, :path => '', :only => :show
resources :articles, :path => 'articles', :except => :show
I have three articles: "book", "chapter1" and "chapter2". Where book is parent to chapter1 and chapter2.
Today, my path to each article is: host.com/book, host.com/chapter1 and host.com/chapter2. I want the url path to be host.com/book/chapter1 and host.com/book/chapter2 , i.e. nested routes.
How can I create this in a clean simple manner?
Basically, I want a path that will be host.com/:parent_id/:parent_id/:id with N numbers of :parent_id. Pretty much how Wordpress-articles are routed.
I don't believe route globbers is the solution, but I might be wrong. It seems to give the same result for host.com/:id and host.com/foo/bar/:id which will result in duplicate content.
A)
If you have a solution for the routing and the only problem with it is that you're concerned about duplicate content issues, you could consider adding <link rel="canonical" href="..."> to the pages generated from those requests. It's not bulletproof though, as Google considers it a suggestion.
Not sure if the route globbers solution would take care of generating the URLs with parent IDs though.
B)
You don't need the parent IDs to perform the routing, correct? You just want to include them in the URLs and route those requests the same as if using the URLs like example.com/chapter1, correct?
If you'd consider a solution that's not purely at the Rails level, what about rewriting the URLs on those requests so that /:parent_id/:parent_id/:id becomes /:id before Rails processes it? That would be easier if there was a static prefix, like /articles/:parent_id/:parent_id/:id.
I imagine you'd need to write some helpers to generate the URLs with parent IDs for linking to those resources.
Duplicate Content
Either way, you'll need to generate URLs that include the parent IDs, so duplicate content issues probably aren't too likely if you only link to those resources using those URLs.
You have three "articles"... "book", "chapter1" and "chapter2" all represent same 'resources', named 'articles'. Same 'resource' cannot be nested. If you need nested routes you have to define separately parent resource and child resource. following code spinet may help you
class Book < ActiveRecord::Base
has_many :chapter
accepts_nested_attributes_for :chapters
end
class Chapter < ActiveRecord::Base
belongs_to :book
acts_as_tree :parent_id
end
match '*p1/*p2/*p3/.../*pn' => 'articles#show'
The ... is not literal, just define as many parameters as you need upto n.
URL:
host.com/book/chapter1
params[:p1] = 'book'
params[:p2] = 'chapter1'
params[:p3] = nil
URL:
host.com/book/chapter1/section2/sentence4
params[:p1] = 'book'
params[:p2] = 'chapter1'
params[:p3] = 'section2'
params[:p4] = 'sentence4'
params[:p5] = nil
That'd have to be your LAST route.
I think it would also make any catchall routes inoperable, but they're now commented out in the default routes.rb in Rails 3, If you use them, you'd have to manually specify all routes normally handled by the old style catchall routes.
And, if you have a controller named articles, you could never have a book titled 'articles' same with all your controllers, To be safe you probably have to rename all your controllers, i.e articles becomes X_articles. You could never have a book call X_articles then, and so on....
Totally untested.
What you're looking to do is use Rails for something it isn't made for. No matter what answer you get here, it either won't be RESTful, DRY, or make sense to be used with Active Record. Consider restructuring your idea, or bring your application to another platform if it's not too late.
Source to back up my claim: https://stackoverflow.com/a/174287/628859
Assume that there are Post and Comment models.
class Post < ActiveRecord::Base
has_many :comments
end
class Comment < ActiveRecord::Base
belongs_to :post
end
In config/routes.rb
resources posts do
resources comments
end
In this situation, if we retrieve the comment id 12 of the post id 1, the proper restful routing path will be as follows:
post_comments_path(#comment.post, #comment)
and this will be displayed in the URL box of the client's browser as follows:
post/1/comments/12
What I am concerning in this context is whether there are ways to hide the above url string including ids and replace others expression excluding id data, for exmaple, "post/comments", or not.
If this questions is not significant, although id data are exposed in the query string, I am curious about whether there is any security problem or not.
You may want to checkout a Railscast on displaying model attributes in the url. However, its much more easy to manage your resources keeping the id in the url.
http://railscasts.com/episodes/63-model-name-in-url
Even on the Railscast, you'll find Ryan Bates talking of tricky issues if you do not have the id in the url and simply have, say, name as posts/name-of-post instead of posts/1.
To change the url, all you need to do is override the to_param method that Rails uses to convert the model to a url. However, without passing the id, you'll need to modify your code in other places too.