customize rails url with username - ruby-on-rails

I want to copy the twitter profile page and have a url with a username "http://www.my-app.com/username" and while I can manually type this into the address bar and navigate to the profile page I can't link to the custom URL.
I think the problem is in the routes - here's the code in my routes.rb
map.connect '/:username', :controller => 'users', :action => 'show'
Also, I have Question and Answer models and I want to link to them with the customized URL like so:
http://www.my-app.com/username/question/answer/2210

There's nothing wrong with your route. Just remember to define it at the end, after defining all other routes. I would also recommend using RESTful routes and only if you want to have better looking URLs use named routes. Don't use map.connect. Here's some good reading about Rails routes.
Here's how this could look:
map.resources :questions, :path_prefix => '/:username' do |question|
question.resources :answers
end
map.resources :users
map.user '/:username', :controller => 'users', :action => 'show'
Just a draft you can extend.

To create urls you need to define to_param method for your user model (read here).
class User < ActiveRecord::Base
def to_param
username
end
end

I know this questions is old but it will help someone.
You could try the below. I've used it in a rails 4 project and all seems to be working great. The reason for the as: :admin is I also had a resources posts outside of this scope. It will add a admin to the helper calls e.g. admin_posts_path
scope ":username", module: 'admin', as: :admin do
get '', to: 'profiles#show'
resources :posts
end

I have used like this
In View part
portfolio.user.name,:id =>portfolio) %>
and in rout.rb
map.show_portfolio "portfolios/:username", :action => 'show_portfolio', :controller => 'portfolios'

Related

Rails 3 vanity URLs with url_for integration

I would like vanity URLs for the #show action on one of my controllers. I've setup this route:
match "/:username" => "users#show", as: :show_user
I would really like to be able to use this vanity URL with the standard way to link to a user show, like so:
link_to("foo", user)
Thanks!
Jesse Wolgamott has the right idea but a couple notes...
this should go at the bottom of routes.rb so that it doesn't clobber any other routes
resources :users, :path => '/'
UsersController#show
#user = User.where(:username => params[:id])
One (slightly verbose) way to do this with your current route setup is
link_to "foo", show_user_path(user)
Alternatively,
You could name your route 'user instead' of 'show_user'. And then override the provided show_user_url(user) helper to use user.username instead of user.id
Under the covers link_to calls polymorphic_url, which calls build_named_route_call you could monkey-path build_named_route to call your custom route instead of the regular user_url.
Unfortunately, there is no public api/configuration to make this happen cleanly.
routes.rb
resources :users, :path => '/'
user.rb
def to_param
username.parameterize
end
If there is a username of Bob, then <%= link_to user.username, user%> will create
Bob

Rails routing help

I want the url of a user post to be like this:
example.com/users/username/post-name
How should I set this up?
Currently, the post model contains:
def to_param
name.parameterize
end
(to hyphenate the post name accordingly)
routes.rb contains:
map.resources :users
map.resources :posts
Preferably, I would like to say post_path(post) and this would generate the appropriate path for me by finding the post.user automatically.
What do I need to do to make this happen?
Also added
map.resources :users do |user|
user.resources :posts
end
One way more:
map.resources :users do |user|
user.connect ':name/:action', :controller => 'posts', :defaults => {:action => 'show'}
end
Available routes:
example.com/users/username/post-name
example.com/users/username/post-name/edit (any action)
Hi To make your application recognize routes like
example.com/users/username/post-name
you should add to your routes.rb
map.connect 'users/:username/:post', :controller => "users", :action => "test"
Then you can access params[:username] and params[:post] inside your controllers test action You should define it after map.resources :users but before map ':controller/:action/:id' but you must write your own helper then
That to_param looks okay, but the builtin helpers don't link to nested resources like you want, you'd have to use user_post_path(user, post). Ofcourse, you could write your own post_path helper method which does work the way you want.
def post_path(post)
url_for [post.user, post]
end

Can controller names in RESTful routes be optional?

