How to define a custom path in rails? - ruby-on-rails

I have a User model. If I do:
def my_action
#user = User.new
end
then
<% form_for(#user) do |f| %>
I get
undefined method `users_path' for #<ActionView::Base:0x1b4b878>
Which make sense because I haven't mapped it going map.resources :users... but I don't want to do it this way because I don't need all the resources.
How can I just define this user_path method in my routes?

Since I came here looking for a way to create helpers in routes.rb, here is the way to do it:
get '/users/:id/' =>'users#show', :as => :user

You can also customize restful routes. For example in my application only the index and show actions are appropriate for certain controllers. In my routes.rb file I have some routes like this:
map.resources :announcements, :only => [:index, :show]
You can also use :except if that's more appropriate.

You can map custom routes in your routes.rb file like this...
map.users '/users', :controller => 'user', :action => 'index'
This gives you the users_path helper you're looking for.

Related

How to setup a controller's routes when it doesn't match the name

I want to have the url /community so here is what I did. I created the controller: CommunitiesController and have this in my routes:
get 'community' => 'communities#index'
Did I set this up incorrectly? The problem I'm having is I now want to add the kaminari pagination gym but the naming mismatch is causing this not to work:
get 'community' => 'communities#index'
resources :communities do
get 'page/:page', action: :index, on: :collection
end
as it wants me to user /communities/page/1 when I want to use /community/page/1
What would be the correct way to setup a controller and route with this use case?
I would go with
get 'community' => 'communities#index'
get 'community/page/:page' => 'communities#index'
But you may need to tweak paginate method and pass explicit params to make it work. I am not sure if this will be required, but it looks something like this
<%= paginate(#communities, params: { controller: 'communities', action: 'index' } %>
The more "resourceful" way of declaring your original community route is as follows:
resources :communities, path: "community", only: "index"
Then you can add the Kaminari route according like this:
resources :communities, path: "community", only: "index" do
get "page/:page", action: :index, on: :collection
end
For further explanation, read the very helpful Rails Routing from the Outside In guide.

Redundant Rails Routes

Why is it that my <%= form_for charges_path %> returns an undefined local variable when visiting /product/:product with these routes :
get 'product/:product' => 'charges#new'
post 'product/:product' => 'charges#create'
but works when I add these?
resources :charges, :only => [:new, :create]
I'd like to clean this up
When you use the get and post methods you don't get the path helpers created, ie. there is no charges_path method unless you provide a string with the :as option.
So without charges_path method, ruby thinks it's the name of a variable and so you get the error you're getting.

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 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

customize rails url with username

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'

Resources