Named routes inserting a . instead of a / - ruby-on-rails

I've been having trouble with named routes in rails 4 (Named route for non resource nesting).
I've moved onto something else, but still struggling with the same problem of named routes for non resource urls.
This is my route from rake routes:
GET /messages/:id/report/:reply_token(.:format) messages#report
messages POST /messages(.:format) messages#create
and my routes.rb
resources :messages, only: [:create] do
member do
get 'report/:reply_token', :action => 'report'#, :as => :message
end
end
Because of the problem I had in my post linked at the top, I'm trying to get a url to the /messages/:id/report/:reply_token route by doing the following:
"#{messages_url(#message, :host => "localhost:3000")}/report/#{#message.reply_token}"
But it's giving me this:
http://localhost:3000/messages.110/report/6bBw22TdaRYcQ3iVzW1ZwA
Why is there a . between the 'messages' and the '110' (message_id)?
Instead of #message, I've also tried #message.id in the messages_url(). I've also tried this: report_message_path(message_id: #message.id, reply_token: #message.reply_token) but got the same error as in my question linked above. I've also tried message_url() instead but it gives undefined method 'message_url'.

You are mixing up routes. messages_url is to generate a URL for create action which does not have ID in its route. Rails assumes 110 is the format and uses the second route (which is named as messages)
messages POST /messages(.:format)
As a solution, name your route like this and also add show action
resources :messages, only: [:create,:show] do
member do
get 'report/:reply_token', :action => 'report' , :as => :custom_message
end
end
And,
custom_message_url(#message, :host => "localhost:3000")
More about naming routes here.
Answerd here already - Rails _path helper generating path with format not id

Related

How to remove /posts/ from URL?

How can I also show a blog post without /posts/ in the URL?
http://www.anthonygalli.com/posts/i-walk-the-line
http://www.anthonygalli.com/posts/50-shades-of-galli
http://www.anthonygalli.com/posts/tips-for-regaining-momentum
Shortened Version (Goal of Question):
http://www.anthonygalli.com/i-walk-the-line
http://www.anthonygalli.com/50-shades-of-galli
http://www.anthonygalli.com/tips-for-regaining-momentum
I have post as a MVC.
routes.rb
resources :posts
get 'about' => 'posts#about'
get 'feed' => 'posts#feed'
get 'subscribe' => 'posts#subscribe'
Change your routes.rb to:
resources :posts, path: '/' do
collection do
get 'about'
get 'feed'
get 'subscribe'
end
end
For documentation on Rails routing check: http://guides.rubyonrails.org/routing.html
Your routes should be updated to look something like this:
resources :posts
get 'about' => 'posts#about'
get 'feed' => 'posts#feed'
get 'subscribe' => 'posts#subscribe'
get ':id' => 'posts#show', :as => :post_by_slug
That as option will be important for linking to your new route if you want to link to the /post/-less paths:
<%= link_to post.title, post_by_slug_path(post) %>
P. S. I believe that the new route will need to be listed last in your routes so that the routes before it can have precedence. (Otherwise, trying to visit /about would try to load a post with a slug named about instead of the posts#about action. You should try this and see if that's true.)
Resource generates the standard CRUD urls, so you have to specify the posts route specifically. Something like this
get '/desired-url' => 'posts#index'

Ruby on Rails routing for variable controller

I have a URL I want to be able to redirect to.
Something similar to:
"http://localhost:3000/username/admin/page".
I have a match in routes.rb as:
match ':account/admin/:page' => "admin#index"
I have redirect code:
redirect_to :controller => account.username, :action=>"admin", :page=>"index"
This, however comes up with a routing error:
No route matches {:action=>"admin", :controller=>"sdunn", :page=>"index"}
I know what I have done is wrong, but how can I fix this?
Many thanks.
Route is expecting 2 parameters, first one is :account, second is :page, i think you are only passing :page. I would add :as => 'some_name' to your route and then use _path :
routes.rb
match ':account/admin/:page' => "admin#index", :as => 'my_route'
controller:
redirect_to my_route_path(#user, #page)
my_route_path could be something different depending on your exact route file, so use
rake routes | grep my_route
to see exact name, then add _path to the end.

Rails routing. Singular resource

I've got Rails routing problem. I would like to use singular resource with user controller but it doesn't work as I expected. Here is the fragment of my routes.rb file:
scope :module => "frontend" do
root :to => "home#index"
resource :user, :controller => "user"
get "/sign_up" => "user#new"
get "/sign_in" => "user#sign_in"
get "/sign_out" => "user#sign_out"
post "/authenticate" => "user#authenticate"
resources :articles
resources :article_categories
end
I thought it will work when I'll use for example "/user" or "/user/new" URL but it didn't. I get a routing error:
No route matches {:controller=>"frontend/user"}
The 'rake routes' command output is:
user POST /user(.:format) frontend/user#create
new_user GET /user/new(.:format) frontend/user#new
edit_user GET /user/edit(.:format) frontend/user#edit
GET /user(.:format) frontend/user#show
PUT /user(.:format) frontend/user#update
DELETE /user(.:format) frontend/user#destroy
sign_up GET /sign_up(.:format) frontend/user#new
sign_in GET /sign_in(.:format) frontend/user#sign_in
sign_out GET /sign_out(.:format) frontend/user#sign_out
authenticate POST /authenticate(.:format) frontend/user#authenticate
What is interesting, when I add route for index action in user controller, like this:
scope :module => "frontend" do
root :to => "home#index"
resource :user, :controller => "user"
get "/user" => "user#index"
get "/sign_up" => "user#new"
get "/sign_in" => "user#sign_in"
get "/sign_out" => "user#sign_out"
post "/authenticate" => "user#authenticate"
resources :articles
resources :article_categories
end
...it works!
But index action is not defined in user controller!
'rake routes' command returns double line for GET /user
GET /user(.:format) frontend/user#show
GET /user(.:format) frontend/user#index
so I suppose that's not the solution. Other actions assigned to '/users' URL don't work.
Is it necessary to define the route for the index action like
get "/controller_name" => "controller_name#index"
What am I doing wrong?
Defining a singular resource in your routes will not generate a route to an index action by design. The singular resource implies you're always going to lookup this resource without specifying an ID and consequently a get to index for a singular resource just doesn't make logical sense. So, a GET to your url "/user" will route to a show action for that singular resource and not an index.
EDIT: Since your issue isn't obvious, I'd simplify your routes until you can at least hit the controller you'd expect and then build from there.
config/routes.rb
scope :module=>"frontend" do
resource :user
end
#ensure you don't have any other user routes listed before this that would match "/user".
app/controllers/frontend/users_controller.rb
module Frontend
class UsersController < ApplicationController
def show
raise "in frontend/show"
end
end
end
Thanks a lot for help! I found the bug.
The routing error was caused by the following line of the layout html file
<%= auto_discovery_link_tag(:rss, {:action => "index"}, {:title => "RSS"}) %>
I was looking for errors in the erb view files but I forgot about the layout.
I must remember to check the entire view layer in such situations.

How to declare a rails resource with a parameter for new action?

I have a model named Entree for which the new action needs a parameter, the id of another model named Cave. I don't want to nest Entree in Cave since Cave is already nested.
What I did was declaring the resource Entree as follow in routes.rb:
resources :entrees, :except => [:new]
match "/entrees/new/:id", :to => "Entrees#new", :as => 'new_entree'
That works, but the problem is when there's an error in the create action, I want to display the page again with the invalid input. But since there's no new action, I must do a redirect_to new_entree_path, which does not keep the user input.
I have tried the following (simplest) route:
resources :entrees
But then the path http://localhost:3000/entrees/new/32 returns an error:
No route matches [GET] "/entrees/new/32"
The question is, how can I declare the Entree resource in the routes file with a parameter for the new action ?
I'm not sure if that's a hack or not, but the following works and seems cleaner than 2-levels nesting.
resources :entrees, :except => [:new] do
collection do
get 'new/:id', :to => "entrees#new", :as => 'new'
end
end
Now I can do a render "new" instead of a redirect_to.
I must say that I must have asked my question wrongly, my bad.
Rails has a route helper called path_names that does this:
resources :entrees, path_names: { new: 'new/:id' }
To improve gwik 's solution (which in fact didn't work for me):
resources :things, except: [:new] do
new do
get ':param', to: 'things#new', as: ''
end
end
It gets you new_thing_* helpers (instead of new_things_*) for free.
If you want to use Rails resource routes, you will have to nested them according to how they work
resources :caves do
resources :entrees
end
to get the route /caves/70/entrees/new
Otherwise, you are in a world of creating manual match routes.
match "/entrees/new/:id", :to => "entrees#new", :as => 'new_entrees'
I do not understand why you are forced to use a redirect? The new_entrees route is valid. You will not be able to use the form_for helper, since it is not a resource, but the form_tag helper will work.
UPDATE: Render and Route
The Route does not directly change what view is rendered in the Controller. That is determined by the controller itself. Render examples:
render :new will render the new action's view
render 'entrees/new' will render the entrees/new template
I found this generates the correct new_thing_path method not new_things_path as Antoine's solution.
resources :things, :except => [:new] do
with_scope_level(:new) do
get 'new/:param', :to => "things#new", :as => ''
end
end

Rails 3 route appends _index to route name

I am migrating a Rails 2.3.8 version to Rails 3.0 and so ive rewritten my routes file. When i list the routes using rake routes, i see some route names have _index appended to them. I cant figure out why this is.
Relevant routes:
Rails 2.3.8:
map.namespace "tracker", :path_prefix => "" do |planner|
planner.resources :planner, :collection => {:step1 => :get,
:add => :get,
:unsubscribe => [:get, :post] }
end
Rails 3.0 route:
namespace "tracker", :path => "" do
resources :planner do
collection do
get :step1
get :add
get :unsubscribe
post :unsubscribe
end
end
end
Output from rake routes
Rails 2.3.8
step1_tracker_planner GET /planner/step1(.:format)
add_tracker_planner GET /planner/add(.:format)
unsubscribe_tracker_planner GET /planner/unsubscribe(.:format)
POST /planner/unsubscribe(.:format)
Rails 3.0
step1_tracker_planner_index GET /planner/step1(.:format)
add_tracker_planner_index GET /planner/add(.:format)
unsubscribe_tracker_planner_index GET /planner/unsubscribe(.:format)
POST /planner/unsubscribe(.:format)
Any ideas as to why this _index is being added would be much appreciated.
It is because your resource is named :planner instead of :planners that Rails decided to add the _index to any collection nested underneath. My guess it is there for readability.
The action named in the collection normally translates to a verb, so I can see why this makes sense. Take the typical photos resource example given in the routing docs:
resources :photos do
collection do
get 'search'
end
end
search_photos GET /photos/search(.:format)
But if instead we called the resources 'photo'...
resources :photo do
collection do
get 'search'
end
end
search_photo_index GET /photo/search(.:format)
In the first case, you search the "photos", and in the second case you search the "photo index".
You should be using either resource :planner either resources :planners depending on what you need. To learn about singular resource and it differences check out Rails Guides.
Following on from Semyon Perepelitsa's response, note that resource :planner expects the controller's name is PlannersController, whereas resources :planners expects PlannerController.
If you don't want to rename your controller when changing from resources to resource, you can override the default by specifying resource :planner, controller: :planner.

Resources