Does the order of the routes effect which controller is accessed? - ruby-on-rails

In my app I have grants and I want the url to be root/grant_id instead of root/grants/grant_id. I have this in my routes
Rails.application.routes.draw do
...
root 'static_pages#welcome'
# get 'home' => 'static_pages#home'
get 'about' => 'static_pages#about'
get 'faq' => 'static_pages#faq'
get 'signup' => 'users#new'
get 'login' => 'sessions#new'
post 'login' => 'sessions#create'
delete 'logout' => 'sessions#destroy'
get 'dashboard' => 'dashboard#index'
resources :users do
resources :projects
member do
get 'access_granted'
put 'access_granted'
get 'remove_access'
put 'remove_access'
end
end
resources :profiles
resources :account_activations, only: [:edit]
resources :password_resets, only: [:new, :create, :edit, :update]
resource :request_access, only: [:show, :new, :create]
resources :grants, :path => '' do
resources :app_types do
resources :submissions
end
end
get 'grants' => 'grants#index'
resources :matches
end
When I put resources :matches below the resources :grants, :path => '' do line I get the error "Couldn't find Grant" and I see that request parameters are
{"controller"=>"grants", "action"=>"show", "id"=>"matches"}. When I put resources :matches above the the grant line everything works fine. Its almost like something in the grant route isn't closing and is forcing any lines below it to look for the grant controller. A simple solution is just keeping everything above that line but I'm trying to understand why this is happening.
I also noticed that even though I define the grant#index as grants, when I rake routes I see:
grants GET / grants#index
GET /grants(.:format) grants#index
So two questions
1. Is :path => '' the correct way to remove the grants/ part of the url.
2. Why is everything below the grants route getting sent to the grants controller?

From the documentation :
Rails routes are matched in the order they are specified, so if you have a resources :photos above a get 'photos/poll' the show action's route for the resources line will be matched before the get line. To fix this, move the get line above the resources line so that it is matched first.
So, the problem you're having is that matching grants to "" means your grants INDEX route is /, and your grants SHOW route is /:grant_id, which will match any route. If you want to have this kind of route (which I would advise against), it has got to be at the bottom of the routes file.
You can read more about routing here: http://guides.rubyonrails.org/routing.html

Related

Rails custom and default routes

I'm trying to define custom routes to my controller and I need to use some of the default routes too. Is there any simple solution?
So far I've something like this
resources :users do
member do
get 'users/:id', to: 'users#show'
delete 'users/:id', to: 'users#destroy'
end
collection do
post 'users', to: 'users#create'
post 'users/login', to: 'users#login'
end
end
resources :users, :only => [:show, :destroy, :create, :login]
I don't need nor want the index route but with this settings it's still trying to route GET users/ to user_controller index method.
I know that there is probably some simple and obvious answer but I'm not able to find it.
Thank's in advance.
You got your routes wrong. The resources :users generates seven default routes which include the index route as well. You need to tweak the code to below
resources :users, :only => [:show, :destroy, :create] do
collection do
post 'login', to: 'users#login'
end
end
Note:
If you noticed, I've removed the custom routes for show,create and delete as they are generated by default.
Your first line defines the route to the index action. Define a resource once only. Read the routing guide.
resources :users, :except => [:index] do
collection do
post 'users/login', to: 'users#login'
end
end
Run rake routes from the command line in your project root folder to see all your route definitions.

ui-router, devise and a user profile page

I'm trying to create a user profile page but I'm having some problems. I've used Devise for user handling in my project and I'm using AngularJS and ui-router and obviously RoR.
What I'm trying to do is to show a profile page of a user when the following URL is visited http://localhost:3000/users/1
When I visit that URL now I see my frontpage (views/layout/application.html.haml) which is obviously wrong.
In my mainCtrl.js I have
$stateProvider
.state('home', {
url: '',
templateUrl: '../assets/angular-app/templates/_search.html',
controller: 'searchCtrl'
})
.state('users.profile', {
url: '/users/{id}',
templateUrl: '../assets/angular-app/templates/_profile.html'
})
The home state works when I go to localhost:3000
But like I said, when I go to http://localhost:3000/users/1 the template _profile.html doesn't get inserted, there's not even an error if I mistype the template file name. So it looks like the state action doesn't do anything.
My expectation is that the template _profile.html gets loaded into the
%div{"ui-view" => ""}
on my application.html.haml page. But it inserts the _search template.
And this is the routes.rb if it matters,
Rails.application.routes.draw do
devise_for :users, :controllers => { :omniauth_callbacks => "callbacks" }
get 'sessions/create'
get 'sessions/destroy'
devise_scope :user do
root to: 'application#angular'
match '/sessions/user', to: 'devise/sessions#create', via: :post
end
resources :users do
member do
get :following, :followers
end
end
resources :relationships, only: [:create, :destroy]
get 'login/show'
get 'auth/:provider/callback', to: 'sessions#create'
get 'auth/failure', to: redirect('/')
get 'signout', to: 'sessions#destroy', as: 'signout'
resources :sessions, only: [:create, :destroy]
resources :movies, only: [:create, :destroy, :index, :show]
end
Researching some examples I noticed the hashtag. When I added the # to my url the route states started working. Then I used html5mode enabled to remove the # and now it's working fine.

