routes.rb - Controller name not supported - ruby-on-rails

I'm having quite a peculiar issue. This is the portion of routes.rb it relates to:
resources :players
match '/players/:userid', :to => 'Players#show'
When you visit localhost:3000/players/1234 it gives this error:
'Players' is not a supported controller name. This can lead to potential routing problems.
The related code in the controller:
def show
begin
if Player.find_by(:uid => :userid) then
#playerattributes = Player.find_by(:uid => :userid)
if player[:profile_complete] == true then
#playerinfo = {
:age => player[:age],
:team => player[:team],
:position => player[:position]
}
else
#playerinfo = 0
end
end
player = Player.find_by(:uid => :userid)[:info]
rescue ActiveRecord::RecordNotFound
redirect_to root_url
end
end
The problem doesn't end there. When the page does load (which it sometimes randomly works), this line acts up:
if Player.find_by(:uid => :userid) then
Using PostgreSQL, and the query gets displayed. Instead of using the :userid value from the URL (i.e. localhost:3000/players/1234 would be 1234), it just inputs the text "userid".
Am I missing something obvious?
Really appreciate any help.

Change: Players to players so:
match '/players/:userid', :to => 'Players#show'
to
match '/players/:userid', :to => 'players#show'
Read more.
To read user id value in your controller, use params[:userid], not just :userid.

Rails individual routes is going to write in this way.
EG: requested action "browser url_name(whatever you want)", to:
'controller_name#method_name'
In your case it should be:
match '/players/:userid', :to => 'players#show'
Similarly for a get request:
get '/players/:userid', :to => 'players#show'

Related

how to make dynamic nested routes on rails?

I'll explain when open www.domain.com/:id should be check the :id is a page then use
get ':id' => 'pages#show'
else if :id is a Category use
get ':category' => 'categories#show'
sorry for my english
get ':page' => 'pages#show'
resources :categories, :path => '/' do
resources :posts, :path => '/'
end
constraints for routes is way to go, but I would suggest a bit different solution for your problem.
Consider creating custom Constraint objects, which will query the database in order to check if Post or Category exists:
app/lib/post_constraint.rb
class PostConstraint
def matches?(request)
Post.exists?(request[:id])
end
end
app/lib/category_constraint.rb
class CategoryConstraint
def matches?(request)
Category.exists?(request[:id])
end
end
In your app/config/routes.rb
get ":id" => "posts#show", constraints: PostConstraint.new
get ":id" => "categories#show", constraints: CategoryConstraint.new
You have to be aware of the fact, that id is very poor candidate for such comparison, because the Post is checked in first place, and if there is record matching, the "posts#show" will be accessed, and CategoryConstraint wot be even bothered.
For more, check the documentation.
You should consider adding a slug for both models to easier serve exactly what user expects to see. For this purpose, try gem friendly_id.
Hope that helps! Good luck!
why dont you write something like this:
routes.rb
get '/:category_id/:post_id', to: 'categories#post'
and in your categories_controller.rb
def post
#params[:category_id] and params[:post_id] will contain the params from the url
end
Couple of solutions
If your post id and category id follow a pattern you can add constraints to your routes
1)
get ':post_id' => 'posts#show', :constraints => { :id => /[A-Z]\d{5}/}
get ':category_id' => 'categories#show', :constraints => { :id => /[1-9]\d{5}/ }
2)
Add a custom method where both post_id/category_id routes point, in that check if the id is a post id or category id and based on that render the page

One matched route overrides another, but shouldn't

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!

More Dynamic Routes?

