Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

install plugin, add some views/models/controllers

  • Loading branch information...
commit eeedf8af432aa001005efdd99e7af95331955edc 1 parent 143a53c
@grosser authored
View
5 README.md
@@ -1,6 +1,9 @@
An example Rails 3 application that uses [Restful catch all routes Rails plugin](http://github.com/grosser/restful_catch_all_route)
+ git clone git://github.com/grosser/restful_catch_all_route_example.git
+ cd restful_catch_all_route_example
bundle install
+ rake db:migrate
rails server
-[http://localhost:3000](http://localhost:3000)
+and visit [http://localhost:3000](http://localhost:3000) !
View
38 app/controllers/users_controller.rb
@@ -0,0 +1,38 @@
+class UsersController < ApplicationController
+ def index
+ end
+
+ def new
+ @user = User.new
+ end
+
+ def create
+ @user = User.new(params[:user])
+ if @user.save
+ redirect_to @user
+ else
+ render :action => :new
+ end
+ end
+
+ def edit
+ @user = User.find(params[:id])
+ end
+
+ def update
+ @user = User.find(params[:id])
+ if @user.update_attributes(params[:user])
+ redirect_to @user
+ else
+ render :action => :edit
+ end
+ end
+
+ def show
+ @user = User.find(params[:id])
+ end
+
+ def small
+ @user = User.find(params[:id])
+ end
+end
View
2  app/models/user.rb
@@ -0,0 +1,2 @@
+class User < ActiveRecord::Base
+end
View
4 app/views/users/_form.erb
@@ -0,0 +1,4 @@
+<% form_for @user do |f| %>
+ <%= f.text_field :name %>
+ <%= f.submit %>
+<% end %>
View
2  app/views/users/edit.erb
@@ -0,0 +1,2 @@
+This is edit, submit the form!
+<%= render 'form' %>
View
13 app/views/users/index.erb
@@ -0,0 +1,13 @@
+This is <%= link_to 'index', User %>
+<br />
+
+<table>
+ <% User.all.each do |user| %>
+ <tr><td><%= link_to user.name, user %></td></tr>
+ <% end %>
+</table>
+
+<br />
+If you like it you may also like:<br />
+<%= link_to 'new', :controller => :users, :action => :new %> or
+<%= link_to 'search', :action => :search %>
View
2  app/views/users/new.erb
@@ -0,0 +1,2 @@
+This is new, submit the form!
+<%= render 'form' %>
View
1  app/views/users/search.erb
@@ -0,0 +1 @@
+This is search .. im just a boring example...
View
3  app/views/users/show.erb
@@ -0,0 +1,3 @@
+I am <%=@user.name%>
+<%= link_to @user.name+' but i can be small', polymorphic_url(@user, :action => :small) %>
+<%= link_to 'edit', polymorphic_url(@user, :action => :edit) %>
View
2  app/views/users/small.erb
@@ -0,0 +1,2 @@
+I am small :D
+<%= link_to @user.name, @user %>
View
3  config/routes.rb
@@ -1,2 +1,3 @@
-RestfulCatchAllRouteExample::Application.routes.draw do
+RestfulCatchAllRouteExample::Application.routes.draw do |map|
+ map.restful_catch_all_route
end
View
11 db/migrate/20100321082357_initial.rb
@@ -0,0 +1,11 @@
+class Initial < ActiveRecord::Migration
+ def self.up
+ create_table :users do |t|
+ t.string :name
+ end
+ end
+
+ def self.down
+ drop_table :users
+ end
+end
View
18 db/schema.rb
@@ -0,0 +1,18 @@
+# This file is auto-generated from the current state of the database. Instead of editing this file,
+# please use the migrations feature of Active Record to incrementally modify your database, and
+# then regenerate this schema definition.
+#
+# Note that this schema.rb definition is the authoritative source for your database schema. If you need
+# to create the application database on another system, you should be using db:schema:load, not running
+# all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations
+# you'll amass, the slower it'll run and the greater likelihood for issues).
+#
+# It's strongly recommended to check this file into your version control system.
+
+ActiveRecord::Schema.define(:version => 20100321082357) do
+
+ create_table "users", :force => true do |t|
+ t.string "name"
+ end
+
+end
View
63 vendor/plugins/restful_catch_all_route/README.markdown
@@ -0,0 +1,63 @@
+One rule, no worries (Rails 2 + 3)
+
+ - resources like normal (get:show, put:update, delete:destroy, post:create, edit, new, index, etc.)
+ - no resources need to be added
+ - no actions (aka collection/member) need to be added
+ - no _url / _path / _hash helpers in global namespace
+ - `form_for @user` / `link_to xxx, @user` / `polymorphic_url @user` like normal
+ - you can always add normal resources for edge-cases (e.g. nesting)
+ - [restful catch all route example app](http://github.com/grosser/restful_catch_all_route_example)
+
+
+Install
+=======
+
+ script/plugins install git://github.com/grosser/restful_catch_all_route.git
+
+ # config/routes.rb
+ map.restful_catch_all_route
+
+ # if you need REST-less fallback urls, they must be placed after restful catch all
+ # map.connect ':controller/:action/:id'
+
+Usage
+=====
+
+ # like normal:
+ form_for @user
+ link_to 'hey', @user
+ polymorphic_url(@user)
+
+ # changed:
+ link_to 'foo', new_users_path
+
+ # is now...
+ link_to 'foo', '/users/new'
+ link_to 'foo', :controller => 'users', :action => 'new'
+
+
+### Id formats
+By default it accepts ids that are pure numbers, or contain a '-'.
+You can overwrite it by passing `:id => /my_rex/`
+
+ - `/my_controller/1/edit` - works
+ - `/my_controller/1-fancy-title/edit` - works
+ - `/my_controller/fancy-title/edit` - works
+ - `/my_controller/fancy_title/edit` - works NOT
+
+Performance
+===========
+Rails 2.3.5 with 50 resources 100_000 times
+
+<table>
+<tr><td></td><td>Recognition</td><td>Generation</td><td>RAM</td><td>Helpers</td></tr>
+<tr><td>catch all</td><td>9.1s</td><td>6.6</td><td></td><td>200+ (1</td></tr>
+<tr><td>resources</td><td>68.2s</td><td>9.5</td><td>+9MB</td><td>0</td></tr>
+</table>
+(1 `50 * (xxx_path + xxxs_path + new_xxx_path + edit_xxx_path + custom members)`
+
+Author
+======
+[Michael Grosser](http://pragmatig.wordpress.com)
+grosser.michael@gmail.com
+Hereby placed under public domain, do what you want, just do not hold me accountable...
View
3  vendor/plugins/restful_catch_all_route/Rakefile
@@ -0,0 +1,3 @@
+task :default => :spec
+require 'spec/rake/spectask'
+Spec::Rake::SpecTask.new {|t| t.spec_opts = ['--color']}
View
55 vendor/plugins/restful_catch_all_route/benchmark/benchmark.rake
@@ -0,0 +1,55 @@
+TEST_CONTROLLERS = ('aa'..'bz').to_a # 52 controllers
+
+def router
+ ActionController::Routing::Routes
+end
+
+def memory
+ pid = Process.pid
+ map = `pmap -d #{pid}`
+ map.split("\n").last.strip.squeeze(' ').split(' ')[3].to_i
+end
+
+def run_bench
+ num = 100_000
+
+ TEST_CONTROLLERS.each{|c| send("#{c}_url")}
+
+ x = Benchmark.realtime do
+ num.times do
+ router.recognize_path("/#{TEST_CONTROLLERS.rand}/123/test", :method => :get)
+ end
+ end
+ puts "Recognition: #{x}"
+
+ x = Benchmark.realtime do
+ num.times do
+ # get one of the middle controllers for an even benchmark
+ generated_path, extra_keys = router.generate_extras({:controller => TEST_CONTROLLERS.rand, :action => :test, :id => '123'}, {})
+ end
+ end
+ puts "Generation: #{x}"
+ puts "Memory: #{memory}"
+end
+
+task :bench_catch_all => :environment do
+ ActionController::Routing.use_controllers!(TEST_CONTROLLERS)
+ router.draw do |map|
+ map.restful_catch_all_route
+ map.connect ':controller/:action/:id'
+ end
+
+ run_bench
+end
+
+task :bench_resources => :environment do
+ ActionController::Routing.use_controllers!(TEST_CONTROLLERS)
+
+ router.draw do |map|
+ # resource with some members to emulate normal usage
+ TEST_CONTROLLERS.each{|c| map.resources c, :member => {:test => :get, :something => :post}, :collection => {:xxx => :get, :yyy => :get}}
+ map.connect ':controller/:action/:id'
+ end
+
+ run_bench
+end
View
15 vendor/plugins/restful_catch_all_route/benchmark/simple.rb
@@ -0,0 +1,15 @@
+folder = '/tmp/rest'
+
+# make app
+system "rm -rf #{folder}"
+system "mkdir -p #{folder}"
+system "cd #{folder}/.. && rails rest"
+
+# copy plugin
+puts here = File.dirname(File.dirname(File.expand_path(__FILE__)))
+system "cp -R #{here} #{folder}/vendor/plugins"
+
+# run benchmark
+system "cp #{here}/benchmark/benchmark.rake #{folder}/lib/tasks"
+system "cd #{folder} && rake bench_catch_all --trace"
+system "cd #{folder} && rake bench_resources --trace"
View
1  vendor/plugins/restful_catch_all_route/init.rb
@@ -0,0 +1 @@
+require 'restful_catch_all_route'
View
49 vendor/plugins/restful_catch_all_route/lib/restful_catch_all_route.rb
@@ -0,0 +1,49 @@
+klass = if ActionPack::VERSION::MAJOR >= 3
+ ActionDispatch::Routing::DeprecatedMapper
+else
+ ActionController::Routing::RouteSet::Mapper
+end
+
+klass.class_eval do
+ def restful_catch_all_route(options={})
+ id_rexp = options[:id] || /[^-\/]*-[^\/]*|\d+/
+ connect '/:controller', :action => :index, :conditions => { :method => :get }
+ connect '/:controller', :action => :create, :conditions => { :method => :post }
+ connect '/:controller/:id', :action => :show, :conditions => { :method => :get }, :requirements => { :id => id_rexp }
+ connect '/:controller/:id', :action => :update, :conditions => { :method => :put }, :requirements => { :id => id_rexp }
+ connect '/:controller/:id', :action => :destroy, :conditions => { :method => :delete }, :requirements => { :id => id_rexp }
+ connect '/:controller/:id/:action', :requirements => { :id => id_rexp } # member
+ connect '/:controller/:action' # collection
+ end
+end
+
+# if something like `unknown method 'users_path'` is raised
+# convert it into :controller => :users
+module ActionController::PolymorphicRoutes
+ def polymorphic_url_with_restful_fallback(*args, &block)
+ begin
+ polymorphic_url_without_restful_fallback(*args, &block)
+ rescue NoMethodError => error
+ model = [*args.first] # called with [<User>] or <User>
+ raise error if model.compact.size != 1 # something like [:admin, <User>], [nil,<User>], ..
+ model = model.first
+
+ options = (args.last.is_a?(Hash) ? args.last.dup : {})
+ options.delete(:routing_type)
+
+ model_name = (model.is_a?(Class) ? model : model.class).class_name.underscore
+
+ raise error unless error.to_s =~ /\W((.*?)_)?(#{model_name}|#{model_name.pluralize})_(path|url)\W/
+
+ options.reverse_merge!(:controller => model_name.pluralize, :action => $2)
+ options.reverse_merge!(:only_path => ($4 == 'path'))
+ if not model.is_a?(Class) and model.respond_to?(:new_record?) and not model.new_record?
+ options.reverse_merge!(:id => model.to_param)
+ options[:action] ||= :show # or it would be users?id=1 instead of users/1
+ end
+
+ url_for(options)
+ end
+ end
+ alias_method_chain :polymorphic_url, :restful_fallback
+end
View
113 vendor/plugins/restful_catch_all_route/spec/restful_catch_all_route_spec.rb
@@ -0,0 +1,113 @@
+require 'rubygems'
+gem 'actionpack', '~>2.3'
+gem 'activesupport', '~>2.3'
+require 'action_pack'
+require 'action_controller'
+begin; require 'redgreen'; rescue LoadError; end
+$LOAD_PATH << 'lib'
+require 'restful_catch_all_route'
+
+ActionController::Base.logger = nil
+ActionController::Routing::Routes.reload!
+
+ActionController::Routing.use_controllers!(['cheap'])
+
+ActionController::Routing::Routes.draw do |map|
+ map.restful_catch_all_route
+ map.connect ':controller/:action/:id'
+end
+
+describe 'Routing' do
+ def router
+ ActionController::Routing::Routes
+ end
+
+ describe 'recognition' do
+ def params_from(method, path)
+ ActionController::Routing::Routes.reload if ActionController::Routing::Routes.empty?
+ router.recognize_path(path, :method => method)
+ end
+
+ it "recognizes index" do
+ params_from(:get, "/cheap").should == {:controller => 'cheap', :action => 'index'}
+ end
+
+ it "recognizes create" do
+ params_from(:post, "/cheap").should == {:controller => 'cheap', :action => 'create'}
+ end
+
+ it "recognizes show" do
+ params_from(:get, "/cheap/1").should == {:controller => 'cheap', :action => 'show', :id => '1'}
+ end
+
+ it "recognizes update" do
+ params_from(:put, "/cheap/1").should == {:controller => 'cheap', :action => 'update', :id => '1'}
+ end
+
+ it "recognizes destroy" do
+ params_from(:delete, "/cheap/1").should == {:controller => 'cheap', :action => 'destroy', :id => '1'}
+ end
+
+ it "recognizes members" do
+ params_from(:get, "/cheap/1/xxx").should == {:controller => 'cheap', :action => 'xxx', :id => '1'}
+ end
+
+ it "recognizes collections" do
+ params_from(:get, "/cheap/xxx").should == {:controller => 'cheap', :action => 'xxx'}
+ end
+
+ it "recognizes to_param urls with number-text-text" do
+ params_from(:get, "/cheap/111-abc-def/xxx").should == {:controller => 'cheap', :action => 'xxx', :id => '111-abc-def'}
+ end
+
+ it "recognizes to_param urls with text-text" do
+ params_from(:get, "/cheap/abc-def/xxx").should == {:controller => 'cheap', :action => 'xxx', :id => 'abc-def'}
+ end
+
+ it "does not recognizes to_param urls with simple text" do
+ params_from(:get, "/cheap/abc/xxx").should == {:controller => 'cheap', :action => 'abc', :id => 'xxx'}
+ end
+
+ it "does not recognizes to_param urls with method-name like names" do
+ params_from(:get, "/cheap/step1/xxx").should == {:controller => 'cheap', :action => 'step1', :id => 'xxx'}
+ end
+
+ it "leaves room for old catch-all rule" do
+ params_from(:get, "/cheap/xxx/111").should == {:controller => 'cheap', :action => 'xxx', :id => '111'}
+ end
+ end
+
+ describe 'generation' do
+ def generate(options)
+ ActionController::Routing::Routes.reload if ActionController::Routing::Routes.empty?
+ router.generate(options)
+ end
+
+ it "generates index without action" do
+ generate(:controller => :cheap).should == "/cheap"
+ end
+
+ it "generates index with action" do
+ generate(:controller => :cheap, :action => :index).should == "/cheap"
+ end
+
+ it "generates collection actions" do
+ generate(:controller => :cheap, :action => :foo).should == "/cheap/foo"
+ end
+
+ it "generates show" do
+ pending 'works, but not in tests.. :P'
+ generate(:controller => :cheap, :id => '1').should == "/cheap/1"
+ end
+
+ it "generates show with action" do
+ pending 'works, but not in tests.. :P'
+ generate(:controller => :cheap, :id => '1', :action => :show).should == "/cheap/1"
+ end
+
+ it "generates member actions" do
+ pending 'works, but not in tests.. :P'
+ generate(:controller => :cheap, :id => '1', :action => :edit).should == "/cheap/1/edit"
+ end
+ end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.