In routes.rb, I have:
[some routes]
match '/me' => "scores#all_athlete_scores", :constraints => LoggedInChecker
devise_scope :user do
match '/me' => "devise/sessions#new"
end
match '/scores/athlete/:id', :to =>"scores#all_athlete_scores", :as => "all_athlete_scores"
[some more routes]
LoggedInChecker returns true if the user is logged in, and false if it's not. If false, the second route picks it up and sends the user to a login page.
In scores_controller_test.rb, I have:
def test_get_all_athlete_scores
[set up]
get :all_athlete_scores, :id => #user
end
The weird part is that request.filtered_parameters[:full_path] in scores_controller_test is /me?id=#user.id, not /scores/athlete/:id'.
If I change routes.rb to be:
[some routes]
match '/scores/athlete/:id', :to =>"scores#all_athlete_scores", :as => "all_athlete_scores"
match '/me' => "scores#all_athlete_scores", :constraints => LoggedInChecker
devise_scope :user do
match '/me' => "devise/sessions#new"
end
[some more routes]
The test works fine and request.filtered_parameters[:full_path] = /scores/athlete/:id.
Totally baffled by this - /me should not be matched when a GET is made to all_athlete_scores.
Any ideas?
Kareem,
I think the confusion is in the fact that you have a method as well as a named route 'all_athlete_scores'.
get :all_athlete_scores, :id => #user
calls the method all_athlete_scores rather than the named route, which is what you are expecting.
Probably should just test the functionality of that method within this test and leave the testing of routes to another test.
Hope that helps!
Related
I am using Rails 4 and am trying to include the koudoku stripe gem. Here is my routes:
# Added by Koudoku.
mount Koudoku::Engine, at: 'koudoku'
scope module: 'koudoku' do
get 'pricing' => 'subscriptions#index', as: 'pricing'
end
resource :account
devise_for :users, :skip => [:sessions]
as :user do
get '/login' => 'devise/sessions#new', :as => :new_user_session
post '/login' => 'devise/sessions#create', :as => :user_session
get '/logout' => 'devise/sessions#destroy', :as => :destroy_user_session
end
get '/dashboard', to: 'dashboard#index'
get '/reports/generate', to: 'reports#generate'
authenticated :user do
root :to => 'dashboard#index', :as => :authenticated_root
end
root :to => redirect('/login')
And this is the error I am getting:
undefined local variable or method `root_url
I can access the other routes just fine, it is just trying to render the Application Helper methods (for instance, a custom app method I have defined, or routes methods) from the module routes... Does this make sense? How do I fix this?
Try adding "main_app." before your root path. For example:
main_app.root_path
Conditional logic in the routing layer kind of goes against the intent of the Rails MVC architecture. The route file should just map a web request to a controller, which then has conditional logic to determine what is displayed.
In this case it's a bit different since you want to redirect, but I personally would still put it in the controller. In other words send the root to dashboard#index, and then at the top of that controller (or in a before_filter) just do
redirect_to login_path unless current_user_authenticated?
(here I'm assuming you would have a named route for login, which would be good practice, as well as a current_user_authenticated? method to check whatever logic you want before the redirect. This would be a more Rails-y approach, whatever that's worth...)
I have been trying to implement a vanity url for user profiles, based on the example here: Rails 3: Permalink public profile. I have replaced the 'id' with username:
def to_param
username
end
However this has caused issues with my other routes. I have set them so that they match the default sets of routes exactly, when running 'rake routes'.
get '/users/' => 'users#index', :as => :users
post '/users' => 'users#create'
get '/users/new' => 'users#new', :as => :new_user
get '/users/:id/edit' => 'users#edit', :as => :edit_user
patch '/users/:id' => 'users#update'
put '/users/:id' => 'users#update'
delete '/users/:id' => 'users#destroy'
# for vanity url
get '/:id' => 'users#show', :as => :user
With this setup, trying to access delete and update routes give me 'no route matches' error. What is the proper way to specify these, and / or should I be doing this a different way? Any help is appreciated.
I think it's interresting and more readable to keep the resources syntax in the routes.rb, except for the show, which you can rewrite to customize user_path :
resources :users, :except => [:show]
# 2 possibilities for the show url
get '/users/:id' => 'users#show' # can be removed if you don't want to keep /users/:id url
get '/:id' => 'users#show', :as => :user
But change the controller to find user by username instead of id, for example
def show
#post = Post.find_by_username(params[:id]) # instead of Post.find(params[:id])
# ...
end
I feel like I should know this and I'm certain this could be done more cleanly, but I'm not quite sure the best way to go about it.
How could a set of routes like this be written in a more DRY way?
# Artists
match "/:id/remixes", :to => "artists#remixes", :as => "artist_remixes"
match "/:id/originals", :to => "artists#originals", :as => "artist_originals"
match "/:id/popular", :to => "artists#popular", :as => "artist_popular"
match "/:id/mashups", :to => "artists#mashups", :as => "artist_mashups"
match "/:id/covers", :to => "artists#covers", :as => "artist_covers"
match "/:id/productions", :to => "artists#productions", :as => "artist_productions"
match "/:id/features", :to => "artists#features", :as => "artist_features"
That should do it:
resources :artists, path: '/' do
member do
get 'remixes'
get 'originals'
get 'popular'
get 'mashups'
get 'covers'
get 'features'
end
end
I would look to try and do 1 route and pass list_type as a parameter.
Something like
resources: artists do
resources list_types
end
I would try and avoid having seperate actions for a bunch of methods that probably do similar things.
Ah, should have just thought this through (hungover today):
[:remixes_of, :remixes_by, :originals, :popular, :mashups, :covers, :productions, :features].each do |role|
match ":id/#{role}", to: "artists\##{role}", as: "artist_#{role}"
end
I already have a route to match /username for the users show page. However, when I add another action, for example: followers and following as below:
resources :users, :only => [:show] do
get :following, :followers
end
I get the URL /users/username/following instead of /username/following.
How can I make all the /users/username URL's be matched as /username/etc.. ?
Here's my /username route:
match '/:id' => 'users#show', :constraints => { :id => /[a-zA-Z0-9\-_]*/ }, :as => "user_profile"
thank you.
Edit:
I have fixed this by adding
match '/:id/following' => 'users#show/following', :as => "user_following"
match '/:id/followed' => 'users#show/following', :as => "user_followers"
But I'm not sure if that's the best solution. What I'd really want is a default route that would match all /:id/:action to the appropriate action omitting the /users.
I have fixed this by adding
match '/:id/following' => 'users#show/following', :as => "user_following"
match '/:id/followed' => 'users#show/following', :as => "user_followers"
But I'm not sure if that's the best solution. What I'd really want is a default route that would match all /:id/:action to the appropriate action omitting the /users.
Near the bottom
match ':id/:action', :controller => :users
I'm trying out Rails, and I've stumbled across an issue with my routing.
I have a controller named "Account" (singular), which should handle various settings for the currently logged in user.
class AccountController < ApplicationController
def index
end
def settings
end
def email_settings
end
end
How would I set-up the routes for this in a proper manner? At the moment I have:
match 'account(/:action)', :to => 'account', :as => 'account'
This however does not automagically produce methods like account_settings_path but only account_path
Is there any better practice of doing this? Remember the Account controller doesn't represent a controller for an ActiveModel.
If this is in fact the best practice, how would I generate links in my views for the actions? url_to :controller => :account, :action => :email_settings ?
Thanks!
To get named URLs to use in your views, you need to specify each route to be named in routes.rb.
match 'account', :to => 'account#index'
match 'account/settings', :to => 'account#settings'
match 'account/email_settings', :to => 'account#email_settings'
Or
scope :account, :path => 'account', :name_prefix => :account do
match '', :to => :index, :as => :index
match 'settings', :to => :settings
match 'email_settings', :to => :email_settings
end
Either works the same, it's just a matter of choice. But I do think the first method is the cleanest even if it isn't as DRY.
You could also define it as a collection on the resource:
resources :login do
collection { get :reminder, :test }
end
Of course, this also defines the default CRUD actions as well. I'm currently only using two of those for my not-an-actual-model controller, but I don't think/expect there will be any problem with the extra routes.