Fixing rails 5 deprecation warning for matching routes - ruby-on-rails-5

In my routes.rb file, I have the following
resources :landings, only: [:index],
path: '/golf' do
collection do
get 'break_70', path: 'how-to-break-70'
end
end
which generates a url
/golf/how-to-break-70
After upgrading to Rails 5, this generates the following deprecation message:
DEPRECATION WARNING: Specifying strings for both :path and the route path is deprecated. Change things like this:
match "break_70", :path => "how-to-break-70"
to this:
match "how-to-break-70", :as => "break_70", :action => "break_70"
If I try to follow these directions with
resources :landings, only: [:index],
match: '/golf' do
collection do
match: 'how-to-break-70', as: 'break_70', action: 'break_70'
end
end
then I get the following error
syntax error, unexpected ':', expecting keyword_end
match: 'how-to-break-70', as: 'break_70', action: 'break_70'
How do I modify this route to avoid the deprecation warning?

Updated Answer
I update my answer to fix a little mistake so any reader can see a working code. Thanks #Obromios for the little fix.
In resources it should still be path:.
And in the route definition you have an extra ":" after match. Also you have to specify via: [:get, :post] if you match.
So the final version looks like:
resources :landings, only: [:index], path: '/golf' do
collection do
match 'how-to-break-70', as: 'break_70', action: 'break_70', via: [:get, :post]
end
end
Original Answer
In resources it should still be path:.
And in the route definition you have an extra ":" after match
So the final version looks like:
resources :landings, only: [:index], path: '/golf' do
collection do
match 'how-to-break-70', as: 'break_70', action: 'break_70'
end
end
Not tested, but should work.

Related

Rails' routes: how to pass "all" request params in a redirect

I want to redirect all root requests to a /pages/home url, but I want to keep all the params used in the original request.
So:
http://myserver.com/?param1=value1&param2=value2
Becomes
http://myserver.com/pages/home?param1=value1&param2=value2
There are several SO questions about passing params in a redirect but I haven't found any related to passing request's params.
The other answer works but leaves a ? at the end in case there are no parameters.
This seems to do the trick without the side effects:
root to: redirect(path: '/quick_searches/new')
Hope it helps!
# routes.rb
root :to => redirect { |params, request| "/pages/home?#{request.params.to_query}" }
Update 1
You can also play with the request.params to build the new path:
root :to => redirect { |params, request| "/pages/#{request.params[:page]}.html?#{request.params.to_query}" }
In Rails 5, this can be now be done concisely simply by rewriting ONLY the path component in the redirect (so all original query params will be retained):
# in routes.rb
root to: redirect(path: '/pages/home')
Relevant documentation link:
http://api.rubyonrails.org/classes/ActionDispatch/Routing/Redirection.html
Building on #fguillen's answer for Rails4
You need two lines in routes.rb
# in routes.rb
match "/pages/home", to: 'pages#index', via: :get
match "/", to: redirect{ |params, request| [ "/pages/home", request.env["rack.request.query_string"] ].join("?") }, via: :all
The join on an array also handles the dangling question mark at the end in case there are no parameters.

undefined local variable or method `new_admin_company' with new namespace

I have moved to a namespace for the CRUD operations of my rails application. In my routes file i've done:
namespace :admin do
root :to => 'companies#index'
resources :events
resources :vacancies
resources :contacts
resources :companies do
get :getCompanies, :on => :collection
end
end
I get this when I run rake routes:
admin_root /admin(.:format) admin/companies#index
admin_events GET /admin/events(.:format) admin/events#index
POST /admin/events(.:format) admin/events#create
new_admin_event GET /admin/events/new(.:format) admin/events#new
edit_admin_event GET /admin/events/:id/edit(.:format) admin/events#edit
admin_event GET /admin/events/:id(.:format) admin/events#show
PUT /admin/events/:id(.:format) admin/events#update
DELETE /admin/events/:id(.:format) admin/events#destroy
admin_vacancies GET /admin/vacancies(.:format) admin/vacancies#index
POST /admin/vacancies(.:format) admin/vacancies#create
new_admin_vacancy GET /admin/vacancies/new(.:format) admin/vacancies#new
edit_admin_vacancy GET /admin/vacancies/:id/edit(.:format) admin/vacancies#edit
admin_vacancy GET /admin/vacancies/:id(.:format) admin/vacancies#show
PUT /admin/vacancies/:id(.:format) admin/vacancies#update
DELETE /admin/vacancies/:id(.:format) admin/vacancies#destroy
admin_contacts GET /admin/contacts(.:format) admin/contacts#index
POST /admin/contacts(.:format) admin/contacts#create
new_admin_contact GET /admin/contacts/new(.:format) admin/contacts#new
edit_admin_contact GET /admin/contacts/:id/edit(.:format) admin/contacts#edit
admin_contact GET /admin/contacts/:id(.:format) admin/contacts#show
PUT /admin/contacts/:id(.:format) admin/contacts#update
DELETE /admin/contacts/:id(.:format) admin/contacts#destroy
getCompanies_admin_companies GET /admin/companies/getCompanies(.:format) admin/companies#getCompanies
admin_companies GET /admin/companies(.:format) admin/companies#index
POST /admin/companies(.:format) admin/companies#create
new_admin_company GET /admin/companies/new(.:format) admin/companies#new
edit_admin_company GET /admin/companies/:id/edit(.:format) admin/companies#edit
admin_company GET /admin/companies/:id(.:format) admin/companies#show
PUT /admin/companies/:id(.:format) admin/companies#update
DELETE /admin/companies/:id(.:format) admin/companies#destroy
Yet i'm getting the error:
undefined local variable or method `new_admin_company'
So what have I forgot to do when moving things to a namespace?
It should be new_admin_company_path.
check if you have the method "new" in your company controller.

