Dynamic URL -> Controller mapping for routes in Rails

后端 未结 4 913
死守一世寂寞
死守一世寂寞 2020-12-13 10:55

I would like to be able to map URLs to Controllers dynamically based on information in my database.

I\'m looking to do something functionally equivalent to this (ass

相关标签:
4条回答
  • 2020-12-13 11:28

    As suggested in the question Rails routing to handle multiple domains on single application, I guess you could use Rails Routing - Advanced Constraints to build what you need.

    If you have a limited space of controllers (with unlimited views pointing to them), this should work. Just create a constraint for each controller that verifies if the current view matches them.

    Assuming you have a space of 2 controllers (PostController and CommentController), you could add the following to your routes.rb:

    match "*path" => "post#show", :constraints => PostConstraint.new
    match "*path" => "comment#show", :constraints => CommentConstraint.new
    

    Then, create lib/post_constraint.rb:

    class PostConstraint     
      def matches?(request)
        'post' == Rails.cache.fetch("/view_controller_map/#{request.params[:view_name]}") { View.find_by_name(request.params[:view_name]).controller }
      end
    end
    

    Finally, create lib/comment_constraint.rb:

    class CommentConstraint     
      def matches?(request)
        'comment' == Rails.cache.fetch("/view_controller_map/#{request.params[:view_name]}") { View.find_by_name(request.params[:view_name]).controller }
      end
    end
    

    You can do some improvements, like defining a super constraint class that fetches the cache, so you don't have to repeat code and don't risk fetching a wrong cache key name in one of the constraints.

    0 讨论(0)
  • 2020-12-13 11:30

    Here is a nice Rack Routing solution to SEO contributed by zetetic and Steve ross

    Testing Rack Routing Using rSpec

    It shows you how to write a custom dispatcher (where you can do a db lookup if needed) and with constraints, and testing as well.

    0 讨论(0)
  • 2020-12-13 11:51

    So I think that you are asking that if you have a Views table and a View model for it where the table looks like

    id | name | model
    ===================
    1  | aaa  | Post
    2  | bbb  | Post
    3  | ccc  | Comment
    

    You want a url of /aaa to point to Post.controller - is this right?

    If not then what you suggest seems fine assuming it works.

    You could send it to a catch all action and have the action look at the url, run the find_by_name and then call the correct controller from there.

    def catch_all
      View.find_by_name('aaa').controller.action
    end
    

    Update

    You can use redirect_to and even send the params. In the example below you I am sending the search parameters

    def catch_all
      new_controller = View.find_by_name('aaa').controller
      redirect_to :controller => new_controller, :action => :index, 
          :search => params[:search] 
    end
    
    0 讨论(0)
  • 2020-12-13 11:54

    This question is old, but I found it interesting. A fully working solution can be created in Rails 3 using router's capability to route to a Rack endpoint.

    Create the following Rack class:

        class MyRouter
          def call(env)
            # Matched from routes, you can access all matched parameters
            view_name= env['action_dispatch.request.path_parameters'][:view_name]
    
            # Compute these the way you like, possibly using view_name
            controller= 'post' 
            my_action= 'show'
    
            controller_class= (controller + '_controller').camelize.constantize
            controller_class.action(my_action.to_sym).call(env)
          end
        end
    

    In Routes

        match '/:view_name', :to => MyRouter.new, :via => :get
    

    Hint picked up from http://guides.rubyonrails.org/routing.html#routing-to-rack-applications which says "For the curious, 'posts#index' actually expands out to PostsController.action(:index), which returns a valid Rack application."

    A variant tested in Rails 3.2.13.

    0 讨论(0)
提交回复
热议问题