How to change a rails controller default router from index to other? - ruby-on-rails

As we know, if we have a UsersController, when we get /users it default to /users/index. If I want to map /users to /users/show, what can I do? (This can apply to any other controllers, not just users.)

You can modified the file Global.asax.
There is a method named 'RegisterRoutes',change the 'Index' in 'action=Index' to 'show'

The only difference between URLs for the index action and the show action is the show action requires the identity of the resource. The default Rails URL for index on the users resource is /users, and the default show URL looks like /users/12, where the 12 identifies the resource. This identification part isn't optional, so you can't usefully map /users to the show action in a RESTful scheme.

For example if you want to have a profile page at localhost:3000/username you can add match '/:id' => 'users#show', :as => :user to routes.rb and <%= link_to "Profile", #user %> to your view. With a little fiddling in the controller to grab your profile info via the current user's username, this will link to localhost:3000/username.

Related

Rails route pointing to wrong place

In attempts to make my application more clean I have decided to create an imports controller and a views folder along with that instead of creating an import.html.erb view and an import method in my users controller.
My goal is to make the url: http://10.0.0.7/accounts/1/users/import
However, as one might think, this is directing to the show page and is thinking that import is the users id. How can I create the route so that it does not think that the word import is actually the users id?
Parameters shown in error page: {"account_id"=>"1", "id"=>"import"}
In my routes file I have this route which takes care of the
resources :accounts do
resources :users do collection { post :import, :controller => "imports", :action => "users" } end
end
I have also tried this route.
resources :accounts do
post :import, controller: 'imports', action: 'users'
end
There's a few issues I see here.
First, #accounts is nil. This is probably because it's in a partial, and you need to pass in variables into the partial.
<%= render partial: 'admin_sidebar', accounts: #accounts %>
And then use the variable accounts in the partial. Also, why is users in the URL? Your basic routing should have done this just fine.
I'd suggest a route like:
post 'account_users/:id', to: 'imports#users', as 'account_users'
This says - if a post request to URL /account_users/# send to imports controller and use the users method.

How does a rails resource know to use the show view?

I'm looking at this tutorial: https://www.railstutorial.org/book/sign_up
We get on to rails resources.
config/routes.rb
Rails.application.routes.draw do
root 'static_pages#home'
get 'help' => 'static_pages#help'
get 'about' => 'static_pages#about'
get 'contact' => 'static_pages#contact'
get 'signup' => 'users#new'
resources :users
end
app/controllers/users_controller.rb
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
end
def new
end
end
app/views/users/show.html.erb
<%= #user.name %>, <%= #user.email %>
There is also this handy table of telling us how ruby will handle the various requests to the Users resource.
I have two questions here.
How does RoR know when accessing the /users, /users/1 etc urls, what to actually use the index, show methods.
More importantly, - when the show method is called, how it does it know the give the show.html.erb view to browser? What if I wanted to return a different view?
1. Rails knows which methods to use based on the HTTP request type (GET, POST, PUT, or DELETE) and the endpoint. So when you hit the '/users' endpoint with a GET request, it will use the index method. When you hit the '/users/:id' endpoint with a GET request, it will use the show method.
2. The show.html.erb view is used because the name matches the show method. To use a different view, just use match in the routes file like so:
match "users" => "users#show"
The example above would match the '/users' route to the '/user/:id' route.
The mechanism that is responsible for dispatching actions in response to requests is router. You define all the routes in config/routes.rb file as you said. Each line in this files define the request in clear way. resources is a shorthand to define a set of routes - all of them listed here.
There are two thins that distinct requests - the URL and the HTTP request type (GET, POST, PUT, DELETE). Based on these two things you can clearly direct the request to proper controller. Take a look on this one:
get 'help' => 'static_pages#help'
This means: If you get a request of type get directed to url of value /help dispatch the request to controller static_pages and its action help. What happens in help action is a matter of code.
This is also an answer to your second question, how does Rails know what template should it render. Assume that we still work on above example of help action. If this action has no explicit render call, Rails will use its convention over configuration and search for a template that will be in directory called as the controller and in file name as the action name. Therefore, it will render the file that is in app/views/static_pages/help.html.erb. On the other hand, the developer can call render with explicit other file name, e.g.: render "products/show".
If you want to find more please take a look at these two Rails guides:
Layouts and rendering
Rails Routing
rails is said to have convention over configuaration. this is one of the strongest feature available in Rails.in another way. Smart and less code. Here when u say method name as show. rails by default will look for show.html.erb. if you want to explicitly render some other view. You can do this in your controller methods
render :new_view_name
Regarding the routes.
resources :users
This is very helpful when we have Rest calls ,crud operations.it creates 7 urls for crud. And how it differentiate is depending on http data type.

Rails render "action" as custom url