How can I restrict access ActiveAdmin login page by ip?

rails version
rails 3.2.1
Goal:
Access ActiveAdmin login page only office computer.
Code:
route.rb
constraints(:ip => /(^127.0.0.1$)|(^192.168.10.[0-9]*$)/) do
match 'admin/' => 'admin#login'
end
It is not work, any suesstion?
==========================
I edit my route.rb follow code
constraints(:ip => /(^127.0.0.1$)|(^192.168.10.[0-9]*$)/) do
ActiveAdmin.routes(self)
end
devise_for :admin_users, ActiveAdmin::Devise.config
it's work!
Refer to Rails guides Chapter routing (http://guides.rubyonrails.org/routing.html#advanced-constraints):
class WhitelistConstraint
  def initialize
    #ips = Whitelist.retrieve_ips
  end
 
  def matches?(request)
    #ips.include?(request.remote_ip)
  end
end
 
TwitterClone::Application.routes.draw do
  match 'admin/' => 'admin#login',
    :constraints => WhitelistConstraint.new
end
I'm sure this can also be done using another way but I'm sure you get the point.
I use this way, because you are able to move some logic out into a class if it is too complex for routes.
This class must have a matches? method defined on it which either returns true if the user should be given access to that route, or false if the user should not.
It helps me to add ips to the array without regex.
I hope, it helps someone)
More info - https://api.rubyonrails.org/v5.2.2/classes/ActionDispatch/Routing/Mapper/Scoping.html#method-i-constraints
class WhitelistConstraint
IPS = %w[
143.132.200.43,
]
def self.matches?(request)
IPS.include?(request.remote_ip)
end
end
Rails.application.routes.draw do
constraints(WhitelistConstraint) do
ActiveAdmin.routes(self)
mount Sidekiq::Web => '/sidekiq'
end
end

assert_routing with method is giving an error instead of failing

In my rails 3.2.3 app, I have a topics controller, which is modeled as a resource. I want to write a functional test to verify that post on /topics is a valid route. This should fail first, and then I will add the code to fix it. However, I am getting an error in the routing test, instead of a failure. What am I doing wrong?(Note: If I fix the route in routes.rb, the test passes - just not sure why I am getting an error instead of a failure in the test):
# topics_controller_test.rb
test 'route exists to create topic' do
assert_routing({:path => '/topics', :method => 'post'} , { :controller => "topics", :action => "create"}, {}, {}, 'could not route to create topic')
end
# routes.rb
resources :topics, :only => [:new]
# terminal output
$ rake test:functionals
Run options:
# Running tests:
.....E.
Finished tests in 0.373543s, 18.7395 tests/s, 53.5414 assertions/s.
1) Error:
test_route_exists_to_create_topic(TopicsControllerTest):
ActionController::RoutingError: No route matches "/topics"
.../gems/ruby-1.9.3-p0/gems/actionpack-3.2.3/lib/action_dispatch/routing/route_set.rb:633:in `recognize_path'
.../gems/ruby-1.9.3-p0/gems/actionpack-3.2.3/lib/action_dispatch/testing/assertions/routing.rb:210:in `recognized_request_for'
.../gems/ruby-1.9.3-p0/gems/actionpack-3.2.3/lib/action_dispatch/testing/assertions/routing.rb:42:in `assert_recognizes'
.../gems/ruby-1.9.3-p0/gems/actionpack-3.2.3/lib/action_dispatch/testing/assertions/routing.rb:118:in `assert_routing'
`.../myapp/test/functional/topics_controller_test.rb:25:in block in <class:TopicsControllerTest>'`
>> 7 tests, 20 assertions, 0 failures, 1 errors, 0 skips
The created route in routes.rb is different from the route your testing. If you want to route to the :create action in the controller, in your routes.rb you should use:
resources :topics, :only => [:create]
See the routing topic in the RailsGuides.

How do I write a Rails 3.1 engine controller test in rspec?