I have this site where I want to be able to export all the data using CSV. There is a controller called "dataexport" and it has a method for each model. In my routes.rb file, I have this:
match "export_checkouts", :to => "dataexport/checkouts_csv"
match "export_committees", :to => "dataexport/committees_csv"
match "export_libitems", :to => "dataexport/libitems_csv"
match "export_locations", :to => "dataexport/locations_csv"
match "export_logs", :to => "dataexport/logs_csv"
match "export_patrons", :to => "dataexport/patrons_csv"
match "export_products", :to => "dataexport/products_csv"
match "export_questions", :to => "dataexport/questions_csv"
match "export_reasons", :to => "dataexport/reasons_csv"
match "export_roles", :to => "dataexport/roles_csv"
match "export_sales", :to => "dataexport/sales_csv"
match "export_shifts", :to => "dataexport/shifts_csv"
match "export_tasks", :to => "dataexport/tasks_csv"
match "export_tickets", :to => "dataexport/tickets_csv"
match "export_types", :to => "dataexport/types_csv"
match "export_users", :to => "dataexport/users_csv"
match "export_visitors", :to => "dataexport/visitors_csv"
match "export_years", :to => "dataexport/years_csv"
Is there a more dynamic way of doing this? This definitely goes against the "DRY" paradigm and was wondering if anyone could help me with this. I was thinking that you could just do this in one line by replacing the model names with a variable but I'm not quite sure how to go about doing this.
Why not just:
match "export/:model", :to => "dataexport/export_csv"
and use params[:model] to get the correct Model, then direct the dataexport controller export_csv method to ask the model for the data in CSV format like:
class DataexportController do
def export_csv
params[:model].constantize.export_csv
end
end
You could try this:
%w(checkouts committees).each do |model|
match "export_#{model}", :to => "dataexport/#{model}_csv"
end
Obviously fill out the array with all of the models you need this for.
However, whilst this cuts down on the code, you are still polluting your routes. You should consider that there might be a more Rails-way of doing this.
One thing Rails has support for is responding to different formats in controllers. So if a JSON format is requested by the browser, a JSON file is provided for by Rails (as long as you write the code for it). It sounds to me like you could just do the same thing with a CSV format.
What you are defining as "export" is really just the index method on a normal controller. It's just that rather than displaying the data as HTML, you are displaying it as CSV. I haven't really looked into this myself and so I'm not sure exactly how you would go about doing it. Something like this:
class FooController < ApplicationController
def index
respond_to do |format|
format.html #This will load your standard html index view
format.csv { #CSV stuff goes here. Perhaps you can get it to load app/views/foo/index.csv.erb somehow }
end
end
There is some discussion on this here: http://weblog.rubyonrails.org/2006/12/19/using-custom-mime-types

rails routing aliases

I have a model called Spaces which has different types of places... such as Bars, Restaurants, etc. It has the same columns, same, model, controller, etc. no fancy STI, I just have one field called Space_type which I would like to determine an aliased route.
Instead of domain.com/spaces/12345 it would be /bars/12345 or /clubs/12345
Currently I have:
resources :spaces do
collection do
get :update_availables
get :update_search
get :autocomplete
end
member do
post :publish
post :scrape
end
resources :photos do
collection do
put :sort
end
end
resources :reviews
end
Also, Is there a way I can do this so that anytime I use the space_url it can figure out which one to use?
The routes are not a way to interact with your model directly. So, as long as you write a standard route, you can make things work. For instance, to make /bars/12345 and /clubs/12345 for your spaces_controller (or whatever the name of the controller is) , you can create routes like :
scope :path => '/bars', :controller => :spaces do
get '/:id' => :show_bars, :as => 'bar'
end
scope :path => '/clubs', :controller => :spaces do
get '/:id' => :show_clubs, :as => 'clubs'
end
# routes.rb
match "/:space_type/:id", :to => "spaces#show", :as => :space_type
# linking
link_to "My space", space_type_path(#space.space_type, #space.id)
which will generate this urls: /bars/123, /clubs/1 ... any space_type you have
And it looks like STI wold do this job little cleaner ;)
UPD
Also you can add constraints to prevent some collisions:
match "/:space_type/:id", :to => "spaces#show", :as => :space_type, :constraints => { :space_type => /bars|clubs|hotels/ }
And yes - it is good idea to put this rout in the bottom of all other routes
You can also wrap it as a helper (and rewrite your default space_url):
module SpacesHelper
def mod_space_url(space, *attrs)
# I don't know if you need to pluralize your space_type: space.space_type.pluralize
space_type_url(space.space_type, space.id, attrs)
end
end

Rails 3 routing - what's best practice?

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.

Resources