views:

13

answers:

1

I'm trying to generate an easy macro for a Rails app that uses Devise for authentication. Basically I want to ensure that when a user accesses a page that requires authentication, they're redirected to the login page. So something like this:

it_requires_authentication_for :index, :new, :create, :update

The desired results here should be obvious. My problem however is that I can't think of the best way to map each action to its appropriate http method (:get, :post etc...)

I started out with this:

def it_should_require_authentication_for(*actions)
  actions.each do |action|
    it "should require authentication for #{action}" do
      get action.to_sym
      response.should redirect_to( new_user_session_path )
    end
  end
end

Which of course only does the get. Can someone tell me how I might provide this macro for all actions? I'm assuming I need to somehow test if the action routes properly for a particular method, but I'm just not really sure.

Any help is greatly appreciated.

A: 

I'm using the following until I come up with something more elegant:

# controller_macros.rb
def it_should_recognize_and_generate_routes_for(controller, routes)
  describe "routing" do
    routes.each do |route|
      action   = route[:action].to_s
      method   = route[:method] || :get
      url      = controller + (route[:url] || '')
      params   = route.reject {|k, v| [:action, :method, :url].include?(k) }
      expected = { :controller => controller, :action => action }.merge(params)

      it "should recognize and generate '#{action}'" do
        { method => url }.should route_to(expected)
      end
    end
  end
end

# posts_controller_spec.rb
describe Forum::PostsController do
  it_should_recognize_and_generate_routes_for('forum/posts', [
    { :action => :new, :url => '/new' },
    { :action => :create, :method => :post },
    { :action => :show, :url => '/1', :id => '1' },
    { :action => :index },
    { :action => :edit, :url => '/1/edit', :id => '1' },
    { :action => :update, :method => :put, :url => '/1', :id => '1' },
    { :action => :destroy, :method => :delete, :url => '/1', :id => '1' }
  ])
end

BTW I still have to extend it to work with routes like:

get 'login' => 'user_sessions#new'
kschaper