I'm trying to setup a subdirectory in my Rails 3.2.3 app to service API requests at: http://example.com/api
I have created a directory like: app/controllers/api/
and I'm following the standard convention for implementing the namespaced controllers:
module Api
class GroupsController < ApplicationController
# RESTful verbs implemented here
end
end
I've setup a namespaced route like this:
namespace :api, defaults: {format: 'json'} do
resources :groups
end
However requests to http://example.com/api/groups.json result in the following exception:
ActionController::RoutingError (wrong constant name groups):
app/controllers/api/groups_controller.rb:2:in `<module:Api>'
app/controllers/api/groups_controller.rb:1:in `<top (required)>'
As you can see, it appears that the name "groups" here isn't valid because it's lowercase. I have no idea where this is coming from though.
I have read in a few places that a version of the right-aws gem was breaking the String#camelize method and causing similar errors. However I have confirmed that this gem is not present in my Rails application's stack.
Been slamming my head against this for some time. Has anyone else ever hit this problem?
EDIT: pasted output from $ rake routes:
root / welcome#index
api_groups GET /api/groups(.:format) api/groups#index {:format=>"json"}
POST /api/groups(.:format) api/groups#create {:format=>"json"}
new_api_group GET /api/groups/new(.:format) api/groups#new {:format=>"json"}
edit_api_group GET /api/groups/:id/edit(.:format) api/groups#edit {:format=>"json"}
api_group GET /api/groups/:id(.:format) api/groups#show {:format=>"json"}
PUT /api/groups/:id(.:format) api/groups#update {:format=>"json"}
DELETE /api/groups/:id(.:format) api/groups#destroy {:format=>"json"}
So the underlying cause of this was some code from an internal gem conflicting with the routing/namespacing of Rails.
However, the code in this gem was copied/pasted from an older version of Rails, so other people may hit this same issue.
The root cause was the gem had over-ridden the String#constantize inflection method that Rails extends on the String class. The version of the method this gem copied does not play well with the latest version of Rails and recent versions of Ruby.
So, the result was that "#{controller_name}".constantize returned a camelCase name, but the first character was lowercase.
Solution is to update this String#constantize method in the gem to match the latest version from Rails core, or to simply remove/rename that method within the gem's codebase.
Related
After upgrading to Rails 6.1, I'm getting following error:
undefined method `find_script_name' for nil:NilClass
In this case the route is being used is root_path but getting this for many other routes too! routes.rb is as following (tried like this after removing all other route definitions)
Rails.application.routes.draw do
root 'home#index'
end
Only relevant thing I found online is this commit. Anyone has idea what could be wrong?
I'm running on ruby 2.7.2
it looks like a bug in the current release of rails 6.1
https://github.com/rails/rails/issues/42218
the current fix is to prefix all path helper calls inside the views with:
Rails.application.routes.url_helpers.
so session_path becomes Rails.application.routes.url_helpers.session_path
I'm working on a project where I have a Rails application (rails 4.2.5) that incorporates a gem, which is a Rails Engine. I'm currently working on moving the route definitions from the main application to the gem. I have a controller test that exercises one of the routes. The test fails when I move the route definition over to the gem, but the route looks the same.
My gem is called CallCenter, and includes a controller called call_center_controller (with an action called reports_tab). This is what routes.rb looks like in the Rails app:
...
mount CallCenter::Engine, at: "/call_center", as: 'call_center_urls'
get '/call_center/reports_tab' => 'call_center/call_center#reports_tab'
...
This is what I get running rake routes:
❯❯❯ rake routes | grep reports_tab
call_center_reports_tab GET /call_center/reports_tab(.:format) call_center/call_center#reports_tab
At this point controller test runs without errors. But when I move the route definition to the routes.rb file in the gem:
get 'call_center/reports_tab' => 'call_center#reports_tab'
(note that the route now points to 'call_center#reports_tab' instead of 'call_center/call_center#reports_tab', because the main application mounts the engine at /call_center)
Here is my output from rake routes, (still running from the main app's directory)
❯❯❯ rake routes | grep reports_tab
call_center_reports_tab GET /call_center/reports_tab(.:format) call_center/call_center#reports_tab
This is identical to the route reported by rake routes when it was defined in the main app, but now my test fails with the following message:
Failure/Error: get :reports_tab
ActionController::UrlGenerationError:
No route matches {:action=>"reports_tab", :controller=>"call_center/call_center"}
As far as I can tell the route is defined, and looks exactly the same as it did before when it was in the routes file for the main app. What am I missing?
I found the answer - I needed to add this to my controller spec to tell it to look at the routes provided by the Engine:
routes { CallCenter::Engine.routes }
So in our Rails 4.2 application, there is the alchemy_cms gem which requires its routes to be mounted last in config/routes.rb.
SampleApp::Application.routes.draw do
#other routes for the rails app here
# :
# :
mount Alchemy::Engine => '/'
end
We get routes like "/somehacker/routingurl" which then falls out to the Alchemy::Engine to handle, resulting in a default 500 error. If I wanted to do a custom 404 error, then the proper way to do it is to build a custom 404 page and have Alchemy handle the redirect? Otherwise since the Alchemy docs specify that it has to be the last route in config/routes.rb, there won't be a way to add a catchall route to redirect to some kind of error page I assume.
EDIT:
One of the problems is that there are some routes that are like the invalid "somehacker" route above that do need to be parsed by the Alchemy routing engine, such as "/en/us" where "en" is a valid locale. This is why I initially thought to put the route handling in the Alchemy engine's routes file.
If it is difficult for you to configure and use the Alchemy cms gem to redirect unknown routes into a custom defined page, you can use the bellow method to implement the same with a small coding tweak given bellow:
Rails 4.XXX
1. First Method.
(routes.rb)
You can still use a simple get to redirect all unknown routes.
get '*path', to: 'home#index'
If you wish to provide routing to both POST and GET requests you can still use match, but Rails wants you to specify the request method via via.
match "*path" => "home#index", via: [:get, :post]
Remember that routes.rb is executed sequentially (matching the first route that fits the supplied path structure), so put wildcard catching at the bottom of your matchings.
Here you can replace the home#index with any custom path that you defined in you application, also note that it is important to keep this redirection code only at the bottom of routes.rb.
2. You can follow the bellow tutorial on the same problem in a different perspective to solve can be found.
Custom 404 error page with Rails 4
I have the following routes in Refinery:
$ rake routes | grep blog
blog_root /blog(.:format) refinery/blog/posts#index
blog_post GET /blog/posts/:id(.:format) refinery/blog/posts#show
...
However, when I try to access that route, it gives an error.
> app.refinery.blog_post_path
ActionController::RoutingError: No route matches {:action=>"show", :controller=>"refinery/blog/posts"}
Here is part of routes.rb
# Refinery
mount Refinery::Core::Engine, at: '/'
Rails 3.2.14, Refinery 2.1.1.
Two things spring to mind
You probably don't need to preface refinery.blog_post_path with app although that doesn't seem to be the source of your error.
More importantly, you have not specified which blog post you want to show. So, your code should look something like refinery.blog_post_path my_blog_post.id
Warp Drive is a nice way to package an entire Rails application into a Gem for use in other Rails applications. I've gotten Warp Drive to work for a blogging engine I'm creating. There's just one problem - Authlogic OpenID authentication fails.
I created a bare-bones OpenID example application. I can compile to a gem with no problems:
$ warpify
$ rake warp_drive:compile
I then installed the compiled gem on my system. Creating a blank Rails project, I ran:
$ install_warp_drive rails-openid
You can get this project here.
In my blank Rails projects, I needed to configure gems through environment.rb (I'm probably doing this the wrong way):
config.gem "authlogic"
config.gem "authlogic-oid", :lib => "authlogic_openid"
config.gem "ruby-openid", :lib => "openid"
To get the blank Rails application working, I ran rake db:migrate, then through the console I added a user with an :openid_identifier field set to one that I control. So far so good. But trying to create a new session fails with this error:
Processing UserSessionsController#create (for 127.0.0.1 at 2009-12-31 11:35:59) [POST]
Parameters: {"commit"=>"Login", "user_session"=>{"openid_identifier"=>"richdev.myopenid.com"}, "authenticity_token"=>"BcsIKNpumqZrTV/bdSLQ6szBvq6kpaAIxJRmYgxySLU="}
OpenIdAuthentication::Association Load (0.3ms) SELECT * FROM "open_id_authentication_associations" WHERE ("open_id_authentication_associations"."server_url" = 'http://www.myopenid.com/server')
Generated checkid_setup request to http://www.myopenid.com/server with assocication {HMAC-SHA1}{4b3cf228}{mWlzhg==}
Redirected to http://www.myopenid.com/server?openid.assoc_handle=%7BHMAC-SHA1%7D%7B4b3cf228%7D%7BmWlzhg%3D%3D%7D&openid.ax.mode=fetch_request&openid.identity=http%3A%2F%2Frichdev.myopenid.com%2F&openid.mode=checkid_setup&openid.return_to=http%3A%2F%2Flocalhost%3A3001%2Fuser_sessions%2Fcreate%3Ffor_session%3D1%26_method%3Dpost%26open_id_complete%3D1%26openid1_claimed_id%3Dhttp%253A%252F%252Frichdev.myopenid.com%252F%26rp_nonce%3D2009-12-31T19%253A35%253A59ZUEd2eN&openid.trust_root=http%3A%2F%2Flocalhost%3A3001%2F
Completed in 15ms (DB: 0) | 302 Found [http://localhost/user_sessions]
Processing ApplicationController#index (for 127.0.0.1 at 2009-12-31 11:36:00) [POST]
Parameters: {"openid.mode"=>"id_res", "openid.return_to"=>"http://localhost:3001/user_sessions/create?for_session=1&_method=post&open_id_complete=1&openid1_claimed_id=http%3A%2F%2Frichdev.myopenid.com%2F&rp_nonce=2009-12-31T19%3A35%3A59ZUEd2eN", "openid.sig"=>"l+tfFAmeKsskHKlOYRoZF7yHM7Q=", "rp_nonce"=>"2009-12-31T19:35:59ZUEd2eN", "openid.op_endpoint"=>"http://www.myopenid.com/server", "for_session"=>"1", "openid.response_nonce"=>"2009-12-31T19:36:00ZBhX5fE", "openid1_claimed_id"=>"http://richdev.myopenid.com/", "openid.identity"=>"http://richdev.myopenid.com/", "open_id_complete"=>"1", "openid.assoc_handle"=>"{HMAC-SHA1}{4b3cf228}{mWlzhg==}", "openid.signed"=>"assoc_handle,identity,mode,op_endpoint,response_nonce,return_to,signed"}
ActionController::MethodNotAllowed (Only get, put, and delete requests are allowed.):
Rendered rescues/_trace (96.3ms)
Rendered rescues/_request_and_response (0.5ms)
Rendering rescues/layout (method_not_allowed)
The problem seems to occur during the redirect back from the openid provider, at which point ApplicationController#index gets called, instead of UserSessionsController#create. I'm not sure if this is an OpenID issue or a Warp Drive issue.
How can I bundle an Authlogic/OpenID application as a Warp Drive Gem and get authentication to work successfully?
Update: Adding an explicit resource definition for user_session fixes the problem. In routes.rb:
map.resources :user_sessions
Not sure why, and this doesn't seem to be required for any other controller.
Two things worked:
Add an explicit user_session resource definition in routes.rb:
map.resources :user_sessions
Remove default routes in routes.rb of the app using the warp drive gem.
Removing default routes in routes.rb
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
solved a horrific routing issue where a resource routing in the warp drive:
map.resources :users, :member => {:activate => [:post, :get]}
created a URL: /users/:id/activate(.:format)
But an HTTP request to that URL resulted in the :action and :id getting reversed when passed to the controller (as if interpreted as a default URL). e.g.
Parameters = {"action"=>"123456", "id"=>"activate", "controller"=>"users"}
Not pretty. Removing the default routes in the warp drive or the client app did it. Seems safer to do it in the client app, though.