I have written a Rails 3.1 engine with the namespace Posts. Hence, my controllers are found in app/controllers/posts/, my models in app/models/posts, etc. I can test the models just fine. The spec for one model looks like...
module Posts
describe Post do
describe 'Associations' do
it ...
end
... and everything works fine.
However, the specs for the controllers do not work. The Rails engine is mounted at /posts, yet the controller is Posts::PostController. Thus, the tests look for the controller route to be posts/posts.
describe "GET index" do
it "assigns all posts as #posts" do
Posts::Post.stub(:all) { [mock_post] }
get :index
assigns(:posts).should eq([mock_post])
end
end
which yields...
1) Posts::PostsController GET index assigns all posts as #posts
Failure/Error: get :index
ActionController::RoutingError:
No route matches {:controller=>"posts/posts"}
# ./spec/controllers/posts/posts_controller_spec.rb:16
I've tried all sorts of tricks in the test app's routes file... :namespace, etc, to no avail.
How do I make this work? It seems like it won't, since the engine puts the controller at /posts, yet the namespacing puts the controller at /posts/posts for the purpose of testing.
I'm assuming you're testing your engine with a dummy rails app, like the one that would be generated by enginex.
Your engine should be mounted in the dummy app:
In spec/dummy/config/routes.rb:
Dummy::Application.routes.draw do
mount Posts::Engine => '/posts-prefix'
end
My second assumption is that your engine is isolated:
In lib/posts.rb:
module Posts
class Engine < Rails::Engine
isolate_namespace Posts
end
end
I don't know if these two assumptions are really required, but that is how my own engine is structured.
The workaround is quite simple, instead of this
get :show, :id => 1
use this
get :show, {:id => 1, :use_route => :posts}
The :posts symbol should be the name of your engine and NOT the path where it is mounted.
This works because the get method parameters are passed straight to ActionDispatch::Routing::RouteSet::Generator#initialize (defined here), which in turn uses #named_route to get the correct route from Rack::Mount::RouteSet#generate (see here and here).
Plunging into the rails internals is fun, but quite time consuming, I would not do this every day ;-) .
HTH
I worked around this issue by overriding the get, post, put, and delete methods that are provided, making it so they always pass use_route as a parameter.
I used Benoit's answer as a basis for this. Thanks buddy!
module ControllerHacks
def get(action, parameters = nil, session = nil, flash = nil)
process_action(action, parameters, session, flash, "GET")
end
# Executes a request simulating POST HTTP method and set/volley the response
def post(action, parameters = nil, session = nil, flash = nil)
process_action(action, parameters, session, flash, "POST")
end
# Executes a request simulating PUT HTTP method and set/volley the response
def put(action, parameters = nil, session = nil, flash = nil)
process_action(action, parameters, session, flash, "PUT")
end
# Executes a request simulating DELETE HTTP method and set/volley the response
def delete(action, parameters = nil, session = nil, flash = nil)
process_action(action, parameters, session, flash, "DELETE")
end
private
def process_action(action, parameters = nil, session = nil, flash = nil, method = "GET")
parameters ||= {}
process(action, parameters.merge!(:use_route => :my_engine), session, flash, method)
end
end
RSpec.configure do |c|
c.include ControllerHacks, :type => :controller
end
Use the rspec-rails routes directive:
describe MyEngine::WidgetsController do
routes { MyEngine::Engine.routes }
# Specs can use the engine's routes & named URL helpers
# without any other special code.
end
– RSpec Rails 2.14 official docs.
Based on this answer I chose the following solution:
#spec/spec_helper.rb
RSpec.configure do |config|
# other code
config.before(:each) { #routes = UserManager::Engine.routes }
end
The additional benefit is, that you don't need to have the before(:each) block in every controller-spec.
Solution for a problem when you don't have or cannot use isolate_namespace:
module Posts
class Engine < Rails::Engine
end
end
In controller specs, to fix routes:
get :show, {:id => 1, :use_route => :posts_engine}
Rails adds _engine to your app routes if you don't use isolate_namespace.
I'm developing a gem for my company that provides an API for the applications we're running. We're using Rails 3.0.9 still, with latest Rspec-Rails (2.10.1). I was having a similar issue where I had defined routes like so in my Rails engine gem.
match '/companyname/api_name' => 'CompanyName/ApiName/ControllerName#apimethod'
I was getting an error like
ActionController::RoutingError:
No route matches {:controller=>"company_name/api_name/controller_name", :action=>"apimethod"}
It turns out I just needed to redefine my route in underscore case so that RSpec could match it.
match '/companyname/api_name' => 'company_name/api_name/controller_name#apimethod'
I guess Rspec controller tests use a reverse lookup based on underscore case, whereas Rails will setup and interpret the route if you define it in camelcase or underscore case.
It was already mentioned about adding routes { MyEngine::Engine.routes }, although it's possible to specify this for all controller tests:
# spec/support/test_helpers/controller_routes.rb
module TestHelpers
module ControllerRoutes
extend ActiveSupport::Concern
included do
routes { MyEngine::Engine.routes }
end
end
end
and use in rails_helper.rb:
RSpec.configure do |config|
config.include TestHelpers::ControllerRoutes, type: :controller
end