設定済みのroutesをRails内部で動的にとる。

設定済みのroutesをRails内部で動的にとる。

家にいると無限にものを食べてしまい、無職期間中にどれだけ体重が増えるかこわい。

兎にも角にもとりあえずとる

rake routesで見れる感じのやつが欲しかったんです。

こういうので

class RoutesReader
  def self.all
    @stored ||= Rails.application.routes.routes.map do |route|
      controller = route.defaults[:controller]
      verb = %W{ GET POST PUT PATCH DELETE }.grep(route.verb).first.downcase.to_sym
      action = route.defaults[:action]
      path = route.path.spec.to_s.gsub(/\(\.:format\)/, "")
      params = path.scan(/:([a-zA-Z0-9_]+)/).flatten.collect(&:to_sym)
      {
        path: path,
        verb: verb,
        action: action.try(:to_sym),
        controller: controller,
        params: params
      }
    end
  end
end

はしょってますが、ドバッととれる。

RoutesReader.all
[{:path=>"/assets", :verb=>:get, :action=>nil,:controller=>nil, :params=>[]},
 {:path=>"/entry/new", :verb=>:get, :action=>:new, :controller=>"editor/entries", :params=>[]},
 {:path=>"/entry/new", :verb=>:post, :action=>:create, :controller=>"editor/entries", :params=>[]},
 {:path=>"/v/:id", :verb=>:get, :action=>:show, :controller=>"viewer/entries", :params=>[:id]},
 {:path=>"/m/:year/:month", :verb=>:get, :action=>:index_date, :controller=>"viewer/entries", :params=>[:year, :month]}]

なにをしたくてこんなことをしたのか

あるパス以下の行動には、必ず承認が必要であるというのはよくある設計ですが、それのテストを抜かりなくやるために何かないかな~と考えて、とりあえず総当たりはどうだろうとこういうことをしていた。

RoutesReader.all.each do |config|
  controller = eval(config[:controller].split('/').map(&:capitalize).join('::') << 'Controller') rescue next
  verb = config[:verb]
  action = config[:action]
  params = config[:params].map { |key| {key => 'params'} }
  login = case config[:path]
            when %r{^/entry/}
              <<-EOS
                activate_authlogic
                user = FactoryGirl.create(:user, :valid)
                UserSession.create!(user)
              EOS
            when %r{^/manager/}
              <<-EOS
                manager = FactoryGirl.create(:manager, :valid)
                sign_in manager, :manager
              EOS
            else
              # 指定パス以外はテストしない
              next
          end

  RSpec.describe controller, :type => :controller do
    describe "#{verb} ##{action}" do
      context 'when logined' do
        it do
          eval(login)
          begin
            send(verb, action, *params)
          rescue ActionController::ParameterMissing
            # do nothing
          end
          expect(response).not_to redirect_to(root_path)
        end
      end

      context 'when not logined' do
        it do
          send(verb, action, *params)
          expect(response).to redirect_to(root_path)
        end
      end
    end
  end
end

根本的に解決したい

controllerで承認するから各controllerのテストがいるわけで、routes側で承認を行えるなら一発で漏れがなくていいのでは?と思ってやってたのが、前回、前々回のroutes.rbで承認をやっていくやつです。