In my routes.rb I have the following:
get "contact" => "inquiries#new"
So that when I go to /contact in the browswer, it calls the InquiriesController's new action.
Now when I try to call render "new" in the create action inside InquiriesController:
def create
…
render "new"
end
The resulting url in the browser is /inquiries.
Is there a way besides calling redirect_to to render "new" but have the url as /contact in the browser?
Short answer is No. And here's why:
render is different from redirect_to. When you write redirect_to :action, you are initiating an entirely new browser request. The rails stack is hit, again routes are searched for and the corresponding action is executed. Its exactly the same as entering the url in address bar and pressing enter.
On the other hand, when you use render, you are telling which view to use for the current request. As such, the address in the address bar will generally be of the action in which you are calling render. That's because you put an address and then you tell rails to display a different page in that same request.
In a nutshell, while redirect_to begins an entirely new request cycle, render simply replaces the default view with what you choose in the same request cycle.
So if you want the address bar to change, you will have to initiate a new request to the address you want. It can be by manually entering the address, clicking a link to that address or redirecting to it from rails.
Hope this helps.
The solution is to use custom routes, if you use Restful routing, you can simply add this line to your routes.rb :
resources :inquiries, path: "contact", as: :inquiries, only: [:create]
here you tell rails to change url by default from inquiries to contact when the name of the action is create
if you want other action to match an url which is begin with contact, just add the name of the action to "only", for example : only: [:create, :update ...]
if you want all your actions in that controller (inquiries) to be customized to "contact" just remove only like this :
resources :inquiries, path: "contact", as: :inquiries
and all your routes for inquiries controller will be change from /inquiries to /contact
for more details about how to customizing restful routes please check this link
When using render :new in the create action, it will use the same URL that the form posted to.
Therefore, if you would like to set up both an inquires you can set up your routes like:
get '/contact', 'inquiries#new', as: 'contact'
post '/contact', 'inquiries#create'
You can also use the resources method as medBo references, but I just prefer plain old get and post when I'm doing custom things. Also, these routes can co-exist with your exiting inquiries routes without any ill affects.
Then with those routes sets, you can create your contact from by writing:
<%= form_tag contacts_url do %>
...
<% end %>
The important step here, is that we set up the form to post to `/contact' instead of posting to '/inquiries'.
I think you first need to understand difference between redirect_to & render
For /contact url
change
render "new"
to
redirect_to "/contact"

Editing the current User in Rails 3

Users can be edited from a normal resourceful URI like:
/users/1/edit
The issue is that in my application, the edit user page is the home page or root route.
# routes.rb
root :to => "users#edit"
So, I tried to set #user to the current user in the absence of params[:id].
# app/controllers/users_controller.rb
def edit
#user = (params[:id]) ? User.find_by_id(params[:id]) : #current_user
end
Unfortunately, I'm having trouble getting the form to point properly.
# app/views/shared/_manage_users.rb
<%= form_tag follow_user_path, :id => 'update-following-form' %>
I'm getting:
No route matches {:action=>"follow", :controller=>"users"}
follow is a member route of the user resource and has a corresponding controller method. If I access the page via the URI at the top of this question, /users/1/edit, everything works fine and no error is thrown.
I'm not sure whether I'm going about this completely the wrong way or if I'm just not using the right form helper or something silly. How can I fix this issue, or what steps can I follow to debug it?
A member route expects the member to be passed as an argument. You route is expecting a User, like so:
follow_user_path(#user)
in your routes do this
resource :user
instead of
resources :users
now the id param is notin the url. you just need to ensure the user is logged in
I think you need to actually define follow_user in your routes.rb.
Example:
post "user/follow" => "users#follow", :as => :follow_user

custom action in rails 3

I'm trying to make a simple link that will toggle my "status" attribute in my model from "pending" to "active". For example, when I first create a user, I set the status to "pending". Then when I show the list of users, I add a button that should change that user's status to "active". I tried this via a custom action (is this a good approach?) but I'm having trouble with the auto-generated named route.
in my user index.html.haml:
button_to "Manually Activate", activate_user_path
in routes.rb:
resources :users do
get :activate, :on => :member
in users_controller.rb:
def activate
#user = User.find(params[:id])
#user.update_attribute(:status, 'Active')
redirect_to #user
end
this seems to work when I go to say, /users/1/activate, as the status will update. However, the /users page doesn't show and gives me error:
ActionController::RoutingError in Users#index
No route matches {:action=>"activate", :controller=>"users"}
ie, it is having a problem with the activate_user_path I specified in my view. (However if I use another named-routes-style path that I haven't specified in my routes.rb to test it out, I get
NameError in Users#index
undefined local variable or method `blahblah_user_url' for #<#<Class:0x00000102bd5d50>:0x00000102bb9588>
so it seems that it knows it's in the routes.rb but something else is wrong? I'm really new to rails and would appreciate the help!
thanks!
Your link should look like this:
button_to "Manually Activate", activate_user_path(#user)
You need to add what user you want to activate.
A number of problems, I can see.
Firstly you should NOT update the database using a GET request.
Secondly button_to will provide you with an inplace form which when clicked will POST to your app.
Thirdly, the way you have your routes setup, you need to provide the user in the path (you've tested it by forming the url in the browser already).
run
rake routes
on the command prompt to see how your routes look and the name you can use to generate those routes.
I suspect you need to use
button_to "Manually Activate", activate_user_path(user)
(user or #user or whatever is the user object). In your button_to call and change the "get" to "post" in the routes file.
resources :users do
member do
post :activate
end
end

Resources