Rails 3 URL without controller name - ruby-on-rails

Suppose I want to have a blog with Rails 3 on my website and it will be the only thing I have on it. I would like to use Rails to implement it but I don't like the URLs Rails produces. I would like URLs like this:
example.com/2012/05/10/foo
I don't want something like that which I know how to do (with to_param):
example.com/entries/2012/05/10/foo
I still want to use the helpers like
new_entry_path(#entry) # -> example.com/new
entry_path(#entry) # -> example.com/2012/05/10/foo
edit_entry_path(#entry) # -> example.com/2012/05/10/foo/edit
destroy_entry_path(#entry)
form_for(#entry)
link_to(#entry.title, #entry)
and so on. I then will have comments and want to make them accessible as their own resources too, like
example.com/2012/05/10/foo/comments/5
and those urls should also be possible to get with the normal helpers:
edit_entry_comment_path(#entry, #comment) # -> example.com/2012/05/10/foo/comments/5/edit
or something like that.
So is it possible to get URLs without the controller name and still use the url helper methods? Just overwriting to_param will always just change the part after the controller name in the url. It would be really helpful to get some example code.

Your routes.rb probably has a line something like this:
resources :entries
which produces routes of the form /entries/2012/05/10/foo.
There exists a :path argument that allows you to use something besides the default name entries. For example:
resources :entries, :path => 'my-cool-path'
will produce routes of the form /my-cool-path/2012/05/10/foo.
But, if we pass an empty string to :path, we see the behavior you're looking for:
resources :entries, :path => ''
will produce routes of the form /2012/05/10/foo.

Related

Rails redirect scoped routes

I have an app with the following scoped routes:
scope "(:locale)", :locale => Regexp.new(I18n.available_locales.join('|')) do
# ...
# lots of routes here
# ...
end
As you can see, the 'locale' is optional here. Both http://myapp.com/en/foo and http://myapp.com/foo end up to the same controller#action. Works great.
Now I want to get rid of the locale in the url, but I want old routes still to work, so simply removing the scope statement won't do. I'd like to redirect old locale based url to be redirected to the non-locale url. Like this:
http://myapp/en/foo redirect to http://myapp/foo
and
http://myapp/foo still to work as it used to do.
So far, I only found a 'redirect' option in the Rails guides for individual routes. But I'd like this to hold for a collection of routes; the routes in my 'scope' block.
Any ideas on how to get this working?
My guess - from a lot of url stripping experiments on a different pattern - something like this would have worked for you:
scope "(:locale)", :locale => Regexp.new(I18n.available_locales.join('|')) do
get '/en/:ccc' => redirect(path: "%{ccc}")
end
The path may need a slash before the variable, and you can of course have a different language code to strip.
The big annoyance here is redirect feeds two separate classes, depending on hash or string - OptionRedirect or PathRedirect. Option redirect lets you do a lot more with variables, as of writing.

Adding a record's attribute to the URL before the ID

I'm trying to add a specific attribute of a record in Rails to the URL from something like:
domain.com/share/5
(where 5 is the record ID) to something like:
domain.com/share/johnsmith/5
where johnsmith is stored in record 5. I'm alternating between these two routes to no success:
get "/share/:name/:id" => "share#show"
resources :share, :only => [:show]
And between these two methods:
share_path(doc.user.name, doc)
share_path(doc)
The show method in the ShareController is pretty standard.
The problem:
Using share_path(doc.user.name, doc) in the view generates a link to /share/johnsmith.5, instead of /share/johnsmith/5.
get "/share/:name/:id" => "share#show" should do the job. But you may have to look at the order of routes in routes.rb, maybe Rails took the wrong route?
Best tip to look at what's happening:
Call the URL in your browser (or using curl or whatever) and then look into your console where your started rails s (or rails server).
There you should see something like this:
Processing by ShareController#show
Parameters: {"id"=>"5", "name"=>"johnsmith"}
Concerning the path methods:
Simply use rake routes, it will tell you which path methods are available.
No idea what happened but it resolved itself with this:
get "/share/:name/:id" => "share#show", :as => :share
share_path(doc.user.name, doc)
I do not get the . and / issue at all. I restarted everything and it was gone.

Custom urls and paths in rails

I have two models: Books and pages in a typical one_to_many relationship.
How can I make the following
page_path(#page)
output this path:
bookname/page/pageid
instead of
page/pageid
If I override the to_param, all I can do is make a path like localhost/page/bookid/pageid but that's not what I want.
Not sure if it's possible to get exactly what you want, but you can make the Page a nested resource under book like this:
resources :books do
resources :pages
end
Then you will get:
localhost/book/bookid/page/pageid
Then you can override `to_param' to get:
localhost/book/bookid-bookname/page/pageid
I'm assuming you mean to have path as /:book_name/page/:id
In routes.rb:
match '/:book_name/page/:id' => "page#show", :as => :page
In the controller you would access params[:id] to get page.id and params[:book_name] to get the name of the book.
I discovered that to have full control over path helpers, you have to override those inside the application_helper.erb file. The following code worked for me:
def pages_path(#page)
#bookpath = Book.find(#page.book_id)
#bookpath + '/page/' + #page.id
end
The helper only creates the path. You still need to link it to a particular action in routes.rb. You may even nest the pages resource inside the books resource. The only important thing is that the path generated by the above helper must be recognizable by the rails application.

Routes with Dash `-` Instead of Underscore `_` in Ruby on Rails

I want my urls to use dash - instead of underscore _ as word separators. For example controller/my-action instead of controller/my_action.
I'm surprised about two things:
Google et al. continue to distinguish them.
That Ruby on Rails doesn't have a simple, global configuration parameter to map - to _ in the routing. Or does it?
The best solution I've is to use :as or a named route.
My idea is to modify the Rails routing to check for that global config and change - to _ before dispatching to a controller action.
Is there a better way?
With Rails 3 and later you can do like this:
resources :user_bundles, :path => '/user-bundles'
Another option is to modify Rails, via an initializer.
I don't recommend this though, since it may break in future versions (edit: doesn't work in Rails 5).
Using :path as shown above is better.
# Using private APIs is not recommended and may break in future Rails versions.
# https://github.com/rails/rails/blob/4-1-stable/actionpack/lib/action_dispatch/routing/mapper.rb#L1012
#
# config/initializers/adjust-route-paths.rb
module ActionDispatch
module Routing
class Mapper
module Resources
class Resource
def path
#path.dasherize
end
end
end
end
end
end
You can overload controller and action names to use dashes:
# config/routes.rb
resources :my_resources, path: 'my-resources' do
collection do
get 'my-method', to: :my_method
end
end
You can test in console:
rails routes -g my_resources
my_method_my_resources GET /my-resources/my-method(.:format) my_resources#my_method
You can use named routes. It will allow using '-' as word seperators. In routes.rb,
map.name_of_route 'a-b-c', :controller => 'my_controller', :action => "my_action"
Now urls like http://my_application/a-b-c would go to specified controller and action.
Also, for creating dynamic urls
map.name_of_route 'id1-:id2-:id3', :controller => 'my_controller', :action => "my_action"
in this case 'id1, id2 & id2 would be passed as http params to the action
In you actions and views,
name_of_route_url(:id1=>val1, :id2=>val2, :id3=>val3)
would evaluate to url 'http://my_application/val1-val2-val3'.
if you use underscores in a controller and view file then just use dashes in your routes file, and it will work..
get 'blog/example-text' this is my route for this controller
def example_text
end <-- this is my controller
and example_text.html.erb is the file
and this is the actual link site.com/blog/example-text
i figured this is works for me, and it's more effective than underscores SEO wise

Rails: Override RESTful paths?

Is it possible to override a RESTful path?
For instance, I have photo_path(photo) which would generate /photos/12345
But I'd like for all uses of photo_path to actually generate URL's like /photos/joeschmoe/12345 (which is the photo's user and the photo id).
Obviously I could just create a new route, but wanted to make sure there wasn't a more RESTful way of doing it.
You could make photos a sub-resource to user's, so you'd have users/joeschmoe/photos/12345 (of course here, your users controller would require the ability to accept a username instead of an id, which is another routing problem to solve but not difficult)
resources :users do
resources :photos
end
Then your controller could maybe call
#photos = Photo.find_by_username(params[:id])
Although I think there are less hacky ways of doing that.
You could also add joeschmoe as a query string parameter.
Or you could make username an optional parameter in the route, so it would be something like
match "/photos(/:username)/:id" => "photos#show"
Or if you want a new named route:
match "/photos/:username/:id" => "photos#show_by_user", :as => :user_photo

Resources