Rails is there a way to collect all routes

I am using this as an example:
https://github.com/toshimaru/Rails-4-Twitter-Clone
The route file looks like:
Rails.application.routes.draw do
root 'static_pages#home'
resources :users do
member do
get :following, :followers
end
end
resources :sessions, only: [:new, :create, :destroy]
resources :tweets, only: [:index, :create, :destroy]
resources :relationships, only: [:create, :destroy]
get 'signup' => 'users#new'
get 'signin' => 'sessions#new'
delete 'signout' => 'sessions#destroy'
get 'about' => 'static_pages#about'
match '*path' => 'application#routing_error', via: :all
end
It appears that in some controllers there are comments mentioning which route it uses, however it's not specified in the route file. For instance:
# GET /users
def index
#users = User.all
end
# GET /users/1
def show
#tweet = current_user.tweets.build if signed_in?
#feed_items = #user.tweets.paginate(page: params[:page])
end
(in users_controller.rb)
My question is, how does rails app know that there is an endpoint here? I would like to know whether I can actually collect all the routes in one file?
What I am intending to do is, I would like to replace current routes.rb file with all routes.
Its specified in route file
When, we write
resources :users
It creates CRUD routes for specified resource namely index, new, create, show, edit, update, destroy routes for resource, here in this case resource is user.
You can see all routes for user by
rake routes | grep 'users'
and to list all routes in application
rake routes
resources :users has automatically created all RESTful routes for you, although you can limit it to only certain routes (as your example does with sessions, tweets, and relationships).
You can see all the routes from the console... in the root of your project do rake routes
See here for an explanation...
http://guides.rubyonrails.org/routing.html#listing-existing-routes
You can access the output of rake routes in your application....
output = `rake routes`
(note the use of backticks in the above)

