Rails Routing: How to route to a specific controller/action/id? - ruby-on-rails

I think this should be a simple question. I would like to route a URL of the form:
http://mywebsite.com/my_special_tag
to a specific controller/action pair with a specific id, e.g.
http://mywebsite.com/user/post/13
(where 13 is the id I want to pass into the controller/action).
Note also that I don't want to redirect, just want to render.
Is there an easy way to do this in Rails 3?
Thanks!

Assuming your know specifically which URL you want to have rendered to, you can explicitly match to the target in your routes:
# config/routes.rb
match 'my_special_tag' => 'user#post', :defaults => {:id => 13}
Note that this necessarily requires that you have a post action within a UserController (note that the names are singular, as they are in your desired path).

You simply need a table like this:
tags table:
id | post_id | tag
-------------------
1 | 13 | my_special_tag
And then you need a before_filter, that takes that tag and checks the database for the post_id.
You'd also need a wildcard route that looks something like this: Rails 3.1 - in routes.rb, using the wildcard, match '*' is not catching any routes
Start with that and then let us know when you have more specific questions and we can help you better.

If you check your routes you should get the syntax for a user post route, if you have defined the nested route correctly.
To alias the route, you can define a specific id for a particular match like so:
match '/special_tag' => 'posts#index', :defaults => { :id => '5' }
Update
To clarify, the above should only be used for a couple of specific pages you'd like to alias a route for. If you want to provide a more user friendly link to each user post page, I'd recommend something like https://github.com/norman/friendly_id which allows you to have routes like
http://example.com/states/washington
instead of:
http://example.com/states/4323454

Related

Rails routing: Treating hardcoded path as a parameter?

