jonleighton / focused_controller

MIT License
468 stars 27 forks source link

Named routes #12

Closed george closed 12 years ago

george commented 12 years ago

The focused_controller_routes helper appears to not support the as: 'named_route' construct:

focused_controller_routes do 
  get '/login'  =>  'sessions#new',     as: 'login' 
  get '/logout' =>  'sessions#destroy', as: 'logout' 

  resources :sessions 
end

rake routes:

       login GET    /login(.:format)                           sessions#new
      logout GET    /logout(.:format)                          sessions#destroy
    sessions GET    /sessions(.:format)                        SessionsController::Index
             POST   /sessions(.:format)                        SessionsController::Create
 new_session GET    /sessions/new(.:format)                    SessionsController::New
edit_session GET    /sessions/:id/edit(.:format)               SessionsController::Edit
     session GET    /sessions/:id(.:format)                    SessionsController::Show
             PUT    /sessions/:id(.:format)                    SessionsController::Update
             DELETE /sessions/:id(.:format)                    SessionsController::Destroy

@jonleighton provided a workaround on the mailing list, which works well:

focused_controller_routes do
  get '/login'  =>  'SessionsController::New',     as: 'login'
  get '/logout' =>  'SessionsController::Destroy', as: 'logout'

  resources :sessions
end

       login GET    /login(.:format)                           SessionsController::New
      logout GET    /logout(.:format)                          SessionsController::Destroy
    sessions GET    /sessions(.:format)                        SessionsController::Index
             POST   /sessions(.:format)                        SessionsController::Create
 new_session GET    /sessions/new(.:format)                    SessionsController::New
edit_session GET    /sessions/:id/edit(.:format)               SessionsController::Edit
     session GET    /sessions/:id(.:format)                    SessionsController::Show
             PUT    /sessions/:id(.:format)                    SessionsController::Update
             DELETE /sessions/:id(.:format)                    SessionsController::Destroy

If I can make some time, I'll take a crack at a patch. I took a cursory look at it, but I don't yet understand how it's all working. Any direction someone could provide would be most welcomed.

dyba commented 12 years ago

Here's preliminary code:

# lib/focused_controller/route_mapper.rb
  def to_option
    if @options[:to] && @options[:to].match(/^[\w\d]+\#[\w\d]+$/) # Handles simple case i.e. 'sessions#new'
      name = ''
      controller, action = @options[:to].split('#')
      name << controller.camelize << 'Controller::'
      name << action.camelize
      name
    elsif @options[:to] && !@options[:to].respond_to?(:call)
      @options[:to]
    # more code ...

and the tests to make it work:

  it 'creates routes that map to focused controllers' do
    route_set.draw do
      focused_controller_routes do
        match 'posts' => 'PostsController::Index'
        get 'login' => 'sessions#new', as: 'login'

        resources :sessions

        resources :comments do
          resources :replies
        end

        resource :account

        namespace :admin do
          resources :comments
        end
      end
    end

    mappings = {
      [:get, '/login']        => 'SessionsController::New',
      # more code...

Problem is, the test test_0002_doesn_t_mess_with_callable_routes doesn't pass because that test uses an Object with a dummy call method. @jonleighton any suggestions as to how I should handle the failing test case?

jonleighton commented 12 years ago

Well 'sessions#new' doesn't response to #call so you could put another conditional under what is now the first branch I think.

Have you looked into re-using the existing code in Rails that matches e.g. sessions#new? Ideally we would hook into that, but this part of rails is quite a mess so it may not be possible.

dyba commented 12 years ago

Good idea. I had a hunch Rails might have done that already but didn't venture to look. Let me see what I find in Rails.

dyba commented 12 years ago

OK, I found the line in the ActionDispatch library here that has the functionality I'm looking for. I'll take another stab at the code with this in mind.

dyba commented 12 years ago

I'd like to call the private method default_controller_and_action in ActionDispatch::Routing::Mapper from my preliminary code above, but that sounds like code blasphemy. @jonleighton looks like I would have to clean up the Mapper class to tackle the present issue. Who would you recommend I send Rails patches for review? I've submitting unaccepted/ignored patches in the past to the rails repo. Now I understand it is better if someone reviews them beforehand; it is more likely they'll get accepted.

jonleighton commented 12 years ago

The entire of ActionDispatch::Routing::Mapper needs to be refactored really... but either way we still need to support old versions of Rails in Focused Controller. So tbh I would just use send to call the private method - we're already monkey patching anyway.

kristianmandrup commented 12 years ago

Could one of you please explain the option[:to] here?

I've been looking at the docs for #url_for at http://apidock.com/rails/ActionDispatch/Routing/UrlFor/url_for to try to get a clue, but nothing there that I see...

I'm trying to get this to work:

  def wizard_path(goto_step = nil, options = {})
    options = { 
                :controller => wicked_controller,
                :action     => 'show',
                :id         => goto_step || params[:id],
                :only_path  => true
               }.merge options

    # options = FocusedController::RouteMapper.new(options, options).options               
    puts "url to: #{options}"

    url_for(options)
  end

If I leave out the use of the RouteMapper which adds the :to option, I get:

ActionController::RoutingError: No route matches {:controller=>"JumpController", :action=>"show", :id=>:last_step}

module JumpController
  class Show < Action
    def run
       # ...
    end
  end
end

What's the secret here?

https://github.com/kristianmandrup/wicked-focused