rails4 ckeditor (No route matches [POST] "/ckeditor/

I have installed Rails4 (rails (4.1.1))
I Installed Ckeditor+paperclip (http://rubydoc.info/gems/ckeditor/4.0.11/frames)
But if I try to upload images, I get this error in log:
ActionController::RoutingError (No route matches [POST] "/ckeditor/EDITOR.config.filebrowserImageUploadUrl"):
i need help please! This was worked In rails 4.0.0.
My route list
... mount Ckeditor::Engine => '/ckeditor'
I use Ckeditor with Paperclip
My config/routes.rb
Rails.application.routes.draw do
resources :binaries
resources :uploads
resources :coms
resources :comments
mount Ckeditor::Engine => '/ckeditor/'
resources :parts
get "/parts/page/:id" => "parts#page"
resources :answer_types
resources :from_sender_msgs
resources :ufknews
get "/general" => "ufknews#general"
get 'ufk13/ufk13pol'
get 'ufk13/governance'
get 'ufk13/contacts'
get "errors/error_404"
get "errors/error_403"
devise_for :users
devise_scope :user do
get "sign_in" => "devise/sessions#new"
get "logout" => "devise/sessions#destroy"
delete "logout" => "devise/sessions#destroy"
get "users" => "users#index"
get "users/:id" => "users#show" , as: :user_root, as: :user
get "users/:id/edit" => "users#edit" , as: :user_edit
get "users/delete" => "users#delete"
put "users" => "users#update"
end
get 'persons/profile'
resources :budget_types
resources :positions
resources :message_types
resources :message_states
resources :messages
resources :senders
resources :organisations
root 'ufknews#general'
get 'home/index'
get 'home/about'
get 'home/contacts'
get 'home/dufk'
get 'home/photo'
get "/*other" => redirect("/errors/error_404")
end
So, you can modify your routes to use POST request instead PUT while try to update data with ckeditor.
For example, if you have in your routes.rb:
resources :pages
you can update this to:
resources :pages, :except => ['update']
post 'pages/:id' => 'pages#update'
It's all!
This method kill a two rabbits:
Modify route for ckeditor;
Improve your project to update big fields over header size limits on your backend of client browser.

Why rails app is redirecting unexpectedly instead of matching the route?

I asked this question earlier and thought it was fixed, but it's not. Previous question here
My problem is I am trying to set my routes so that when I type in
localhost:3000/sites/admin
It should redirect to
localhost:3000/en/sites/admin
here is my routes.rb file
scope ":locale", locale: /#{I18n.available_locales.join("|")}/ do
get "log_out" => "sessions#destroy", as: "log_out"
get "log_in" => "sessions#new", as: "log_in"
resources :sites, except: [:new, :edit, :index, :show, :update, :destroy, :create] do
collection do
get :home
get :about_us
get :faq
get :discounts
get :services
get :contact_us
get :admin
get :posts
end
end
resources :users
resources :abouts
resources :sessions
resources :coupons
resources :monthly_posts
resources :reviews
resources :categories do
collection { post :sort }
resources :children, :controller => :categories, :only => [:index, :new, :create, :new_subcategory]
end
resources :products do
member do
put :move_up
put :move_down
end
end
resources :faqs do
collection { post :sort }
end
root :to => 'sites#home'
match "/savesort" => 'sites#savesort'
end
match '', to: redirect("/#{I18n.default_locale}")
match '*path', to: redirect("/#{I18n.default_locale}/%{path}")
But as of right now, it redirects to /en/en/en/en/en/en/en/en/en/en/sites/admin (adds en until browser complains).
Any thoughts why it keeps adding /en?
Edit:
The answer is great, thanks. Can you help me diagnose the root route?
root to: redirect("#{/#{I18n.default_locale}") # handles /
I know redirects is looking for something like
redirect("www.example.com")
So that leaves this part
#{/#{I18n.default_locale}
The #{ is using rubys string interpolation, right? i'm not sure what that { is doing though.
So then we have
/#{I18n.default_locale}
Which is also using string interpolation and to print out the value of I18n.default_locale?
Hopefully that makes sense, I really really appreciate the help, I am learning a lot.
Edit 2:
I changed the line from
root to: redirect("#{/#{I18n.default_locale}") # handles /
to
root to: redirect("/#{I18n.default_locale}") # handles /
But i'm not sure if thats right. Now i'm getting the error
uninitialized constant LocaleController
I know it's getting the error from the root to: "locale#root", but i thought the locale# would come from the scope.
I'll continue playing with it and let you know any progress.
Here is a new link to my routes file https://gist.github.com/2332198
We meet again, ruevaughn. :)
I created a test rails app and the following minimal example works for me:
scope ":locale", locale: /#{I18n.available_locales.join("|")}/ do
resources :sites do
collection do
get :admin
end
end
root to: "locale#root" # handles /en/
match "*path", to: "locale#not_found" # handles /en/fake/path/whatever
end
root to: redirect("/#{I18n.default_locale}") # handles /
match '*path', to: redirect("/#{I18n.default_locale}/%{path}") # handles /not-a-locale/anything
When using Rails 4.0.x that %{path} in the redirect will escape slashes in the path, so you will get an infinite loop redirecting to /en/en%2Fen%2Fen%2Fen...
Just in case someone, like me, is looking for a Rails-4-suitable solution, this is what I found to be working without problems, even with more complex paths to be redirected:
# Redirect root to /:locale if needed
root to: redirect("/#{I18n.locale}", status: 301)
# Match missing locale paths to /:locale/path
# handling additional formats and/or get params
match '*path', to: (redirect(status: 307) do |params,request|
sub_params = request.params.except :path
if sub_params.size > 0
format = sub_params[:format]
sub_params.except! :format
if format.present?
"/#{I18n.locale}/#{params[:path]}.#{format}?#{sub_params.to_query}"
else
"/#{I18n.locale}/#{params[:path]}?#{sub_params.to_query}"
end
else
"/#{I18n.locale}/#{params[:path]}"
end
end), via: :all
# Redirect to custom root if all previous matches fail
match '', to: redirect("/#{I18n.locale}", status: 301), via: :all

Resources