I added a route in routes.rb:
match 'notifications/:id/mark_as_read' => 'notifications#mark_as_read', :via => :post
mark_as_read is the only action in notifications controller, and that is the only route for notifications
when I should the routes I see
POST /notifications/:id/mark_as_read(.:format) notifications#mark_as_read
I don't know how to get to it, since it doesn't list as something like notifications_mark_as_read_path
did I do something wrong when I added the route, or can I name the route somehow?
found it..
need to name the route.. with :as => 'my_route_name'
Related
In the rails the default behavior shows the id in the url like
http://0.0.0.0:3000/users/1
Now to change the url to show me something other than the id, I know I could put this in model
def to_param
name
end
And then get something like http://0.0.0.0:3000/users/mikey
I am wondering how can achieve a twitter style url. Currently the model name is still showing in the url. Something like this http://0.0.0.0:3000/mikey without the model name
Get the name of the database column storing your users’ names (let’s say it’s ‘name’).
In config/routes.rb add, somewhere above the default route:
match 'users/:name', :controller => 'users', :action => 'show'
Now, in users_controller, find def show and change it to:
#user = User.find_by_name(params[:name])
Lastly, all the id-based urls pointing to your users need to be updated to reflect the name-based change. Like the one your Users index.html.erb file.
link_to #user.name, 'users/#{#user.name}'
Add a route, near the bottom of your routes file (right above your root route!)
get '/:id', :to => "users#show", :as => :friendly_user
This will act as a fall-through route, so /anything that wasn't caught by an earlier route will route to users#show and pass an :id accordingly. You can then use friendly_user_path(#user) to generate links to that user's Twitter-style profile.
Be sure that this is one of the lowest-priority routes, as you wouldn't want a user to be able to sign up with a username like "logout" and replace your /logout page with their profile!
Say I have an object called invoice. In routes.rb I have
resources :invoices do
get "pay"
end
When I run rake routes, the route is generated as
invoice_pay GET /invoices/:invoice_id/pay(.:format) invoices#pay
and the parameter is :invoices_id instead of :id
If I use a match statement:
match "invoices/:id/pay" => "invoices#pay", :via => :get
I get:
GET /invoices/:id/pay(.:format) invoices#pay
It seems to me that the route should be pay_invoice_path(#invoice), however, I have not found suitable documentation on this. Any suggestions?
i think what you are trying to do is
resources :invoices do
get "pay", :on => :member
end
have a look at the guides: http://guides.rubyonrails.org/routing.html
I'm upgrading my app to rails 3, and I am a bit confused about some of the routes. The resourceful ones are easy enough, but how can I set a generic rule for all actions in a specific controller. I tried something like this:
get 'custom/:action/' => {:controller => :custom}
But that didn't work. It seems the new format is "controller#action", but how can I specify the action to be variable?
Also, other than using named routes or resources, is it possible to do shorthand notation to name routes in a specific controller?
i.e. rather than:
get '/tasks', :controller => :home, :action => :tasks, :as => 'tasks_home'
get '/accounts', :controller => :home, :action => :accounts, :as => 'accounts_home'
is it possible to do something a little cleaner, like:
controller => :home do
get :tasks
get :accounts
end
And that would automatically created the named routes?
You can use action as a variable like this:
resource :custom do
match ':action'
end
This will generate
/custom/:action(.:format) customs#:action
custom POST /custom(.:format) customs#create
new_custom GET /custom/new(.:format) customs#new
edit_custom GET /custom/edit(.:format) customs#edit
GET /custom(.:format) customs#show
PUT /custom(.:format) customs#update
DELETE /custom(.:format) customs#destroy
So it will handle your action as a variable URL-s and will add some default CRUD actions as well.
Note that the controller name here is in plural. If you would like to use a route for a controller which name is in singular, use resources instead of resource.
The answer to the second question is almost identical to the first one, use resource:
resource :home do
get :tasks
get :accounts
end
generates:
tasks_home GET /home/tasks(.:format) homes#tasks
accounts_home GET /home/accounts(.:format) homes#accounts
home POST /home(.:format) homes#create
new_home GET /home/new(.:format) homes#new
edit_home GET /home/edit(.:format) homes#edit
GET /home(.:format) homes#show
PUT /home(.:format) homes#update
DELETE /home(.:format) homes#destroy
Note that the matched controller names are in plural again, because of the convention.
Looks like this is related to the persisted field being set to false on nested ActiveResource objects: https://github.com/rails/rails/pull/3107
I currently have the following routes set up for photos:
resources :photos
match 'photos/:user' => 'photos#user', :as => :user_photo
match 'photos/:user/:key' => 'photos#show', :as => :show_photo
Those two match routes give me URLs like:
http://example.com/photos/joe_schmoe
http://example.com/photos/joe_schmoe/123xyz
...similar to the way Flickr formats its URLs.
The problem I'm having, though, is that the photos/:user route is either interpreted as the show method, or if I put those custom routes before the resources then routes like /new get interpreted as the user method.
How can I get around that without having to do a ton of custom routes?
You'll want to put this custom route above the resources :users, so that it is matched first in the routes.
match 'photos/:user' => 'photos#user', :as => :user_photo
resources :photos
Additionally you can disable the show action altogether:
resources :photos, :except => :show
It's not a good idea to mix restful routes with custom match routes on the same resource. As you observed these two routes will intercept each others actions. Your best choice is to pick only one routing system for a resource and stick with it. If you want flickr style routes you should remove the restful route and add the other necessary match routes for new/create/etc you might need. If you desperately want to keep both of these routes You either need to disable show from the rest route with the rest route being on top, or you disable new from the match route while match being on top. You can use regexp to filter out some requests from match like this:
match 'photos/:user' => 'photos#user', :as => :user_photo, :constraints => { :user => /.*[^n][^e][^w].*/ }
This gets ugly really fast tho and I suggest just not using the rest route at all.
So I'm getting a 'No route matches' error, and being new to Rails 3 (and Rails in general), I really don't know what the problem is. Here are the pertinent routes:
resources :users
#...
match 'reset_password(/:reset_password_code)' => 'users#reset_password', :as => :reset_password, :via => :get
match 'reset_password' => 'users#reset_password_submit', :as => :reset_password, :via => :post
The GET method works fine. I get a routing error when the form POSTs that's generated on the get page, which starts like this.
<%= form_for #user, :url => reset_password_url do |f| %>
It looks like it's posting to the right spot, as the url is generated using 'reset_password_url', it's posting to it, and the url looks as it should... anyone have any ideas?
UPDATE
I'm using Rails 3.0.4
I've tried taking out every other route except for the ones that I've mentioned here, and I still can't figure out why it's not working.
Figured it out!
In my form, rails was (correctly) assuming that since I had a user that I was using with the form_for helper, that I wanted to update the user, not make a new one.
Therefore, it was using the PUT method to post my form. To solve the routing problem, I just had to change the last route to:
match 'reset_password' => 'users#reset_password_submit', :as => :reset_password, :via => :put
I only found the issue after using the Web Inspector in webkit to see the whole request, and looked at the _method parameter being sent in.