I'm new to Rails, and after reading some of the Rails Routing documentation, I still can't figure out why my path is being treated as such:
With the following examples, Rails complains that it is unable to find a Movie whose id is equal to "inception", even though I am trying to pass along an id parameter.
(The controller#action to which I am routing is of the resources-type show).
routes.rb
1: get 'movies/inception' => "movies#show", :id => 6
2: get 'movies/inception' => 'movies#show', defaults: {id: 6}
(These two lines are obviously tried separately.)
Error
1:Couldn't find Movie with id=inception
2: app/controllers/movies_controller.rb:16:inshow'
3: {"id"=>"inception"}
Why is the inception-part of the matched url treated as a variable even when I'm not prefixing it with : and how do I make a hardcoded url point to a object#show-action with a hardcoded id?
Looks like you taked into issue with routes priority:
Not all routes are created equally. Routes have priority defined by the order of appearance of the routes in the config/routes.rb file. The priority goes from top to bottom. The last route in that file is at the lowest priority and will be applied last. If no route matches, 404 is returned.
So, I suppose, that you had defined
resources :movies
before
get 'movies/inception' => "movies#show", :id => 6
get 'movies/inception' => 'movies#show', defaults: {id: 6}
And your routes were not overwritted.
Just see your last question. Uses this route form, instead of yours:
get 'movies/inception/(:id)' => 'movies#show', defaults: {id: 6}
My guess is you have a line something like
resources :movies
If this is the case, then it is creating the standard get show route of movies/:id
If this line is above your hard-coded route then it would take precedence. The lines at the top of the routes file take precedence over anything below it
A couple of things that may help you on your rails journey. From the command line, run
rake routes
That will spit out all available routes
Something you may want to consider if you are looking to do this:
Check out the friendly_id gem
"It allows you to create pretty URL’s and work with human-friendly strings as if they were numeric ids for ActiveRecord models." such as /movies/inception

Submit a form to a Rails route with a dynamic segment

I have a route that looks like
match 'solar_systems/:planet_num/:moon_num' => 'solar_system#moon', :as => :moon
I'd like to have a form with a select box for planet number and moon number and have it submit to this route. However I cannot use moon_path because it will have an error if the dynamic parameters are not included in it like this moon_path(4, 1). Is what I want even possible? If so, what do I give to the form tag for the route?
You don't have to use the routing helper methods, and here you can't since at the time of rendering your form you do not know the required parameters. You do, however, know the controller and action, which is really all that's needed for the destination URL. So this should work:
= form_tag('/solar_systems/moon') do
= select_tag(:planet_num, ...
= select_tag(:moon_num, ...
This should render the form tag. To process the request, you will also have to add another route so the right controller action is called:
match 'solar_systems#moon' => 'solar_system#moon', :via => :post
Or, if it makes more sense in the context of your application, you could modify your existing route to make the parameters optional:
match 'solar_systems(/:planet_num(/:moon_num')) => 'solar_system#moon', :as => :moon
See this Rails guide for more details on non-resourceful routes.
If you use this params on controller you need to specified what params is each one, btw in you helper you need to do something like this
moon_path(planet_moon: 4, moon_num: 1)
Cheers!

Rails 3 URL without controller name

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.

What does a member and collection route mean? [duplicate]

This question already has answers here:
difference between collection route and member route in ruby on rails?
(5 answers)
Closed 9 years ago.
Reading this: http://guides.rubyonrails.org/routing.html#adding-more-restful-actions
What does it mean to add a 'member route'?
or do add a route to the collection?
What is a member and a collection when talking about routes?
They're both ways to add additional actions to a resource-based route in Rails.
A member route requires an ID, because it acts on a member.
A collection route doesn't require an ID because it acts on a collection of objects.
I like to think of them in terms of RESTful URLs. Consider the basics for a resource/model Foo
GET /foo # FooController#index
GET /foo/:id # FooController#show
GET /foo/new # FooController#new
POST /foo # FooController#create
GET /foo/:id/edit # FooController#edit
PUT /foo/:id # FooController#update
DELETE /foo/:id # FooController#destroy
Notice how:
Some routes have :id placeholders for Foo.id, and so refer to a specific Foo
Some routes have no :id, and thus refer to all Foos (and/or no specific foo, as in #new and #create)
Some routes (index/create, show/update/destroy) have the same URL, and use HTTP methods to differentiate between them
Some routes (edit/show) are basically the same (method & URL prefix) except for a different suffix (including "no suffix") at the end.
Member routes and collection routes let you add additional routes/actions using the same techniques as I listed above.
A member route adds a custom action to a specific instance using the URL suffix and HTTP method you provide. So, if you had a member route declaration of :member => { :bar => :get }. you'd get an additional route of:
GET /foo/:id/bar # FooController#bar
Note how it overloads GET /foo/:id in the same way that `edit' does. This is how you'd implement a "delete" action that provides a UI for the "destroy" action.
Similarly, a collection route adds an overload to the collection and/or a non-specific instance (it's up to you to decide exactly what it implies). So, if you declared :collection => { :baz => :get }, you'd get an additional route:
GET /foo/baz # FooController#baz
...in very much the same way as new.
You can also customize the HTTP method.
For example, I just recently had a project where I needed a "reply" action on a Comment. It's basically the same idea as Comment#create (which uses POST), except that it's in reference to a specific parent Comment. So, I created a member route: :member => { :reply => :post }. This gave me:
POST /comment/:id/reply # CommentController#reply
This keeps the routes restful while still expanding upon the basic 7 actions.
The built in member routes are show, edit, update and destroy, since they handle an individual record. index would be a collection route as it returns a collection of records.
So it really depends if you want to do something with a single record (member) or multiple records (collection).
The url helpers reflect singular (member) and plural (collection). For example:
This is a member:
person_path(#person)
This is a collection:
people_path()
If you define a custom collection path, it could look like this in your routes.rb:
resources :people do
member do
put :make_manager
end
collection do
get :show_managers
end
end
To make somebody a manger:
make_manager_person_path(#person)
To list all managers:
show_managers_people_path()
I don't think that the route "cares" if you use it differently, but this is the Rails way. It will make your code easier to read and other coders will have it easier to understand and maintain your code.

What is the best way to deal with Vanity URL helpers in Rails 3?

I have a web application I am working on with Rails 3 and I have just implemented some basic Vanity URL paths to existing resources in the application. What I am looking to do is to not have to explictly build the urls on the user's profile page for the resources that are available, e.g. I would like to be able to build a URL with link_to in the view in the format of:
typealoud.com/:user_id/:thread_id/:comment_id
And not what the standard nested resource helpers give me, something like:
typealoud.com/threads/:thread_id/comments/:comment_id
Should I do this myself as a URL helper, or is there an existing gem?
To do this, I would put this at the top of my routes:
match ':user_id/:thread_id/:id', :to => "comments#show"
I've changed comment_id in this example to id because it's "The Rails Way" that the last id parameter is simply called id. It also results in shorter code.
If you wish to have a routing helper for it use the :as option:
match ':user_id/:thread_id/:id', :to => "comments#show", :as => "comment"
Then you can use comment_path/comment_urlto access the route, but you must pass in three arguments to it, each of them being an object or an id of an object.

Resources