With a standard map.resource routing mechanics and several nested resources the resultant routes are unnecessarily long. Consider the following route:
site.org/users/pavelshved/blogs/blogging-horror/posts/12345
It's easy to create in routes.rb, and I'm sure it follows some kind of beneficial routing logic. But it's way too long and also seems like it's not intended to be human-readable.
A nice improvement would be to drop controller names, so it looks like:
site.org/pavelshved/blogging-horror/12345
Clear, simple, short. It may become ambiguous, but in my case I'm not going to name any user "users", for instance.
I tried setting :as => '', but it yields routes like this: site.org//pavelshved//blogging-horror//12345 when generating them by standard helpers.
Is there a way to map resources in such a way, that controller names become optional?
You're looking for the :path_prefix option for resources.
map.resources :users do |user|
user.resources :blogs do |blog|
blog.resources :posts, :path_prefix => '/:user_login/:blog_title/:id'
end
end
Will produce restful routes for all blogs of this form: site.org/pavelshved/bogging-horror/posts/1234. You'll need to go to a little extra effort to use the url helpers but nothing a wrapper of your own couldn't quickly fix.
The only way to get rid of the posts part of the url is with named routes, but those require some duplication to make restful. And you'll run into the same problems when trying to use route helpers.
The simplest way to get what you want would be to create a route in addition to your RESTful routes that acts as a shorthand:
map.short_blog ':user_id/:blog_id/:id', :controller => 'posts', :action => 'show'
You'll have to change the URL bits to work with how you're filtering the name of the user and the name of their blog. But then when you want to use the shorter URL you can use all the short_blog_* magic.
Straight out of the default routes.rb:
map.connect 'products/:id', :controller => 'catalog', :action => 'view'
You could write:
map.connect ':user_id/:blog_id/:id', :controller => 'posts', :action => 'show'
But be sure to include that in the very end of the file, or it will try to match every three levels deep url to it.
Try this
map.pavelshved '/pavelshved/', :controller => :users, :action => view or
map.pavelshved '/:id', :controller => :users, :action => show do | blogs|
blogs.bloging '/:id', :controller => :blogs, :action => show do | post|
post.posting '/:id', :controller => :posts, :action => show
end
end
I hope it work :)
Google "rails shallow routes" for information about this.

How do I route user profile URLs to skip the controller?

Right now my user profile URLs are like so:
http://example.com/users/joeschmoe
And that points to the show method in the user controller.
What I'd ideally like to do is offer user profile URLs like this:
http://example.com/joeschmoe
So, what sort of route and controller magic needs to happen to pull that off?
I disagree with what jcm says about this. It's not a terrible idea at all and is used in production by the two biggest social networks Facebook and MySpace.
The route to match http://example.com/username would look like this:
map.connect ':username', :controller => 'users', :action => 'show'
If you want to go the subdomain route and map profiles to a URL like http://username.example.com/, I recommend using the SubdomainFu plugin and the resulting route would look like:
map.root :controller => 'users', :action => 'show' , :conditions => {:subdomain => /.+/}
These broad, catch all routes should be defined last in routes.rb, so that they are of lowest priority, and more specific routes will match first.
I also recommend using a validation in your User model to eliminate the possibility of a user choosing a username that will collide with current and future routes:
class User < ActiveRecord::Base
validates_exclusion_of :username, :in => %w( messages posts blog forum admin profile )
…
end
This does not make sense unless you have no controllers. What happens when you want to name a controller the same as an existing user? What if a user creates a username the same as one of your controllers? This looks like a terrible idea. If you think the /user/ is too long try making a new custom route for /u/
So your custom route would be...
map.connect 'u/:id', :controller => 'my/usercontroller', :action => 'someaction'
In routes.rb this should do the trick:
map.connect ":login", :controller => 'users', :action => 'show'
Where login is the name of the variable passed to the show method. Be sure to put it after all other controller mappings.
Well, one thing you need is to ensure that you don't have name collisions with your users and controllers.
Once you do that you, can add a route like this:
map.connect ':username', :controller => 'users', :action => 'show'
Another thing people have done is to use subdomains and rewrite rules in the web server, so you can have http://joeshmoe.example.com
In Rails 4 to skip controller from url you have to do add path: ''.
resources :users, path: '' do
end

Giving a nested route an alias in Rails

If I want to provide an alias for a controller, I can use map.resources :rants, :controller => 'blog_posts' yoursite.com/rants points to the blog_posts controller fine.
How do I give an alias to a nested resource, for example yoursite.com/users/5/rants ?
You may want to try:
map.resources :rants, :controller => 'blog_posts'
map.resources :users do |users|
users.resources :rants, :controller => 'blog_posts'
end
This will give you the yoursite.com/users/5/rants/ url that you are looking for and it will generate the handy methods (for example: users_rants_path(#user))
Hope this helps.

Resources