- completely refactored the test system to use a fake rails_root

- added XML tests
- renamed should_be_a_resource to should_be_restful



git-svn-id: https://svn.thoughtbot.com/plugins/shoulda/trunk@132 7bbfaf0e-4d1d-0410-9690-a8bb5f8ef2aa
This commit is contained in:
tsaleh 2007-07-14 18:35:51 +00:00
parent da341efd4c
commit 3a8b77d1a1
87 changed files with 97455 additions and 139 deletions

View File

@ -3,13 +3,11 @@ require 'rake/testtask'
require 'rake/rdoctask'
Rake::TestTask.new do |t|
t.libs << 'test'
t.pattern = 'test/*_test.rb'
t.libs << 'lib'
t.pattern = 'test/{unit,functional}/**/*_test.rb' # Update this line
t.verbose = true
end
# Generate the RDoc documentation
Rake::RDocTask.new { |rdoc|
rdoc.rdoc_dir = 'doc'
rdoc.title = "Shoulda -- Making your tests easy on the fingers and eyes"
@ -20,4 +18,3 @@ Rake::RDocTask.new { |rdoc|
desc 'Default: run tests.'
task :default => ['test']

View File

@ -6,26 +6,37 @@ class Test::Unit::TestCase
attr_accessor :redirect, :flash, :params, :render
end
attr_accessor :identifier, :klass, :object, :parent_params, :test_actions,
attr_accessor :identifier, :klass, :object, :parent,
:test_html_actions, :test_xml_actions,
:create, :update, :destroy
alias parents parent
def initialize
@create = ActionOptions.new
@update = ActionOptions.new
@destroy = ActionOptions.new
@test_actions = [:index, :show, :new, :edit, :create, :update, :destroy]
end
@test_html_actions = [:index, :show, :new, :edit, :create, :update, :destroy]
@test_xml_actions = [:index, :show, :create, :update, :destroy]
end
def normalize!(target)
@test_actions = @test_actions.map(&:to_sym)
@test_html_actions = @test_html_actions.map(&:to_sym)
@test_xml_actions = @test_xml_actions.map(&:to_sym)
@identifier ||= :id
@klass ||= target.name.gsub(/ControllerTest$/, '').singularize.constantize
@object ||= @klass.name.tableize.singularize
@parent_params ||= {}
@parent ||= []
@parent = [@parent] unless @parent.is_a? Array
@create.redirect ||= "#{@object}_url(record)"
@update.redirect ||= "#{@object}_url(record)"
@destroy.redirect ||= "#{@object.pluralize}_url"
singular_args = @parent.map {|n| "record.#{n}"}
@destroy.redirect ||= "#{@object.pluralize}_url(#{singular_args.join(', ')})"
singular_args << 'record'
@create.redirect ||= "#{@object}_url(#{singular_args.join(', ')})"
@update.redirect ||= "#{@object}_url(#{singular_args.join(', ')})"
@create.flash ||= /created/i
@update.flash ||= /updated/i
@ -36,24 +47,32 @@ class Test::Unit::TestCase
end
end
def self.should_be_a_resource(&blk)
def self.should_be_restful(&blk)
resource = ResourceOptions.new
blk.call(resource)
resource.normalize!(self)
make_show_test(resource) if resource.test_actions.include?(:show)
make_edit_test(resource) if resource.test_actions.include?(:edit)
make_index_test(resource) if resource.test_actions.include?(:index)
make_new_test(resource) if resource.test_actions.include?(:new)
make_destroy_test(resource) if resource.test_actions.include?(:destroy)
make_create_test(resource) if resource.test_actions.include?(:create)
make_update_test(resource) if resource.test_actions.include?(:update)
resource.test_html_actions.each do |action|
self.send(:"make_#{action}_html_test", resource) if self.respond_to? :"make_#{action}_html_test"
end
context "XML: " do
setup do
@request.accept = "application/xml"
end
resource.test_xml_actions.each do |action|
self.send(:"make_#{action}_xml_test", resource) if self.respond_to? :"make_#{action}_xml_test"
end
end
end
def self.make_show_test(res)
should "get show for @#{res.object} via params: #{pretty_param_string(res)}" do
assert(record = instance_variable_get("@#{res.object}"), "This test requires you to set @#{res.object} in your setup block")
get :show, res.parent_params.merge({ res.identifier => record.to_param })
def self.make_show_html_test(res)
# should "get show for @#{res.object} via params: #{pretty_param_string(res)}" do
should "get show for @#{res.object}" do
record = get_existing_record(res)
parent_params = make_parent_params(res, record)
get :show, parent_params.merge({ res.identifier => record.to_param })
assert assigns(res.klass.name.underscore.to_sym), "The show action isn't assigning to @#{res.klass.name.underscore}"
assert_response :success
assert_template 'show'
@ -61,10 +80,12 @@ class Test::Unit::TestCase
end
end
def self.make_edit_test(res)
should "get edit for @#{res.object} via params: #{pretty_param_string(res)}" do
assert(record = instance_variable_get("@#{res.object}"), "This test requires you to set @#{res.object} in your setup block")
get :edit, res.parent_params.merge({ res.identifier => record.to_param })
def self.make_edit_html_test(res)
# should "get edit for @#{res.object} via params: #{pretty_param_string(res)}" do
should "get edit for @#{res.object}" do
record = get_existing_record(res)
parent_params = make_parent_params(res, record)
get :edit, parent_params.merge({ res.identifier => record.to_param })
assert assigns(res.klass.name.underscore.to_sym), "The edit action isn't assigning to @#{res.klass.name.underscore}"
assert_response :success
assert_select "form", true, "The edit template doesn't contain a <form> element"
@ -73,9 +94,10 @@ class Test::Unit::TestCase
end
end
def self.make_index_test(res)
def self.make_index_html_test(res)
should "get index" do
get(:index, res.parent_params)
parent_params = make_parent_params(res)
get(:index, parent_params)
assert_response :success
assert assigns(res.klass.name.underscore.pluralize.to_sym),
"The index action isn't assigning to @#{res.klass.name.underscore.pluralize}"
@ -84,9 +106,10 @@ class Test::Unit::TestCase
end
end
def self.make_new_test(res)
def self.make_new_html_test(res)
should "show form on get to new" do
get(:new, res.parent_params)
parent_params = make_parent_params(res)
get(:new, parent_params)
assert_response :success
assert assigns(res.klass.name.underscore.to_sym),
"The new action isn't assigning to @#{res.klass.name.underscore}"
@ -95,12 +118,12 @@ class Test::Unit::TestCase
end
end
def self.make_destroy_test(res)
def self.make_destroy_html_test(res)
should "destroy @#{res.object} on 'delete' to destroy action" do
assert(record = instance_variable_get("@#{res.object}"),
"This test requires you to set @#{res.object} in your setup block")
record = get_existing_record(res)
parent_params = make_parent_params(res, record)
assert_difference(res.klass, :count, -1) do
delete :destroy, res.parent_params.merge({ res.identifier => record.to_param })
delete :destroy, parent_params.merge({ res.identifier => record.to_param })
assert_redirected_to eval(res.destroy.redirect, self.send(:binding), __FILE__, __LINE__),
"Flash: #{flash.inspect}"
assert_contains flash.values, res.destroy.flash, ", Flash: #{flash.inspect}"
@ -108,10 +131,12 @@ class Test::Unit::TestCase
end
end
def self.make_create_test(res)
def self.make_create_html_test(res)
should "create #{res.klass} record on post to 'create'" do
assert_difference(res.klass, :count, 1) do
post :create, res.parent_params.merge(res.object => res.create.params)
# params = res.parent_params.merge(res.object => res.create.params)
parent_params = make_parent_params(res)
post :create, parent_params.merge(res.object => res.create.params)
assert record = assigns(res.object), "@#{res.object} not set after create"
assert_equal [], record.errors.full_messages, "@#{res.object} has errors:"
assert_redirected_to eval(res.create.redirect, self.send(:binding), __FILE__, __LINE__)
@ -120,50 +145,141 @@ class Test::Unit::TestCase
end
end
def self.make_update_test(res)
def self.make_update_html_test(res)
should "update #{res.klass} record on put to :update" do
assert(record = instance_variable_get("@#{res.object}"),
"This test requires you to set @#{res.object} in your setup block")
put :update, res.parent_params.merge(res.identifier => record.to_param, res.object => res.create.params)
record = get_existing_record(res)
parent_params = make_parent_params(res, record)
put :update, parent_params.merge(res.identifier => record.to_param, res.object => res.update.params)
assert record = assigns(res.object), "@#{res.object} not set after create"
assert_equal [], record.errors.full_messages, "@#{res.object} has errors:"
assert_redirected_to eval(res.update.redirect, self.send(:binding), __FILE__, __LINE__)
assert_contains flash.values, res.update.flash, ", Flash: #{flash.inspect}"
res.create.params.each do |key, value|
res.update.params.each do |key, value|
assert_equal value.to_s, record.send(key.to_sym).to_s,
"#{res.object}.#{key} not set to #{value} after update"
end
end
end
def self.should_be_denied_on(method, action, opts ={})
redirect_proc = opts[:redirect]
klass = opts[:klass] || self.name.gsub(/ControllerTest/, '').singularize.constantize
params = opts[:params] || {}
expected_flash = opts[:flash] || /\w+/
should "no be able to #{method.to_s.upcase} #{action}" do
assert_no_difference(klass, :count) do
self.send(method, action, params)
assert_contains flash.values, expected_flash
assert_response :redirect
if redirect_proc
assert_redirected_to(@controller.instance_eval(&redirect_proc))
end
def self.make_show_xml_test(res)
should "get show for @#{res.object} as xml" do
record = get_existing_record(res)
parent_params = make_parent_params(res, record)
get :show, parent_params.merge({ res.identifier => record.to_param }), :format => :xml
assert_equal "application/xml; charset=utf-8", @response.headers['Content-Type']
assert_response :success
assert_select "#{res.klass.name.underscore.dasherize}", 1,
"Can't find <#{res.klass.name.underscore.dasherize.pluralize}> in \n#{@response.body}"
end
end
def self.make_index_xml_test(res)
should "get index as xml" do
parent_params = make_parent_params(res)
get(:index, parent_params)
assert_equal "application/xml; charset=utf-8", @response.headers['Content-Type']
assert_response :success
assert_select "#{res.klass.name.underscore.dasherize.pluralize}", 1,
"Can't find <#{res.klass.name.underscore.dasherize.pluralize}> in \n#{@response.body}"
end
end
def self.make_destroy_xml_test(res)
should "destroy @#{res.object} on 'delete' to destroy action as xml" do
record = get_existing_record(res)
parent_params = make_parent_params(res, record)
assert_difference(res.klass, :count, -1) do
delete :destroy, parent_params.merge({ res.identifier => record.to_param })
assert_equal "application/xml; charset=utf-8", @response.headers['Content-Type']
assert_response :success
assert_match(/^\s*$/, @response.body, "The response body was not empty:")
end
end
end
def self.make_create_xml_test(res)
should "create #{res.klass} record on post to 'create' as xml" do
assert_difference(res.klass, :count, 1) do
# params = res.parent_params.merge(res.object => res.create.params)
parent_params = make_parent_params(res)
post :create, parent_params.merge(res.object => res.create.params)
assert_equal "application/xml; charset=utf-8", @response.headers['Content-Type']
assert_response :created
assert record = assigns(res.object), "@#{res.object} not set after create"
assert_equal [], record.errors.full_messages, "@#{res.object} has errors:"
assert_equal eval(res.create.redirect, self.send(:binding), __FILE__, __LINE__),
@response.headers["Location"]
end
end
end
def self.make_update_xml_test(res)
should "update #{res.klass} record on put to :update as xml" do
record = get_existing_record(res)
parent_params = make_parent_params(res, record)
put :update, parent_params.merge(res.identifier => record.to_param, res.object => res.update.params)
assert_equal "application/xml; charset=utf-8", @response.headers['Content-Type']
assert record = assigns(res.object), "@#{res.object} not set after create"
assert_equal [], record.errors.full_messages, "@#{res.object} has errors:"
assert_response :success
assert_match(/^\s*$/, @response.body, "The response body was not empty:")
res.update.params.each do |key, value|
assert_equal value.to_s, record.send(key.to_sym).to_s,
"#{res.object}.#{key} not set to #{value} after update"
end
end
end
# def self.should_be_denied_on(method, action, opts ={})
# redirect_proc = opts[:redirect]
# klass = opts[:klass] || self.name.gsub(/ControllerTest/, '').singularize.constantize
# params = opts[:params] || {}
# expected_flash = opts[:flash] || /\w+/
#
# should "no be able to #{method.to_s.upcase} #{action}" do
# assert_no_difference(klass, :count) do
# self.send(method, action, params)
# assert_contains flash.values, expected_flash
#
# assert_response :redirect
# if redirect_proc
# assert_redirected_to(@controller.instance_eval(&redirect_proc))
# end
# end
# end
# end
class << self
private
private
include ThoughtBot::Shoulda::Private
end
private
def self.pretty_param_string(res)
res.parent_params.merge({ res.identifier => :X }).inspect.gsub(':X', '@object.to_param').gsub('=>', ' => ')
def get_existing_record(res)
returning(instance_variable_get "@#{res.object}") do |record|
assert(record, "This test requires you to set @#{res.object} in your setup block")
end
end
def make_parent_params(resource, record = nil, parent_names = nil)
parent_names ||= resource.parents.reverse
return {} if parent_names == [] # Base case
parent_name = parent_names.shift
parent = record ? record.send(parent_name) : parent_name.to_s.classify.constantize.find(:first)
{ :"#{parent_name}_id" => parent.id }.merge(make_parent_params(resource, parent, parent_names))
end
end

View File

@ -5,7 +5,7 @@ module ThoughtBot # :nodoc:
module ClassMethods
# Loads all fixture files (<tt>test/fixtures/*.yml</tt>)
def load_all_fixtures
all_fixtures = Dir.glob(File.join(RAILS_ROOT, "test", "fixtures", "*.yml")).collect do |f|
all_fixtures = Dir.glob(File.join(Test::Unit::TestCase.fixture_path, "*.yml")).collect do |f|
File.basename(f, '.yml').to_sym
end
fixtures *all_fixtures

View File

@ -1,4 +1,4 @@
require File.join(File.dirname(__FILE__), 'test_helper')
require File.join(File.dirname(__FILE__), '..', 'test_helper')
class Post < ActiveRecord::Base
belongs_to :user

View File

@ -1,4 +1,4 @@
require File.join(File.dirname(__FILE__), 'test_helper')
require File.join(File.dirname(__FILE__), '..', 'test_helper')
class ContextTest < Test::Unit::TestCase # :nodoc:

View File

@ -1,4 +1,4 @@
require File.join(File.dirname(__FILE__), 'test_helper')
require File.join(File.dirname(__FILE__), '..', 'test_helper')
class Val
@@val = 0

View File

@ -1,4 +1,4 @@
require File.join(File.dirname(__FILE__), 'test_helper')
require File.join(File.dirname(__FILE__), '..', 'test_helper')
class PrivateHelpersTest < Test::Unit::TestCase # :nodoc:
include ThoughtBot::Shoulda::ActiveRecord

10
test/support/fixtures/posts.yml → test/fixtures/posts.yml vendored Executable file → Normal file
View File

@ -1,5 +1,5 @@
first:
id: 1
title: My Cute Kitten!
body: This is totally a cute kitten
user_id: 1
first:
id: 1
title: My Cute Kitten!
body: This is totally a cute kitten
user_id: 1

16
test/support/fixtures/tags.yml → test/fixtures/tags.yml vendored Executable file → Normal file
View File

@ -1,9 +1,9 @@
first:
id: 1
name: Stuff
second:
id: 2
name: Rails
third:
id: 3
first:
id: 1
name: Stuff
second:
id: 2
name: Rails
third:
id: 3
name: Nothing

11
test/support/fixtures/users.yml → test/fixtures/users.yml vendored Executable file → Normal file
View File

@ -1,6 +1,5 @@
first:
id: 1
name: Some dude
company_id: 1
age: 2
email: none@none.com
first:
id: 1
name: Some dude
age: 2
email: none@none.com

View File

@ -0,0 +1,27 @@
require File.dirname(__FILE__) + '/../test_helper'
require 'posts_controller'
# Re-raise errors caught by the controller.
class PostsController; def rescue_action(e) raise e end; end
class PostsControllerTest < Test::Unit::TestCase
load_all_fixtures
def setup
@controller = PostsController.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
@post = Post.find(:first)
end
should_be_restful do |resource|
resource.parent = :user
resource.create.params = { :title => "first post", :body => 'blah blah blah'}
resource.update.params = { :title => "changed" }
# resource.create.redirect = "post_url( record.user, record)"
# resource.update.redirect = "post_url( record.user, record)"
# resource.destroy.redirect = "posts_url(record.user)"
end
end

View File

@ -0,0 +1,25 @@
require File.dirname(__FILE__) + '/../test_helper'
require 'users_controller'
# Re-raise errors caught by the controller.
class UsersController; def rescue_action(e) raise e end; end
class UsersControllerTest < Test::Unit::TestCase
load_all_fixtures
def setup
@controller = UsersController.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
@user = User.find(:first)
end
should_be_restful do |resource|
resource.create.params = { :name => "bob", :email => 'bob@bob.com', :age => 13}
resource.update.params = { :name => "sue" }
resource.create.redirect = "user_url(record)"
resource.update.redirect = "user_url(record)"
resource.destroy.redirect = "users_url"
end
end

10
test/rails_root/Rakefile Normal file
View File

@ -0,0 +1,10 @@
# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
require(File.join(File.dirname(__FILE__), 'config', 'boot'))
require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'
require 'tasks/rails'

View File

@ -0,0 +1,7 @@
# Filters added to this controller apply to all controllers in the application.
# Likewise, all the methods added will be available for all controllers.
class ApplicationController < ActionController::Base
# Pick a unique cookie name to distinguish our session data from others'
session :session_key => '_rails_root_session_id'
end

View File

@ -0,0 +1,77 @@
class PostsController < ApplicationController
before_filter :load_user
def index
@posts = @user.posts
respond_to do |format|
format.html # index.rhtml
format.xml { render :xml => @posts.to_xml }
end
end
def show
@post = @user.posts.find(params[:id])
respond_to do |format|
format.html # show.rhtml
format.xml { render :xml => @post.to_xml }
end
end
def new
@post = @user.posts.build
end
def edit
@post = @user.posts.find(params[:id])
end
def create
@post = @user.posts.build(params[:post])
respond_to do |format|
if @post.save
flash[:notice] = 'Post was successfully created.'
format.html { redirect_to post_url(@post.user, @post) }
format.xml { head :created, :location => post_url(@post.user, @post) }
else
format.html { render :action => "new" }
format.xml { render :xml => @post.errors.to_xml }
end
end
end
def update
@post = @user.posts.find(params[:id])
respond_to do |format|
if @post.update_attributes(params[:post])
flash[:notice] = 'Post was successfully updated.'
format.html { redirect_to post_url(@post) }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => @post.errors.to_xml }
end
end
end
def destroy
@post = @user.posts.find(params[:id])
@post.destroy
flash[:notice] = "Post was removed"
respond_to do |format|
format.html { redirect_to posts_url }
format.xml { head :ok }
end
end
private
def load_user
@user = User.find(params[:user_id])
end
end

View File

@ -0,0 +1,81 @@
class UsersController < ApplicationController
# GET /users
# GET /users.xml
def index
@users = User.find(:all)
respond_to do |format|
format.html # index.rhtml
format.xml { render :xml => @users.to_xml }
end
end
# GET /users/1
# GET /users/1.xml
def show
@user = User.find(params[:id])
respond_to do |format|
format.html # show.rhtml
format.xml { render :xml => @user.to_xml }
end
end
# GET /users/new
def new
@user = User.new
end
# GET /users/1;edit
def edit
@user = User.find(params[:id])
end
# POST /users
# POST /users.xml
def create
@user = User.new(params[:user])
respond_to do |format|
if @user.save
flash[:notice] = 'User was successfully created.'
format.html { redirect_to user_url(@user) }
format.xml { head :created, :location => user_url(@user) }
else
format.html { render :action => "new" }
format.xml { render :xml => @user.errors.to_xml }
end
end
end
# PUT /users/1
# PUT /users/1.xml
def update
@user = User.find(params[:id])
respond_to do |format|
if @user.update_attributes(params[:user])
flash[:notice] = 'User was successfully updated.'
format.html { redirect_to user_url(@user) }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => @user.errors.to_xml }
end
end
end
# DELETE /users/1
# DELETE /users/1.xml
def destroy
@user = User.find(params[:id])
@user.destroy
flash[:notice] = "User was removed"
respond_to do |format|
format.html { redirect_to users_url }
format.xml { head :ok }
end
end
end

View File

@ -0,0 +1,3 @@
# Methods added to this helper will be available to all templates in the application.
module ApplicationHelper
end

View File

@ -0,0 +1,2 @@
module PostsHelper
end

View File

@ -0,0 +1,2 @@
module UsersHelper
end

View File

@ -0,0 +1,10 @@
class Post < ActiveRecord::Base
belongs_to :user
has_many :taggings
has_many :tags, :through => :taggings
validates_uniqueness_of :title
validates_presence_of :title
validates_presence_of :body, :message => 'Seriously... wtf'
validates_numericality_of :user_id
end

View File

@ -0,0 +1,4 @@
class Tag < ActiveRecord::Base
has_many :taggings
has_many :posts, :through => :taggings
end

View File

@ -0,0 +1,4 @@
class Tagging < ActiveRecord::Base
belongs_to :post
belongs_to :tag
end

View File

@ -0,0 +1,8 @@
class User < ActiveRecord::Base
has_many :posts
attr_protected :password
validates_format_of :email, :with => /\w*@\w*.com/
validates_length_of :email, :in => 1..100
validates_inclusion_of :age, :in => 1..100
end

View File

@ -0,0 +1,17 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
<title>Posts: <%= controller.action_name %></title>
<%= stylesheet_link_tag 'scaffold' %>
</head>
<body>
<p style="color: green"><%= flash[:notice] %></p>
<%= yield %>
</body>
</html>

View File

@ -0,0 +1,17 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
<title>Users: <%= controller.action_name %></title>
<%= stylesheet_link_tag 'scaffold' %>
</head>
<body>
<p style="color: green"><%= flash[:notice] %></p>
<%= yield %>
</body>
</html>

View File

@ -0,0 +1,27 @@
<h1>Editing post</h1>
<%= error_messages_for :post %>
<% form_for(:post, :url => post_path(@post.user, @post), :html => { :method => :put }) do |f| %>
<p>
<b>User</b><br />
<%= f.text_field :user_id %>
</p>
<p>
<b>Title</b><br />
<%= f.text_field :title %>
</p>
<p>
<b>Body</b><br />
<%= f.text_area :body %>
</p>
<p>
<%= submit_tag "Update" %>
</p>
<% end %>
<%= link_to 'Show', post_path(@post.user, @post) %> |
<%= link_to 'Back', posts_path(@post.user) %>

View File

@ -0,0 +1,24 @@
<h1>Listing posts</h1>
<table>
<tr>
<th>User</th>
<th>Title</th>
<th>Body</th>
</tr>
<% for post in @posts %>
<tr>
<td><%=h post.user_id %></td>
<td><%=h post.title %></td>
<td><%=h post.body %></td>
<td><%= link_to 'Show', post_path(post.user, post) %></td>
<td><%= link_to 'Edit', edit_post_path(post.user, post) %></td>
<td><%= link_to 'Destroy', post_path(post.user, post), :confirm => 'Are you sure?', :method => :delete %></td>
</tr>
<% end %>
</table>
<br />
<%= link_to 'New post', new_post_path(post.user) %>

View File

@ -0,0 +1,26 @@
<h1>New post</h1>
<%= error_messages_for :post %>
<% form_for(:post, :url => posts_path(@user)) do |f| %>
<p>
<b>User</b><br />
<%= f.text_field :user_id %>
</p>
<p>
<b>Title</b><br />
<%= f.text_field :title %>
</p>
<p>
<b>Body</b><br />
<%= f.text_area :body %>
</p>
<p>
<%= submit_tag "Create" %>
</p>
<% end %>
<%= link_to 'Back', posts_path(@user) %>

View File

@ -0,0 +1,18 @@
<p>
<b>User:</b>
<%=h @post.user_id %>
</p>
<p>
<b>Title:</b>
<%=h @post.title %>
</p>
<p>
<b>Body:</b>
<%=h @post.body %>
</p>
<%= link_to 'Edit', edit_post_path(@post.user, @post) %> |
<%= link_to 'Back', posts_path(@post.user) %>

View File

@ -0,0 +1,22 @@
<h1>Editing user</h1>
<%= error_messages_for :user %>
<% form_for(:user, :url => user_path(@user), :html => { :method => :put }) do |f| %>
<p>
<b>Email</b><br />
<%= f.text_field :email %>
</p>
<p>
<b>Age</b><br />
<%= f.text_field :age %>
</p>
<p>
<%= submit_tag "Update" %>
</p>
<% end %>
<%= link_to 'Show', user_path(@user) %> |
<%= link_to 'Back', users_path %>

View File

@ -0,0 +1,22 @@
<h1>Listing users</h1>
<table>
<tr>
<th>Email</th>
<th>Age</th>
</tr>
<% for user in @users %>
<tr>
<td><%=h user.email %></td>
<td><%=h user.age %></td>
<td><%= link_to 'Show', user_path(user) %></td>
<td><%= link_to 'Edit', edit_user_path(user) %></td>
<td><%= link_to 'Destroy', user_path(user), :confirm => 'Are you sure?', :method => :delete %></td>
</tr>
<% end %>
</table>
<br />
<%= link_to 'New user', new_user_path %>

View File

@ -0,0 +1,21 @@
<h1>New user</h1>
<%= error_messages_for :user %>
<% form_for(:user, :url => users_path) do |f| %>
<p>
<b>Email</b><br />
<%= f.text_field :email %>
</p>
<p>
<b>Age</b><br />
<%= f.text_field :age %>
</p>
<p>
<%= submit_tag "Create" %>
</p>
<% end %>
<%= link_to 'Back', users_path %>

View File

@ -0,0 +1,13 @@
<p>
<b>Email:</b>
<%=h @user.email %>
</p>
<p>
<b>Age:</b>
<%=h @user.age %>
</p>
<%= link_to 'Edit', edit_user_path(@user) %> |
<%= link_to 'Back', users_path %>

View File

@ -0,0 +1,45 @@
# Don't change this file. Configuration is done in config/environment.rb and config/environments/*.rb
unless defined?(RAILS_ROOT)
root_path = File.join(File.dirname(__FILE__), '..')
unless RUBY_PLATFORM =~ /(:?mswin|mingw)/
require 'pathname'
root_path = Pathname.new(root_path).cleanpath(true).to_s
end
RAILS_ROOT = root_path
end
unless defined?(Rails::Initializer)
if File.directory?("#{RAILS_ROOT}/vendor/rails")
require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer"
else
require 'rubygems'
environment_without_comments = IO.readlines(File.dirname(__FILE__) + '/environment.rb').reject { |l| l =~ /^#/ }.join
environment_without_comments =~ /[^#]RAILS_GEM_VERSION = '([\d.]+)'/
rails_gem_version = $1
if version = defined?(RAILS_GEM_VERSION) ? RAILS_GEM_VERSION : rails_gem_version
# Asking for 1.1.6 will give you 1.1.6.5206, if available -- makes it easier to use beta gems
rails_gem = Gem.cache.search('rails', "~>#{version}.0").sort_by { |g| g.version.version }.last
if rails_gem
gem "rails", "=#{rails_gem.version.version}"
require rails_gem.full_gem_path + '/lib/initializer'
else
STDERR.puts %(Cannot find gem for Rails ~>#{version}.0:
Install the missing gem with 'gem install -v=#{version} rails', or
change environment.rb to define RAILS_GEM_VERSION with your desired version.
)
exit 1
end
else
gem "rails"
require 'initializer'
end
end
Rails::Initializer.run(:set_load_path)
end

View File

@ -0,0 +1,4 @@
sqlite3:
:adapter: sqlite3
# :dbfile: db/sqlite3.db
:dbfile: ":memory:"

View File

@ -0,0 +1,14 @@
# Specifies gem version of Rails to use when vendor/rails is not present
#RAILS_GEM_VERSION = '1.1.6'
require File.join(File.dirname(__FILE__), 'boot')
Rails::Initializer.run do |config|
config.log_level = :debug
config.cache_classes = false
config.whiny_nils = true
config.breakpoint_server = true
config.load_paths << File.join(File.dirname(__FILE__), *%w{.. .. .. lib})
end
Dependencies.log_activity = true

View File

@ -0,0 +1,5 @@
ActionController::Routing::Routes.draw do |map|
map.resources :users do |user|
user.resources :posts
end
end

View File

@ -0,0 +1,13 @@
class CreateUsers < ActiveRecord::Migration
def self.up
create_table :users do |t|
t.column :name, :string
t.column :email, :string
t.column :age, :integer
end
end
def self.down
drop_table :users
end
end

View File

@ -0,0 +1,13 @@
class CreatePosts < ActiveRecord::Migration
def self.up
create_table :posts do |t|
t.column :user_id, :integer
t.column :title, :string
t.column :body, :text
end
end
def self.down
drop_table :posts
end
end

View File

@ -0,0 +1,12 @@
class CreateTaggings < ActiveRecord::Migration
def self.up
create_table :taggings do |t|
t.column :user_id, :integer
t.column :tag_id, :integer
end
end
def self.down
drop_table :taggings
end
end

View File

@ -0,0 +1,11 @@
class CreateTags < ActiveRecord::Migration
def self.up
create_table :tags do |t|
t.column :name, :string
end
end
def self.down
drop_table :tags
end
end

View File

View File

@ -0,0 +1,2 @@
Use this README file to introduce your application and point to useful places in the API for learning more.
Run "rake appdoc" to generate API documentation for your models and controllers.

View File

@ -0,0 +1,4 @@
SQL (0.000000) SQLite3::SQLException: no such table: schema_info: SELECT * FROM schema_info
SQL (0.000207) SELECT name FROM sqlite_master WHERE type = 'table'
SQL (0.000000) SQLite3::SQLException: no such table: schema_info: SELECT * FROM schema_info
SQL (0.000208) SELECT name FROM sqlite_master WHERE type = 'table'

View File

View File

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,950 @@
SQL (0.079100) CREATE TABLE schema_info (version integer)
SQL (0.000229) INSERT INTO schema_info (version) VALUES(0)
SQL (0.000329) SELECT version FROM schema_info
Migrating to CreateUsers (1)
SQL (0.000323) CREATE TABLE users ("id" INTEGER PRIMARY KEY NOT NULL, "email" varchar(255) DEFAULT NULL, "age" integer DEFAULT NULL) 
SQL (0.000108) UPDATE schema_info SET version = 1
SQL (0.000201) SELECT version FROM schema_info
Migrating to CreatePosts (2)
SQL (0.000257) CREATE TABLE posts ("id" INTEGER PRIMARY KEY NOT NULL, "user_id" integer DEFAULT NULL, "title" varchar(255) DEFAULT NULL, "body" text DEFAULT NULL) 
SQL (0.000096) UPDATE schema_info SET version = 2
SQL (0.000178) SELECT version FROM schema_info
Migrating to CreateTaggings (3)
SQL (0.000387) CREATE TABLE taggings ("id" INTEGER PRIMARY KEY NOT NULL, "user_id" integer DEFAULT NULL, "tag_id" integer DEFAULT NULL) 
SQL (0.000134) UPDATE schema_info SET version = 3
SQL (0.000232) SELECT version FROM schema_info
Migrating to CreateTags (4)
SQL (0.000355) CREATE TABLE tags ("id" INTEGER PRIMARY KEY NOT NULL, "name" varchar(255) DEFAULT NULL) 
SQL (0.000116) UPDATE schema_info SET version = 4
SQL (0.000344) SELECT count(*) AS count_all FROM posts 
Processing PostsController#create (for 0.0.0.0 at 2007-06-27 15:52:58) [POST]
Session ID:
Parameters: {"action"=>"create", "post"=>{}, "controller"=>"posts"}
Post Load (0.000164) SELECT * FROM posts WHERE (posts.title IS NULL) LIMIT 1
Rendering actionnewlayoutfalse within layouts/posts
Rendering posts/new
Completed in 0.00789 (126 reqs/sec) | Rendering: 0.00471 (59%) | DB: 0.08255 (1046%) | 200 OK [http://test.host/posts?post=]
SQL (0.000281) SELECT count(*) AS count_all FROM posts 
SQL (0.000262) SELECT count(*) AS count_all FROM posts 
Processing PostsController#destroy (for 0.0.0.0 at 2007-06-27 15:52:59) [DELETE]
Session ID:
Parameters: {"action"=>"destroy", "id"=>"1", "controller"=>"posts"}
Post Load (0.000424) SELECT * FROM posts WHERE (posts."id" = 1) 
Post Destroy (0.000120)  DELETE FROM posts
WHERE "id" = 1

Redirected to http://test.host/posts
Completed in 0.00229 (436 reqs/sec) | DB: 0.00109 (47%) | 302 Found [http://test.host/posts/1]
SQL (0.000320) SELECT count(*) AS count_all FROM posts 
Processing PostsController#edit (for 0.0.0.0 at 2007-06-27 15:52:59) [GET]
Session ID:
Parameters: {"action"=>"edit", "id"=>"1", "controller"=>"posts"}
Post Load (0.000415) SELECT * FROM posts WHERE (posts."id" = 1) 
Rendering within layouts/posts
Rendering posts/edit
Completed in 0.00538 (185 reqs/sec) | Rendering: 0.00442 (82%) | DB: 0.00074 (13%) | 200 OK [http://test.host/posts/1;edit]
Processing PostsController#index (for 0.0.0.0 at 2007-06-27 15:52:59) [GET]
Session ID:
Parameters: {"action"=>"index", "controller"=>"posts"}
Post Load (0.000574) SELECT * FROM posts 
Rendering actionindexcontent_typetext/htmllayoutfalse within layouts/posts
Rendering posts/index
Completed in 0.00600 (166 reqs/sec) | Rendering: 0.00458 (76%) | DB: 0.00057 (9%) | 200 OK [http://test.host/posts]
Processing PostsController#new (for 0.0.0.0 at 2007-06-27 15:52:59) [GET]
Session ID:
Parameters: {"action"=>"new", "controller"=>"posts"}
Rendering within layouts/posts
Rendering posts/new
Completed in 0.00214 (467 reqs/sec) | Rendering: 0.00198 (92%) | DB: 0.00000 (0%) | 200 OK [http://test.host/posts/new]
Processing PostsController#show (for 0.0.0.0 at 2007-06-27 15:52:59) [GET]
Session ID:
Parameters: {"action"=>"show", "id"=>"1", "controller"=>"posts"}
Post Load (0.000392) SELECT * FROM posts WHERE (posts."id" = 1) 
Rendering actionshowcontent_typetext/htmllayoutfalse within layouts/posts
Rendering posts/show
Completed in 0.00394 (254 reqs/sec) | Rendering: 0.00268 (68%) | DB: 0.00039 (9%) | 200 OK [http://test.host/posts/1]
Processing PostsController#update (for 0.0.0.0 at 2007-06-27 15:52:59) [PUT]
Session ID:
Parameters: {"action"=>"update", "post"=>{}, "id"=>"1", "controller"=>"posts"}
Post Load (0.000374) SELECT * FROM posts WHERE (posts."id" = 1) 
Post Load (0.000461) SELECT * FROM posts WHERE (posts.title = 'MyString' AND posts.id <> 1) LIMIT 1
Rendering actioneditlayoutfalse within layouts/posts
Rendering posts/edit
Completed in 0.00600 (166 reqs/sec) | Rendering: 0.00300 (50%) | DB: 0.00084 (13%) | 200 OK [http://test.host/posts/1?post=]
SQL (0.000362) SELECT count(*) AS count_all FROM users 
Processing UsersController#create (for 0.0.0.0 at 2007-06-27 15:52:59) [POST]
Session ID:
Parameters: {"user"=>{}, "action"=>"create", "controller"=>"users"}
Rendering actionnewlayoutfalse within layouts/users
Rendering users/new
Completed in 0.00821 (121 reqs/sec) | Rendering: 0.00539 (65%) | DB: 0.00036 (4%) | 200 OK [http://test.host/users?user=]
SQL (0.000319) SELECT count(*) AS count_all FROM users 
SQL (0.000285) SELECT count(*) AS count_all FROM users 
Processing UsersController#destroy (for 0.0.0.0 at 2007-06-27 15:52:59) [DELETE]
Session ID:
Parameters: {"action"=>"destroy", "id"=>"1", "controller"=>"users"}
User Load (0.000387) SELECT * FROM users WHERE (users."id" = 1) 
User Destroy (0.000120)  DELETE FROM users
WHERE "id" = 1

Redirected to http://test.host/users
Completed in 0.00212 (471 reqs/sec) | DB: 0.00111 (52%) | 302 Found [http://test.host/users/1]
SQL (0.000339) SELECT count(*) AS count_all FROM users 
Processing UsersController#edit (for 0.0.0.0 at 2007-06-27 15:52:59) [GET]
Session ID:
Parameters: {"action"=>"edit", "id"=>"1", "controller"=>"users"}
User Load (0.000410) SELECT * FROM users WHERE (users."id" = 1) 
Rendering within layouts/users
Rendering users/edit
Completed in 0.00544 (183 reqs/sec) | Rendering: 0.00444 (81%) | DB: 0.00075 (13%) | 200 OK [http://test.host/users/1;edit]
Processing UsersController#index (for 0.0.0.0 at 2007-06-27 15:52:59) [GET]
Session ID:
Parameters: {"action"=>"index", "controller"=>"users"}
User Load (0.000482) SELECT * FROM users 
Rendering actionindexcontent_typetext/htmllayoutfalse within layouts/users
Rendering users/index
Completed in 0.00543 (184 reqs/sec) | Rendering: 0.00416 (76%) | DB: 0.00048 (8%) | 200 OK [http://test.host/users]
Processing UsersController#new (for 0.0.0.0 at 2007-06-27 15:52:59) [GET]
Session ID:
Parameters: {"action"=>"new", "controller"=>"users"}
Rendering within layouts/users
Rendering users/new
Completed in 0.00204 (489 reqs/sec) | Rendering: 0.00187 (91%) | DB: 0.00000 (0%) | 200 OK [http://test.host/users/new]
Processing UsersController#show (for 0.0.0.0 at 2007-06-27 15:52:59) [GET]
Session ID:
Parameters: {"action"=>"show", "id"=>"1", "controller"=>"users"}
User Load (0.000340) SELECT * FROM users WHERE (users."id" = 1) 
Rendering actionshowcontent_typetext/htmllayoutfalse within layouts/users
Rendering users/show
Completed in 0.00337 (297 reqs/sec) | Rendering: 0.00224 (66%) | DB: 0.00034 (10%) | 200 OK [http://test.host/users/1]
Processing UsersController#update (for 0.0.0.0 at 2007-06-27 15:52:59) [PUT]
Session ID:
Parameters: {"user"=>{}, "action"=>"update", "id"=>"1", "controller"=>"users"}
User Load (0.000379) SELECT * FROM users WHERE (users."id" = 1) 
Rendering actioneditlayoutfalse within layouts/users
Rendering users/edit
Completed in 0.00437 (228 reqs/sec) | Rendering: 0.00255 (58%) | DB: 0.00038 (8%) | 200 OK [http://test.host/users/1?user=]
SQL (0.000597) CREATE TABLE schema_info (version integer)
SQL (0.000095) INSERT INTO schema_info (version) VALUES(0)
SQL (0.000265) SELECT version FROM schema_info
Migrating to CreateUsers (1)
SQL (0.000272) CREATE TABLE users ("id" INTEGER PRIMARY KEY NOT NULL, "email" varchar(255) DEFAULT NULL, "age" integer DEFAULT NULL) 
SQL (0.000088) UPDATE schema_info SET version = 1
SQL (0.000169) SELECT version FROM schema_info
Migrating to CreatePosts (2)
SQL (0.000225) CREATE TABLE posts ("id" INTEGER PRIMARY KEY NOT NULL, "user_id" integer DEFAULT NULL, "title" varchar(255) DEFAULT NULL, "body" text DEFAULT NULL) 
SQL (0.000088) UPDATE schema_info SET version = 2
SQL (0.000166) SELECT version FROM schema_info
Migrating to CreateTaggings (3)
SQL (0.000227) CREATE TABLE taggings ("id" INTEGER PRIMARY KEY NOT NULL, "user_id" integer DEFAULT NULL, "tag_id" integer DEFAULT NULL) 
SQL (0.000086) UPDATE schema_info SET version = 3
SQL (0.000162) SELECT version FROM schema_info
Migrating to CreateTags (4)
SQL (0.000204) CREATE TABLE tags ("id" INTEGER PRIMARY KEY NOT NULL, "name" varchar(255) DEFAULT NULL) 
SQL (0.000089) UPDATE schema_info SET version = 4
SQL (0.000601) CREATE TABLE schema_info (version integer)
SQL (0.000095) INSERT INTO schema_info (version) VALUES(0)
SQL (0.000265) SELECT version FROM schema_info
Migrating to CreateUsers (1)
SQL (0.000261) CREATE TABLE users ("id" INTEGER PRIMARY KEY NOT NULL, "email" varchar(255) DEFAULT NULL, "age" integer DEFAULT NULL) 
SQL (0.000087) UPDATE schema_info SET version = 1
SQL (0.000166) SELECT version FROM schema_info
Migrating to CreatePosts (2)
SQL (0.000231) CREATE TABLE posts ("id" INTEGER PRIMARY KEY NOT NULL, "user_id" integer DEFAULT NULL, "title" varchar(255) DEFAULT NULL, "body" text DEFAULT NULL) 
SQL (0.000088) UPDATE schema_info SET version = 2
SQL (0.000383) SELECT version FROM schema_info
Migrating to CreateTaggings (3)
SQL (0.000292) CREATE TABLE taggings ("id" INTEGER PRIMARY KEY NOT NULL, "user_id" integer DEFAULT NULL, "tag_id" integer DEFAULT NULL) 
SQL (0.000094) UPDATE schema_info SET version = 3
SQL (0.000186) SELECT version FROM schema_info
Migrating to CreateTags (4)
SQL (0.000220) CREATE TABLE tags ("id" INTEGER PRIMARY KEY NOT NULL, "name" varchar(255) DEFAULT NULL) 
SQL (0.000085) UPDATE schema_info SET version = 4
SQL (0.000287) SELECT count(*) AS count_all FROM posts 
Processing PostsController#create (for 0.0.0.0 at 2007-06-27 15:53:40) [POST]
Session ID:
Parameters: {"action"=>"create", "post"=>{}, "controller"=>"posts"}
Post Load (0.000152) SELECT * FROM posts WHERE (posts.title IS NULL) LIMIT 1
Rendering actionnewlayoutfalse within layouts/posts
Rendering posts/new
Completed in 0.00737 (135 reqs/sec) | Rendering: 0.00446 (60%) | DB: 0.00349 (47%) | 200 OK [http://test.host/posts?post=]
SQL (0.000326) SELECT count(*) AS count_all FROM posts 
SQL (0.000216) SELECT count(*) AS count_all FROM posts 
Processing PostsController#destroy (for 0.0.0.0 at 2007-06-27 15:53:40) [DELETE]
Session ID:
Parameters: {"action"=>"destroy", "id"=>"1", "controller"=>"posts"}
Post Load (0.000293) SELECT * FROM posts WHERE (posts."id" = 1) 
Post Destroy (0.000093)  DELETE FROM posts
WHERE "id" = 1

Redirected to http://test.host/posts
Completed in 0.00179 (557 reqs/sec) | DB: 0.00093 (51%) | 302 Found [http://test.host/posts/1]
SQL (0.000330) SELECT count(*) AS count_all FROM posts 
Processing PostsController#edit (for 0.0.0.0 at 2007-06-27 15:53:40) [GET]
Session ID:
Parameters: {"action"=>"edit", "id"=>"1", "controller"=>"posts"}
Post Load (0.000298) SELECT * FROM posts WHERE (posts."id" = 1) 
Rendering within layouts/posts
Rendering posts/edit
Completed in 0.00415 (240 reqs/sec) | Rendering: 0.00343 (82%) | DB: 0.00063 (15%) | 200 OK [http://test.host/posts/1;edit]
Processing PostsController#index (for 0.0.0.0 at 2007-06-27 15:53:40) [GET]
Session ID:
Parameters: {"action"=>"index", "controller"=>"posts"}
Post Load (0.000389) SELECT * FROM posts 
Rendering actionindexcontent_typetext/htmllayoutfalse within layouts/posts
Rendering posts/index
Completed in 0.00430 (232 reqs/sec) | Rendering: 0.00331 (76%) | DB: 0.00039 (9%) | 200 OK [http://test.host/posts]
Processing PostsController#new (for 0.0.0.0 at 2007-06-27 15:53:40) [GET]
Session ID:
Parameters: {"action"=>"new", "controller"=>"posts"}
Rendering within layouts/posts
Rendering posts/new
Completed in 0.00165 (605 reqs/sec) | Rendering: 0.00153 (92%) | DB: 0.00000 (0%) | 200 OK [http://test.host/posts/new]
Processing PostsController#show (for 0.0.0.0 at 2007-06-27 15:53:40) [GET]
Session ID:
Parameters: {"action"=>"show", "id"=>"1", "controller"=>"posts"}
Post Load (0.000297) SELECT * FROM posts WHERE (posts."id" = 1) 
Rendering actionshowcontent_typetext/htmllayoutfalse within layouts/posts
Rendering posts/show
Completed in 0.00282 (354 reqs/sec) | Rendering: 0.00189 (66%) | DB: 0.00030 (10%) | 200 OK [http://test.host/posts/1]
Processing PostsController#update (for 0.0.0.0 at 2007-06-27 15:53:40) [PUT]
Session ID:
Parameters: {"action"=>"update", "post"=>{}, "id"=>"1", "controller"=>"posts"}
Post Load (0.000314) SELECT * FROM posts WHERE (posts."id" = 1) 
Post Load (0.000334) SELECT * FROM posts WHERE (posts.title = 'MyString' AND posts.id <> 1) LIMIT 1
Rendering actioneditlayoutfalse within layouts/posts
Rendering posts/edit
Completed in 0.00442 (226 reqs/sec) | Rendering: 0.00216 (48%) | DB: 0.00065 (14%) | 200 OK [http://test.host/posts/1?post=]
SQL (0.000202) SELECT count(*) AS count_all FROM users 
Processing UsersController#create (for 0.0.0.0 at 2007-06-27 15:53:40) [POST]
Session ID:
Parameters: {"user"=>{}, "action"=>"create", "controller"=>"users"}
Rendering actionnewlayoutfalse within layouts/users
Rendering users/new
Completed in 0.00616 (162 reqs/sec) | Rendering: 0.00391 (63%) | DB: 0.00020 (3%) | 200 OK [http://test.host/users?user=]
SQL (0.000266) SELECT count(*) AS count_all FROM users 
SQL (0.000198) SELECT count(*) AS count_all FROM users 
Processing UsersController#destroy (for 0.0.0.0 at 2007-06-27 15:53:40) [DELETE]
Session ID:
Parameters: {"action"=>"destroy", "id"=>"1", "controller"=>"users"}
User Load (0.000298) SELECT * FROM users WHERE (users."id" = 1) 
User Destroy (0.000091)  DELETE FROM users
WHERE "id" = 1

Redirected to http://test.host/users
Completed in 0.00172 (582 reqs/sec) | DB: 0.00085 (49%) | 302 Found [http://test.host/users/1]
SQL (0.000278) SELECT count(*) AS count_all FROM users 
Processing UsersController#edit (for 0.0.0.0 at 2007-06-27 15:53:40) [GET]
Session ID:
Parameters: {"action"=>"edit", "id"=>"1", "controller"=>"users"}
User Load (0.000284) SELECT * FROM users WHERE (users."id" = 1) 
Rendering within layouts/users
Rendering users/edit
Completed in 0.00391 (255 reqs/sec) | Rendering: 0.00321 (81%) | DB: 0.00056 (14%) | 200 OK [http://test.host/users/1;edit]
Processing UsersController#index (for 0.0.0.0 at 2007-06-27 15:53:40) [GET]
Session ID:
Parameters: {"action"=>"index", "controller"=>"users"}
User Load (0.000359) SELECT * FROM users 
Rendering actionindexcontent_typetext/htmllayoutfalse within layouts/users
Rendering users/index
Completed in 0.00420 (238 reqs/sec) | Rendering: 0.00323 (76%) | DB: 0.00036 (8%) | 200 OK [http://test.host/users]
Processing UsersController#new (for 0.0.0.0 at 2007-06-27 15:53:40) [GET]
Session ID:
Parameters: {"action"=>"new", "controller"=>"users"}
Rendering within layouts/users
Rendering users/new
Completed in 0.00151 (660 reqs/sec) | Rendering: 0.00139 (91%) | DB: 0.00000 (0%) | 200 OK [http://test.host/users/new]
Processing UsersController#show (for 0.0.0.0 at 2007-06-27 15:53:40) [GET]
Session ID:
Parameters: {"action"=>"show", "id"=>"1", "controller"=>"users"}
User Load (0.000352) SELECT * FROM users WHERE (users."id" = 1) 
Rendering actionshowcontent_typetext/htmllayoutfalse within layouts/users
Rendering users/show
Completed in 0.00295 (339 reqs/sec) | Rendering: 0.00179 (60%) | DB: 0.00035 (11%) | 200 OK [http://test.host/users/1]
Processing UsersController#update (for 0.0.0.0 at 2007-06-27 15:53:40) [PUT]
Session ID:
Parameters: {"user"=>{}, "action"=>"update", "id"=>"1", "controller"=>"users"}
User Load (0.000327) SELECT * FROM users WHERE (users."id" = 1) 
Rendering actioneditlayoutfalse within layouts/users
Rendering users/edit
Completed in 0.00365 (273 reqs/sec) | Rendering: 0.00216 (59%) | DB: 0.00033 (8%) | 200 OK [http://test.host/users/1?user=]
SQL (0.000602) CREATE TABLE schema_info (version integer)
SQL (0.000094) INSERT INTO schema_info (version) VALUES(0)
SQL (0.000264) SELECT version FROM schema_info
Migrating to CreateUsers (1)
SQL (0.000268) CREATE TABLE users ("id" INTEGER PRIMARY KEY NOT NULL, "email" varchar(255) DEFAULT NULL, "age" integer DEFAULT NULL) 
SQL (0.000088) UPDATE schema_info SET version = 1
SQL (0.000163) SELECT version FROM schema_info
Migrating to CreatePosts (2)
SQL (0.000223) CREATE TABLE posts ("id" INTEGER PRIMARY KEY NOT NULL, "user_id" integer DEFAULT NULL, "title" varchar(255) DEFAULT NULL, "body" text DEFAULT NULL) 
SQL (0.000087) UPDATE schema_info SET version = 2
SQL (0.000164) SELECT version FROM schema_info
Migrating to CreateTaggings (3)
SQL (0.000223) CREATE TABLE taggings ("id" INTEGER PRIMARY KEY NOT NULL, "user_id" integer DEFAULT NULL, "tag_id" integer DEFAULT NULL) 
SQL (0.000085) UPDATE schema_info SET version = 3
SQL (0.000158) SELECT version FROM schema_info
Migrating to CreateTags (4)
SQL (0.000209) CREATE TABLE tags ("id" INTEGER PRIMARY KEY NOT NULL, "name" varchar(255) DEFAULT NULL) 
SQL (0.000088) UPDATE schema_info SET version = 4
SQL (0.000616) CREATE TABLE schema_info (version integer)
SQL (0.000095) INSERT INTO schema_info (version) VALUES(0)
SQL (0.000264) SELECT version FROM schema_info
Migrating to CreateUsers (1)
SQL (0.000261) CREATE TABLE users ("id" INTEGER PRIMARY KEY NOT NULL, "email" varchar(255) DEFAULT NULL, "age" integer DEFAULT NULL) 
SQL (0.000088) UPDATE schema_info SET version = 1
SQL (0.000169) SELECT version FROM schema_info
Migrating to CreatePosts (2)
SQL (0.000248) CREATE TABLE posts ("id" INTEGER PRIMARY KEY NOT NULL, "user_id" integer DEFAULT NULL, "title" varchar(255) DEFAULT NULL, "body" text DEFAULT NULL) 
SQL (0.000088) UPDATE schema_info SET version = 2
SQL (0.000381) SELECT version FROM schema_info
Migrating to CreateTaggings (3)
SQL (0.000286) CREATE TABLE taggings ("id" INTEGER PRIMARY KEY NOT NULL, "user_id" integer DEFAULT NULL, "tag_id" integer DEFAULT NULL) 
SQL (0.000093) UPDATE schema_info SET version = 3
SQL (0.000177) SELECT version FROM schema_info
Migrating to CreateTags (4)
SQL (0.000219) CREATE TABLE tags ("id" INTEGER PRIMARY KEY NOT NULL, "name" varchar(255) DEFAULT NULL) 
SQL (0.000086) UPDATE schema_info SET version = 4
SQL (0.000368) SELECT count(*) AS count_all FROM posts 
Processing PostsController#create (for 0.0.0.0 at 2007-06-27 15:53:56) [POST]
Session ID:
Parameters: {"action"=>"create", "post"=>{}, "controller"=>"posts"}
Post Load (0.000162) SELECT * FROM posts WHERE (posts.title IS NULL) LIMIT 1
Rendering actionnewlayoutfalse within layouts/posts
Rendering posts/new
Completed in 0.00768 (130 reqs/sec) | Rendering: 0.00471 (61%) | DB: 0.00360 (46%) | 200 OK [http://test.host/posts?post=]
SQL (0.000318) SELECT count(*) AS count_all FROM posts 
SQL (0.000239) SELECT count(*) AS count_all FROM posts 
Processing PostsController#destroy (for 0.0.0.0 at 2007-06-27 15:53:56) [DELETE]
Session ID:
Parameters: {"action"=>"destroy", "id"=>"1", "controller"=>"posts"}
Post Load (0.000358) SELECT * FROM posts WHERE (posts."id" = 1) 
Post Destroy (0.000095)  DELETE FROM posts
WHERE "id" = 1

Redirected to http://test.host/posts
Completed in 0.00201 (497 reqs/sec) | DB: 0.00101 (50%) | 302 Found [http://test.host/posts/1]
SQL (0.000215) SELECT count(*) AS count_all FROM posts 
Processing PostsController#edit (for 0.0.0.0 at 2007-06-27 15:53:56) [GET]
Session ID:
Parameters: {"action"=>"edit", "id"=>"1", "controller"=>"posts"}
Post Load (0.000382) SELECT * FROM posts WHERE (posts."id" = 1) 
Rendering within layouts/posts
Rendering posts/edit
Completed in 0.00463 (215 reqs/sec) | Rendering: 0.00377 (81%) | DB: 0.00060 (12%) | 200 OK [http://test.host/posts/1;edit]
Processing PostsController#index (for 0.0.0.0 at 2007-06-27 15:53:56) [GET]
Session ID:
Parameters: {"action"=>"index", "controller"=>"posts"}
Post Load (0.000374) SELECT * FROM posts 
Rendering actionindexcontent_typetext/htmllayoutfalse within layouts/posts
Rendering posts/index
Completed in 0.00447 (223 reqs/sec) | Rendering: 0.00348 (77%) | DB: 0.00037 (8%) | 200 OK [http://test.host/posts]
Processing PostsController#new (for 0.0.0.0 at 2007-06-27 15:53:56) [GET]
Session ID:
Parameters: {"action"=>"new", "controller"=>"posts"}
Rendering within layouts/posts
Rendering posts/new
Completed in 0.00166 (601 reqs/sec) | Rendering: 0.00154 (92%) | DB: 0.00000 (0%) | 200 OK [http://test.host/posts/new]
Processing PostsController#show (for 0.0.0.0 at 2007-06-27 15:53:56) [GET]
Session ID:
Parameters: {"action"=>"show", "id"=>"1", "controller"=>"posts"}
Post Load (0.000386) SELECT * FROM posts WHERE (posts."id" = 1) 
Rendering actionshowcontent_typetext/htmllayoutfalse within layouts/posts
Rendering posts/show
Completed in 0.00314 (318 reqs/sec) | Rendering: 0.00196 (62%) | DB: 0.00039 (12%) | 200 OK [http://test.host/posts/1]
Processing PostsController#update (for 0.0.0.0 at 2007-06-27 15:53:56) [PUT]
Session ID:
Parameters: {"action"=>"update", "post"=>{}, "id"=>"1", "controller"=>"posts"}
Post Load (0.000320) SELECT * FROM posts WHERE (posts."id" = 1) 
Post Load (0.000339) SELECT * FROM posts WHERE (posts.title = 'MyString' AND posts.id <> 1) LIMIT 1
Rendering actioneditlayoutfalse within layouts/posts
Rendering posts/edit
Completed in 0.00457 (218 reqs/sec) | Rendering: 0.00225 (49%) | DB: 0.00066 (14%) | 200 OK [http://test.host/posts/1?post=]
SQL (0.000197) SELECT count(*) AS count_all FROM users 
Processing UsersController#create (for 0.0.0.0 at 2007-06-27 15:53:56) [POST]
Session ID:
Parameters: {"user"=>{}, "action"=>"create", "controller"=>"users"}
Rendering actionnewlayoutfalse within layouts/users
Rendering users/new
Completed in 0.00662 (150 reqs/sec) | Rendering: 0.00423 (63%) | DB: 0.00020 (2%) | 200 OK [http://test.host/users?user=]
SQL (0.000275) SELECT count(*) AS count_all FROM users 
SQL (0.000199) SELECT count(*) AS count_all FROM users 
Processing UsersController#destroy (for 0.0.0.0 at 2007-06-27 15:53:56) [DELETE]
Session ID:
Parameters: {"action"=>"destroy", "id"=>"1", "controller"=>"users"}
User Load (0.000267) SELECT * FROM users WHERE (users."id" = 1) 
User Destroy (0.000093)  DELETE FROM users
WHERE "id" = 1

Redirected to http://test.host/users
Completed in 0.00163 (614 reqs/sec) | DB: 0.00083 (51%) | 302 Found [http://test.host/users/1]
SQL (0.000224) SELECT count(*) AS count_all FROM users 
Processing UsersController#edit (for 0.0.0.0 at 2007-06-27 15:53:56) [GET]
Session ID:
Parameters: {"action"=>"edit", "id"=>"1", "controller"=>"users"}
User Load (0.000304) SELECT * FROM users WHERE (users."id" = 1) 
Rendering within layouts/users
Rendering users/edit
Completed in 0.00384 (260 reqs/sec) | Rendering: 0.00313 (81%) | DB: 0.00053 (13%) | 200 OK [http://test.host/users/1;edit]
Processing UsersController#index (for 0.0.0.0 at 2007-06-27 15:53:56) [GET]
Session ID:
Parameters: {"action"=>"index", "controller"=>"users"}
User Load (0.000344) SELECT * FROM users 
Rendering actionindexcontent_typetext/htmllayoutfalse within layouts/users
Rendering users/index
Completed in 0.00440 (227 reqs/sec) | Rendering: 0.00346 (78%) | DB: 0.00034 (7%) | 200 OK [http://test.host/users]
Processing UsersController#new (for 0.0.0.0 at 2007-06-27 15:53:56) [GET]
Session ID:
Parameters: {"action"=>"new", "controller"=>"users"}
Rendering within layouts/users
Rendering users/new
Completed in 0.00220 (454 reqs/sec) | Rendering: 0.00205 (93%) | DB: 0.00000 (0%) | 200 OK [http://test.host/users/new]
Processing UsersController#show (for 0.0.0.0 at 2007-06-27 15:53:56) [GET]
Session ID:
Parameters: {"action"=>"show", "id"=>"1", "controller"=>"users"}
User Load (0.000290) SELECT * FROM users WHERE (users."id" = 1) 
Rendering actionshowcontent_typetext/htmllayoutfalse within layouts/users
Rendering users/show
Completed in 0.00268 (372 reqs/sec) | Rendering: 0.00175 (65%) | DB: 0.00029 (10%) | 200 OK [http://test.host/users/1]
Processing UsersController#update (for 0.0.0.0 at 2007-06-27 15:53:56) [PUT]
Session ID:
Parameters: {"user"=>{}, "action"=>"update", "id"=>"1", "controller"=>"users"}
User Load (0.000272) SELECT * FROM users WHERE (users."id" = 1) 
Rendering actioneditlayoutfalse within layouts/users
Rendering users/edit
Completed in 0.00332 (301 reqs/sec) | Rendering: 0.00200 (60%) | DB: 0.00027 (8%) | 200 OK [http://test.host/users/1?user=]
SQL (0.000655) CREATE TABLE users ("id" INTEGER PRIMARY KEY NOT NULL, "email" varchar(255) DEFAULT NULL, "age" integer DEFAULT NULL) 
SQL (0.000226) CREATE TABLE posts ("id" INTEGER PRIMARY KEY NOT NULL, "user_id" integer DEFAULT NULL, "title" varchar(255) DEFAULT NULL, "body" text DEFAULT NULL) 
SQL (0.000214) CREATE TABLE taggings ("id" INTEGER PRIMARY KEY NOT NULL, "user_id" integer DEFAULT NULL, "tag_id" integer DEFAULT NULL) 
SQL (0.000193) CREATE TABLE tags ("id" INTEGER PRIMARY KEY NOT NULL, "name" varchar(255) DEFAULT NULL) 
SQL (0.000177) CREATE TABLE schema_info (version integer)
SQL (0.000095) INSERT INTO schema_info (version) VALUES(0)
SQL (0.000095) UPDATE schema_info SET version = 1
SQL (0.000315) SELECT count(*) AS count_all FROM posts 
Processing PostsController#create (for 0.0.0.0 at 2007-06-27 15:57:02) [POST]
Session ID:
Parameters: {"action"=>"create", "post"=>{}, "controller"=>"posts"}
Post Load (0.000170) SELECT * FROM posts WHERE (posts.title IS NULL) LIMIT 1
Rendering actionnewlayoutfalse within layouts/posts
Rendering posts/new
Completed in 0.00790 (126 reqs/sec) | Rendering: 0.00492 (62%) | DB: 0.00214 (27%) | 200 OK [http://test.host/posts?post=]
SQL (0.000301) SELECT count(*) AS count_all FROM posts 
SQL (0.000218) SELECT count(*) AS count_all FROM posts 
Processing PostsController#destroy (for 0.0.0.0 at 2007-06-27 15:57:02) [DELETE]
Session ID:
Parameters: {"action"=>"destroy", "id"=>"1", "controller"=>"posts"}
Post Load (0.000447) SELECT * FROM posts WHERE (posts."id" = 1) 
Post Destroy (0.000114)  DELETE FROM posts
WHERE "id" = 1

Redirected to http://test.host/posts
Completed in 0.00279 (358 reqs/sec) | DB: 0.00108 (38%) | 302 Found [http://test.host/posts/1]
SQL (0.000322) SELECT count(*) AS count_all FROM posts 
Processing PostsController#edit (for 0.0.0.0 at 2007-06-27 15:57:02) [GET]
Session ID:
Parameters: {"action"=>"edit", "id"=>"1", "controller"=>"posts"}
Post Load (0.000400) SELECT * FROM posts WHERE (posts."id" = 1) 
Rendering within layouts/posts
Rendering posts/edit
Completed in 0.00443 (225 reqs/sec) | Rendering: 0.00352 (79%) | DB: 0.00072 (16%) | 200 OK [http://test.host/posts/1;edit]
Processing PostsController#index (for 0.0.0.0 at 2007-06-27 15:57:02) [GET]
Session ID:
Parameters: {"action"=>"index", "controller"=>"posts"}
Post Load (0.000397) SELECT * FROM posts 
Rendering actionindexcontent_typetext/htmllayoutfalse within layouts/posts
Rendering posts/index
Completed in 0.00453 (220 reqs/sec) | Rendering: 0.00351 (77%) | DB: 0.00040 (8%) | 200 OK [http://test.host/posts]
Processing PostsController#new (for 0.0.0.0 at 2007-06-27 15:57:02) [GET]
Session ID:
Parameters: {"action"=>"new", "controller"=>"posts"}
Rendering within layouts/posts
Rendering posts/new
Completed in 0.00183 (546 reqs/sec) | Rendering: 0.00165 (90%) | DB: 0.00000 (0%) | 200 OK [http://test.host/posts/new]
Processing PostsController#show (for 0.0.0.0 at 2007-06-27 15:57:02) [GET]
Session ID:
Parameters: {"action"=>"show", "id"=>"1", "controller"=>"posts"}
Post Load (0.000307) SELECT * FROM posts WHERE (posts."id" = 1) 
Rendering actionshowcontent_typetext/htmllayoutfalse within layouts/posts
Rendering posts/show
Completed in 0.00291 (343 reqs/sec) | Rendering: 0.00194 (66%) | DB: 0.00031 (10%) | 200 OK [http://test.host/posts/1]
Processing PostsController#update (for 0.0.0.0 at 2007-06-27 15:57:02) [PUT]
Session ID:
Parameters: {"action"=>"update", "post"=>{}, "id"=>"1", "controller"=>"posts"}
Post Load (0.000347) SELECT * FROM posts WHERE (posts."id" = 1) 
Post Load (0.000269) SELECT * FROM posts WHERE (posts.title = 'MyString' AND posts.id <> 1) LIMIT 1
Rendering actioneditlayoutfalse within layouts/posts
Rendering posts/edit
Completed in 0.00435 (229 reqs/sec) | Rendering: 0.00214 (49%) | DB: 0.00062 (14%) | 200 OK [http://test.host/posts/1?post=]
SQL (0.000181) SELECT count(*) AS count_all FROM users 
Processing UsersController#create (for 0.0.0.0 at 2007-06-27 15:57:02) [POST]
Session ID:
Parameters: {"user"=>{}, "action"=>"create", "controller"=>"users"}
Rendering actionnewlayoutfalse within layouts/users
Rendering users/new
Completed in 0.00680 (147 reqs/sec) | Rendering: 0.00436 (64%) | DB: 0.00018 (2%) | 200 OK [http://test.host/users?user=]
SQL (0.000305) SELECT count(*) AS count_all FROM users 
SQL (0.000229) SELECT count(*) AS count_all FROM users 
Processing UsersController#destroy (for 0.0.0.0 at 2007-06-27 15:57:02) [DELETE]
Session ID:
Parameters: {"action"=>"destroy", "id"=>"1", "controller"=>"users"}
User Load (0.000344) SELECT * FROM users WHERE (users."id" = 1) 
User Destroy (0.000094)  DELETE FROM users
WHERE "id" = 1

Redirected to http://test.host/users
Completed in 0.00207 (483 reqs/sec) | DB: 0.00097 (46%) | 302 Found [http://test.host/users/1]
SQL (0.000226) SELECT count(*) AS count_all FROM users 
Processing UsersController#edit (for 0.0.0.0 at 2007-06-27 15:57:02) [GET]
Session ID:
Parameters: {"action"=>"edit", "id"=>"1", "controller"=>"users"}
User Load (0.000298) SELECT * FROM users WHERE (users."id" = 1) 
Rendering within layouts/users
Rendering users/edit
Completed in 0.00430 (232 reqs/sec) | Rendering: 0.00352 (81%) | DB: 0.00052 (12%) | 200 OK [http://test.host/users/1;edit]
Processing UsersController#index (for 0.0.0.0 at 2007-06-27 15:57:02) [GET]
Session ID:
Parameters: {"action"=>"index", "controller"=>"users"}
User Load (0.000498) SELECT * FROM users 
Rendering actionindexcontent_typetext/htmllayoutfalse within layouts/users
Rendering users/index
Completed in 0.00448 (223 reqs/sec) | Rendering: 0.00330 (73%) | DB: 0.00050 (11%) | 200 OK [http://test.host/users]
Processing UsersController#new (for 0.0.0.0 at 2007-06-27 15:57:02) [GET]
Session ID:
Parameters: {"action"=>"new", "controller"=>"users"}
Rendering within layouts/users
Rendering users/new
Completed in 0.00158 (633 reqs/sec) | Rendering: 0.00144 (91%) | DB: 0.00000 (0%) | 200 OK [http://test.host/users/new]
Processing UsersController#show (for 0.0.0.0 at 2007-06-27 15:57:02) [GET]
Session ID:
Parameters: {"action"=>"show", "id"=>"1", "controller"=>"users"}
User Load (0.000329) SELECT * FROM users WHERE (users."id" = 1) 
Rendering actionshowcontent_typetext/htmllayoutfalse within layouts/users
Rendering users/show
Completed in 0.00288 (347 reqs/sec) | Rendering: 0.00182 (63%) | DB: 0.00033 (11%) | 200 OK [http://test.host/users/1]
Processing UsersController#update (for 0.0.0.0 at 2007-06-27 15:57:02) [PUT]
Session ID:
Parameters: {"user"=>{}, "action"=>"update", "id"=>"1", "controller"=>"users"}
User Load (0.000275) SELECT * FROM users WHERE (users."id" = 1) 
Rendering actioneditlayoutfalse within layouts/users
Rendering users/edit
Completed in 0.00329 (303 reqs/sec) | Rendering: 0.00195 (59%) | DB: 0.00027 (8%) | 200 OK [http://test.host/users/1?user=]
SQL (0.000643) CREATE TABLE schema_info (version integer)
SQL (0.000098) INSERT INTO schema_info (version) VALUES(0)
SQL (0.000272) SELECT version FROM schema_info
Migrating to CreateUsers (1)
SQL (0.000264) CREATE TABLE users ("id" INTEGER PRIMARY KEY NOT NULL, "email" varchar(255) DEFAULT NULL, "age" integer DEFAULT NULL) 
SQL (0.000088) UPDATE schema_info SET version = 1
SQL (0.000166) SELECT version FROM schema_info
Migrating to CreatePosts (2)
SQL (0.000230) CREATE TABLE posts ("id" INTEGER PRIMARY KEY NOT NULL, "user_id" integer DEFAULT NULL, "title" varchar(255) DEFAULT NULL, "body" text DEFAULT NULL) 
SQL (0.000087) UPDATE schema_info SET version = 2
SQL (0.056447) SELECT version FROM schema_info
Migrating to CreateTaggings (3)
SQL (0.000337) CREATE TABLE taggings ("id" INTEGER PRIMARY KEY NOT NULL, "user_id" integer DEFAULT NULL, "tag_id" integer DEFAULT NULL) 
SQL (0.000092) UPDATE schema_info SET version = 3
SQL (0.000198) SELECT version FROM schema_info
Migrating to CreateTags (4)
SQL (0.000241) CREATE TABLE tags ("id" INTEGER PRIMARY KEY NOT NULL, "name" varchar(255) DEFAULT NULL) 
SQL (0.000085) UPDATE schema_info SET version = 4
SQL (0.000218) SELECT count(*) AS count_all FROM posts 
Processing PostsController#create (for 0.0.0.0 at 2007-06-27 15:58:36) [POST]
Session ID:
Parameters: {"action"=>"create", "post"=>{}, "controller"=>"posts"}
Post Load (0.000155) SELECT * FROM posts WHERE (posts.title IS NULL) LIMIT 1
Rendering actionnewlayoutfalse within layouts/posts
Rendering posts/new
Completed in 0.00745 (134 reqs/sec) | Rendering: 0.00448 (60%) | DB: 0.05962 (799%) | 200 OK [http://test.host/posts?post=]
SQL (0.000272) SELECT count(*) AS count_all FROM posts 
SQL (0.000250) SELECT count(*) AS count_all FROM posts 
Processing PostsController#destroy (for 0.0.0.0 at 2007-06-27 15:58:36) [DELETE]
Session ID:
Parameters: {"action"=>"destroy", "id"=>"1", "controller"=>"posts"}
Post Load (0.000367) SELECT * FROM posts WHERE (posts."id" = 1) 
Post Destroy (0.000092)  DELETE FROM posts
WHERE "id" = 1

Redirected to http://test.host/posts
Completed in 0.00190 (526 reqs/sec) | DB: 0.00098 (51%) | 302 Found [http://test.host/posts/1]
SQL (0.000245) SELECT count(*) AS count_all FROM posts 
Processing PostsController#edit (for 0.0.0.0 at 2007-06-27 15:58:36) [GET]
Session ID:
Parameters: {"action"=>"edit", "id"=>"1", "controller"=>"posts"}
Post Load (0.000348) SELECT * FROM posts WHERE (posts."id" = 1) 
Rendering within layouts/posts
Rendering posts/edit
Completed in 0.00454 (220 reqs/sec) | Rendering: 0.00369 (81%) | DB: 0.00059 (13%) | 200 OK [http://test.host/posts/1;edit]
Processing PostsController#index (for 0.0.0.0 at 2007-06-27 15:58:36) [GET]
Session ID:
Parameters: {"action"=>"index", "controller"=>"posts"}
Post Load (0.000376) SELECT * FROM posts 
Rendering actionindexcontent_typetext/htmllayoutfalse within layouts/posts
Rendering posts/index
Completed in 0.00433 (230 reqs/sec) | Rendering: 0.00335 (77%) | DB: 0.00038 (8%) | 200 OK [http://test.host/posts]
Processing PostsController#new (for 0.0.0.0 at 2007-06-27 15:58:36) [GET]
Session ID:
Parameters: {"action"=>"new", "controller"=>"posts"}
Rendering within layouts/posts
Rendering posts/new
Completed in 0.00167 (600 reqs/sec) | Rendering: 0.00154 (92%) | DB: 0.00000 (0%) | 200 OK [http://test.host/posts/new]
Processing PostsController#show (for 0.0.0.0 at 2007-06-27 15:58:36) [GET]
Session ID:
Parameters: {"action"=>"show", "id"=>"1", "controller"=>"posts"}
Post Load (0.000288) SELECT * FROM posts WHERE (posts."id" = 1) 
Rendering actionshowcontent_typetext/htmllayoutfalse within layouts/posts
Rendering posts/show
Completed in 0.00284 (352 reqs/sec) | Rendering: 0.00191 (67%) | DB: 0.00029 (10%) | 200 OK [http://test.host/posts/1]
Processing PostsController#update (for 0.0.0.0 at 2007-06-27 15:58:36) [PUT]
Session ID:
Parameters: {"action"=>"update", "post"=>{}, "id"=>"1", "controller"=>"posts"}
Post Load (0.000346) SELECT * FROM posts WHERE (posts."id" = 1) 
Post Load (0.000271) SELECT * FROM posts WHERE (posts.title = 'MyString' AND posts.id <> 1) LIMIT 1
Rendering actioneditlayoutfalse within layouts/posts
Rendering posts/edit
Completed in 0.00428 (233 reqs/sec) | Rendering: 0.00214 (49%) | DB: 0.00062 (14%) | 200 OK [http://test.host/posts/1?post=]
SQL (0.000184) SELECT count(*) AS count_all FROM users 
Processing UsersController#create (for 0.0.0.0 at 2007-06-27 15:58:36) [POST]
Session ID:
Parameters: {"user"=>{}, "action"=>"create", "controller"=>"users"}
Rendering actionnewlayoutfalse within layouts/users
Rendering users/new
Completed in 0.00608 (164 reqs/sec) | Rendering: 0.00393 (64%) | DB: 0.00018 (3%) | 200 OK [http://test.host/users?user=]
SQL (0.000260) SELECT count(*) AS count_all FROM users 
SQL (0.000215) SELECT count(*) AS count_all FROM users 
Processing UsersController#destroy (for 0.0.0.0 at 2007-06-27 15:58:36) [DELETE]
Session ID:
Parameters: {"action"=>"destroy", "id"=>"1", "controller"=>"users"}
User Load (0.000268) SELECT * FROM users WHERE (users."id" = 1) 
User Destroy (0.000090)  DELETE FROM users
WHERE "id" = 1

Redirected to http://test.host/users
Completed in 0.00158 (632 reqs/sec) | DB: 0.00083 (52%) | 302 Found [http://test.host/users/1]
SQL (0.000210) SELECT count(*) AS count_all FROM users 
Processing UsersController#edit (for 0.0.0.0 at 2007-06-27 15:58:36) [GET]
Session ID:
Parameters: {"action"=>"edit", "id"=>"1", "controller"=>"users"}
User Load (0.000376) SELECT * FROM users WHERE (users."id" = 1) 
Rendering within layouts/users
Rendering users/edit
Completed in 0.00415 (240 reqs/sec) | Rendering: 0.00328 (78%) | DB: 0.00059 (14%) | 200 OK [http://test.host/users/1;edit]
Processing UsersController#index (for 0.0.0.0 at 2007-06-27 15:58:36) [GET]
Session ID:
Parameters: {"action"=>"index", "controller"=>"users"}
User Load (0.000379) SELECT * FROM users 
Rendering actionindexcontent_typetext/htmllayoutfalse within layouts/users
Rendering users/index
Completed in 0.00458 (218 reqs/sec) | Rendering: 0.00352 (76%) | DB: 0.00038 (8%) | 200 OK [http://test.host/users]
Processing UsersController#new (for 0.0.0.0 at 2007-06-27 15:58:36) [GET]
Session ID:
Parameters: {"action"=>"new", "controller"=>"users"}
Rendering within layouts/users
Rendering users/new
Completed in 0.00185 (539 reqs/sec) | Rendering: 0.00168 (90%) | DB: 0.00000 (0%) | 200 OK [http://test.host/users/new]
Processing UsersController#show (for 0.0.0.0 at 2007-06-27 15:58:36) [GET]
Session ID:
Parameters: {"action"=>"show", "id"=>"1", "controller"=>"users"}
User Load (0.000273) SELECT * FROM users WHERE (users."id" = 1) 
Rendering actionshowcontent_typetext/htmllayoutfalse within layouts/users
Rendering users/show
Completed in 0.00263 (380 reqs/sec) | Rendering: 0.00173 (65%) | DB: 0.00027 (10%) | 200 OK [http://test.host/users/1]
Processing UsersController#update (for 0.0.0.0 at 2007-06-27 15:58:36) [PUT]
Session ID:
Parameters: {"user"=>{}, "action"=>"update", "id"=>"1", "controller"=>"users"}
User Load (0.000279) SELECT * FROM users WHERE (users."id" = 1) 
Rendering actioneditlayoutfalse within layouts/users
Rendering users/edit
Completed in 0.00332 (300 reqs/sec) | Rendering: 0.00199 (59%) | DB: 0.00028 (8%) | 200 OK [http://test.host/users/1?user=]
SQL (0.003821) CREATE TABLE schema_info (version integer)
SQL (0.106481) INSERT INTO schema_info (version) VALUES(0)
SQL (0.000000) SQLite3::SQLException: table schema_info already exists: CREATE TABLE schema_info (version integer)
SQL (0.000416) SELECT version FROM schema_info
Migrating to CreateUsers (1)
SQL (0.003526) CREATE TABLE users ("id" INTEGER PRIMARY KEY NOT NULL, "email" varchar(255) DEFAULT NULL, "age" integer DEFAULT NULL) 
SQL (0.003211) UPDATE schema_info SET version = 1
SQL (0.000470) SELECT version FROM schema_info
Migrating to CreatePosts (2)
SQL (0.003677) CREATE TABLE posts ("id" INTEGER PRIMARY KEY NOT NULL, "user_id" integer DEFAULT NULL, "title" varchar(255) DEFAULT NULL, "body" text DEFAULT NULL) 
SQL (0.003985) UPDATE schema_info SET version = 2
SQL (0.000505) SELECT version FROM schema_info
Migrating to CreateTaggings (3)
SQL (0.004088) CREATE TABLE taggings ("id" INTEGER PRIMARY KEY NOT NULL, "user_id" integer DEFAULT NULL, "tag_id" integer DEFAULT NULL) 
SQL (0.003982) UPDATE schema_info SET version = 3
SQL (0.000423) SELECT version FROM schema_info
Migrating to CreateTags (4)
SQL (0.003873) CREATE TABLE tags ("id" INTEGER PRIMARY KEY NOT NULL, "name" varchar(255) DEFAULT NULL) 
SQL (0.003629) UPDATE schema_info SET version = 4
SQL (0.000459) SELECT count(*) AS count_all FROM posts 
Processing PostsController#create (for 0.0.0.0 at 2007-06-27 16:15:06) [POST]
Session ID:
Parameters: {"action"=>"create", "post"=>{}, "controller"=>"posts"}
Post Load (0.000384) SELECT * FROM posts WHERE (posts.title IS NULL) LIMIT 1
Rendering actionnewlayoutfalse within layouts/posts
Rendering posts/new
Completed in 0.00991 (100 reqs/sec) | Rendering: 0.00575 (58%) | DB: 0.14293 (1442%) | 200 OK [http://test.host/posts?post=]
SQL (0.000398) SELECT count(*) AS count_all FROM posts 
SQL (0.000442) SELECT count(*) AS count_all FROM posts 
Processing PostsController#destroy (for 0.0.0.0 at 2007-06-27 16:15:06) [DELETE]
Session ID:
Parameters: {"action"=>"destroy", "id"=>"1", "controller"=>"posts"}
Post Load (0.000578) SELECT * FROM posts WHERE (posts."id" = 1) 
Post Destroy (0.000481)  DELETE FROM posts
WHERE "id" = 1

Redirected to http://test.host/posts
Completed in 0.00576 (173 reqs/sec) | DB: 0.00190 (32%) | 302 Found [http://test.host/posts/1]
SQL (0.000441) SELECT count(*) AS count_all FROM posts 
Processing PostsController#edit (for 0.0.0.0 at 2007-06-27 16:15:06) [GET]
Session ID:
Parameters: {"action"=>"edit", "id"=>"1", "controller"=>"posts"}
Post Load (0.000584) SELECT * FROM posts WHERE (posts."id" = 1) 
Rendering within layouts/posts
Rendering posts/edit
Completed in 0.00578 (173 reqs/sec) | Rendering: 0.00460 (79%) | DB: 0.00103 (17%) | 200 OK [http://test.host/posts/1;edit]
Processing PostsController#index (for 0.0.0.0 at 2007-06-27 16:15:06) [GET]
Session ID:
Parameters: {"action"=>"index", "controller"=>"posts"}
Post Load (0.000643) SELECT * FROM posts 
Rendering actionindexcontent_typetext/htmllayoutfalse within layouts/posts
Rendering posts/index
Completed in 0.00585 (170 reqs/sec) | Rendering: 0.00436 (74%) | DB: 0.00064 (10%) | 200 OK [http://test.host/posts]
Processing PostsController#new (for 0.0.0.0 at 2007-06-27 16:15:06) [GET]
Session ID:
Parameters: {"action"=>"new", "controller"=>"posts"}
Rendering within layouts/posts
Rendering posts/new
Completed in 0.00234 (426 reqs/sec) | Rendering: 0.00213 (90%) | DB: 0.00000 (0%) | 200 OK [http://test.host/posts/new]
Processing PostsController#show (for 0.0.0.0 at 2007-06-27 16:15:06) [GET]
Session ID:
Parameters: {"action"=>"show", "id"=>"1", "controller"=>"posts"}
Post Load (0.000627) SELECT * FROM posts WHERE (posts."id" = 1) 
Rendering actionshowcontent_typetext/htmllayoutfalse within layouts/posts
Rendering posts/show
Completed in 0.00411 (243 reqs/sec) | Rendering: 0.00255 (61%) | DB: 0.00063 (15%) | 200 OK [http://test.host/posts/1]
Processing PostsController#update (for 0.0.0.0 at 2007-06-27 16:15:06) [PUT]
Session ID:
Parameters: {"action"=>"update", "post"=>{}, "id"=>"1", "controller"=>"posts"}
Post Load (0.000550) SELECT * FROM posts WHERE (posts."id" = 1) 
Post Load (0.000450) SELECT * FROM posts WHERE (posts.title = 'MyString' AND posts.id <> 1) LIMIT 1
Rendering actioneditlayoutfalse within layouts/posts
Rendering posts/edit
Completed in 0.00587 (170 reqs/sec) | Rendering: 0.00292 (49%) | DB: 0.00100 (17%) | 200 OK [http://test.host/posts/1?post=]
SQL (0.000377) SELECT count(*) AS count_all FROM users 
Processing UsersController#create (for 0.0.0.0 at 2007-06-27 16:15:06) [POST]
Session ID:
Parameters: {"user"=>{}, "action"=>"create", "controller"=>"users"}
Rendering actionnewlayoutfalse within layouts/users
Rendering users/new
Completed in 0.00806 (124 reqs/sec) | Rendering: 0.00489 (60%) | DB: 0.00038 (4%) | 200 OK [http://test.host/users?user=]
SQL (0.000360) SELECT count(*) AS count_all FROM users 
SQL (0.000503) SELECT count(*) AS count_all FROM users 
Processing UsersController#destroy (for 0.0.0.0 at 2007-06-27 16:15:06) [DELETE]
Session ID:
Parameters: {"action"=>"destroy", "id"=>"1", "controller"=>"users"}
User Load (0.000474) SELECT * FROM users WHERE (users."id" = 1) 
User Destroy (0.000466)  DELETE FROM users
WHERE "id" = 1

Redirected to http://test.host/users
Completed in 0.00528 (189 reqs/sec) | DB: 0.00180 (34%) | 302 Found [http://test.host/users/1]
SQL (0.000477) SELECT count(*) AS count_all FROM users 
Processing UsersController#edit (for 0.0.0.0 at 2007-06-27 16:15:07) [GET]
Session ID:
Parameters: {"action"=>"edit", "id"=>"1", "controller"=>"users"}
User Load (0.000646) SELECT * FROM users WHERE (users."id" = 1) 
Rendering within layouts/users
Rendering users/edit
Completed in 0.00548 (182 reqs/sec) | Rendering: 0.00423 (77%) | DB: 0.00112 (20%) | 200 OK [http://test.host/users/1;edit]
Processing UsersController#index (for 0.0.0.0 at 2007-06-27 16:15:07) [GET]
Session ID:
Parameters: {"action"=>"index", "controller"=>"users"}
User Load (0.000596) SELECT * FROM users 
Rendering actionindexcontent_typetext/htmllayoutfalse within layouts/users
Rendering users/index
Completed in 0.00606 (164 reqs/sec) | Rendering: 0.00464 (76%) | DB: 0.00060 (9%) | 200 OK [http://test.host/users]
Processing UsersController#new (for 0.0.0.0 at 2007-06-27 16:15:07) [GET]
Session ID:
Parameters: {"action"=>"new", "controller"=>"users"}
Rendering within layouts/users
Rendering users/new
Completed in 0.00208 (480 reqs/sec) | Rendering: 0.00191 (91%) | DB: 0.00000 (0%) | 200 OK [http://test.host/users/new]
Processing UsersController#show (for 0.0.0.0 at 2007-06-27 16:15:07) [GET]
Session ID:
Parameters: {"action"=>"show", "id"=>"1", "controller"=>"users"}
User Load (0.000636) SELECT * FROM users WHERE (users."id" = 1) 
Rendering actionshowcontent_typetext/htmllayoutfalse within layouts/users
Rendering users/show
Completed in 0.00394 (253 reqs/sec) | Rendering: 0.00237 (60%) | DB: 0.00064 (16%) | 200 OK [http://test.host/users/1]
Processing UsersController#update (for 0.0.0.0 at 2007-06-27 16:15:07) [PUT]
Session ID:
Parameters: {"user"=>{}, "action"=>"update", "id"=>"1", "controller"=>"users"}
User Load (0.000600) SELECT * FROM users WHERE (users."id" = 1) 
Rendering actioneditlayoutfalse within layouts/users
Rendering users/edit
Completed in 0.00464 (215 reqs/sec) | Rendering: 0.00256 (55%) | DB: 0.00060 (12%) | 200 OK [http://test.host/users/1?user=]

View File

@ -0,0 +1,40 @@
# General Apache options
AddHandler fastcgi-script .fcgi
AddHandler cgi-script .cgi
Options +FollowSymLinks +ExecCGI
# If you don't want Rails to look in certain directories,
# use the following rewrite rules so that Apache won't rewrite certain requests
#
# Example:
# RewriteCond %{REQUEST_URI} ^/notrails.*
# RewriteRule .* - [L]
# Redirect all requests not available on the filesystem to Rails
# By default the cgi dispatcher is used which is very slow
#
# For better performance replace the dispatcher with the fastcgi one
#
# Example:
# RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
RewriteEngine On
# If your Rails application is accessed via an Alias directive,
# then you MUST also set the RewriteBase in this htaccess file.
#
# Example:
# Alias /myrailsapp /path/to/myrailsapp/public
# RewriteBase /myrailsapp
RewriteRule ^$ index.html [QSA]
RewriteRule ^([^.]+)$ $1.html [QSA]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ dispatch.cgi [QSA,L]
# In case Rails experiences terminal errors
# Instead of displaying this message you can supply a file here which will be rendered instead
#
# Example:
# ErrorDocument 500 /500.html
ErrorDocument 500 "<h2>Application error</h2>Rails application failed to start properly"

View File

@ -0,0 +1,30 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<title>The page you were looking for doesn't exist (404)</title>
<style type="text/css">
body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
div.dialog {
width: 25em;
padding: 0 4em;
margin: 4em auto 0 auto;
border: 1px solid #ccc;
border-right-color: #999;
border-bottom-color: #999;
}
h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
</style>
</head>
<body>
<!-- This file lives in public/404.html -->
<div class="dialog">
<h1>The page you were looking for doesn't exist.</h1>
<p>You may have mistyped the address or the page may have moved.</p>
</div>
</body>
</html>

View File

@ -0,0 +1,30 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<title>We're sorry, but something went wrong</title>
<style type="text/css">
body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
div.dialog {
width: 25em;
padding: 0 4em;
margin: 4em auto 0 auto;
border: 1px solid #ccc;
border-right-color: #999;
border-bottom-color: #999;
}
h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
</style>
</head>
<body>
<!-- This file lives in public/500.html -->
<div class="dialog">
<h1>We're sorry, but something went wrong.</h1>
<p>We've been notified about this issue and we'll take a look at it shortly.</p>
</div>
</body>
</html>

View File

@ -0,0 +1,10 @@
#!/opt/local/bin/ruby
require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT)
# If you're using RubyGems and mod_ruby, this require should be changed to an absolute path one, like:
# "/usr/local/lib/ruby/gems/1.8/gems/rails-0.8.0/lib/dispatcher" -- otherwise performance is severely impaired
require "dispatcher"
ADDITIONAL_LOAD_PATHS.reverse.each { |dir| $:.unshift(dir) if File.directory?(dir) } if defined?(Apache::RubyRun)
Dispatcher.dispatch

View File

@ -0,0 +1,24 @@
#!/opt/local/bin/ruby
#
# You may specify the path to the FastCGI crash log (a log of unhandled
# exceptions which forced the FastCGI instance to exit, great for debugging)
# and the number of requests to process before running garbage collection.
#
# By default, the FastCGI crash log is RAILS_ROOT/log/fastcgi.crash.log
# and the GC period is nil (turned off). A reasonable number of requests
# could range from 10-100 depending on the memory footprint of your app.
#
# Example:
# # Default log path, normal GC behavior.
# RailsFCGIHandler.process!
#
# # Default log path, 50 requests between GC.
# RailsFCGIHandler.process! nil, 50
#
# # Custom log path, normal GC behavior.
# RailsFCGIHandler.process! '/var/log/myapp_fcgi_crash.log'
#
require File.dirname(__FILE__) + "/../config/environment"
require 'fcgi_handler'
RailsFCGIHandler.process!

View File

@ -0,0 +1,10 @@
#!/opt/local/bin/ruby
require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT)
# If you're using RubyGems and mod_ruby, this require should be changed to an absolute path one, like:
# "/usr/local/lib/ruby/gems/1.8/gems/rails-0.8.0/lib/dispatcher" -- otherwise performance is severely impaired
require "dispatcher"
ADDITIONAL_LOAD_PATHS.reverse.each { |dir| $:.unshift(dir) if File.directory?(dir) } if defined?(Apache::RubyRun)
Dispatcher.dispatch

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,277 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<title>Ruby on Rails: Welcome aboard</title>
<style type="text/css" media="screen">
body {
margin: 0;
margin-bottom: 25px;
padding: 0;
background-color: #f0f0f0;
font-family: "Lucida Grande", "Bitstream Vera Sans", "Verdana";
font-size: 13px;
color: #333;
}
h1 {
font-size: 28px;
color: #000;
}
a {color: #03c}
a:hover {
background-color: #03c;
color: white;
text-decoration: none;
}
#page {
background-color: #f0f0f0;
width: 750px;
margin: 0;
margin-left: auto;
margin-right: auto;
}
#content {
float: left;
background-color: white;
border: 3px solid #aaa;
border-top: none;
padding: 25px;
width: 500px;
}
#sidebar {
float: right;
width: 175px;
}
#footer {
clear: both;
}
#header, #about, #getting-started {
padding-left: 75px;
padding-right: 30px;
}
#header {
background-image: url("images/rails.png");
background-repeat: no-repeat;
background-position: top left;
height: 64px;
}
#header h1, #header h2 {margin: 0}
#header h2 {
color: #888;
font-weight: normal;
font-size: 16px;
}
#about h3 {
margin: 0;
margin-bottom: 10px;
font-size: 14px;
}
#about-content {
background-color: #ffd;
border: 1px solid #fc0;
margin-left: -11px;
}
#about-content table {
margin-top: 10px;
margin-bottom: 10px;
font-size: 11px;
border-collapse: collapse;
}
#about-content td {
padding: 10px;
padding-top: 3px;
padding-bottom: 3px;
}
#about-content td.name {color: #555}
#about-content td.value {color: #000}
#about-content.failure {
background-color: #fcc;
border: 1px solid #f00;
}
#about-content.failure p {
margin: 0;
padding: 10px;
}
#getting-started {
border-top: 1px solid #ccc;
margin-top: 25px;
padding-top: 15px;
}
#getting-started h1 {
margin: 0;
font-size: 20px;
}
#getting-started h2 {
margin: 0;
font-size: 14px;
font-weight: normal;
color: #333;
margin-bottom: 25px;
}
#getting-started ol {
margin-left: 0;
padding-left: 0;
}
#getting-started li {
font-size: 18px;
color: #888;
margin-bottom: 25px;
}
#getting-started li h2 {
margin: 0;
font-weight: normal;
font-size: 18px;
color: #333;
}
#getting-started li p {
color: #555;
font-size: 13px;
}
#search {
margin: 0;
padding-top: 10px;
padding-bottom: 10px;
font-size: 11px;
}
#search input {
font-size: 11px;
margin: 2px;
}
#search-text {width: 170px}
#sidebar ul {
margin-left: 0;
padding-left: 0;
}
#sidebar ul h3 {
margin-top: 25px;
font-size: 16px;
padding-bottom: 10px;
border-bottom: 1px solid #ccc;
}
#sidebar li {
list-style-type: none;
}
#sidebar ul.links li {
margin-bottom: 5px;
}
</style>
<script type="text/javascript" src="javascripts/prototype.js"></script>
<script type="text/javascript" src="javascripts/effects.js"></script>
<script type="text/javascript">
function about() {
if (Element.empty('about-content')) {
new Ajax.Updater('about-content', 'rails/info/properties', {
method: 'get',
onFailure: function() {Element.classNames('about-content').add('failure')},
onComplete: function() {new Effect.BlindDown('about-content', {duration: 0.25})}
});
} else {
new Effect[Element.visible('about-content') ?
'BlindUp' : 'BlindDown']('about-content', {duration: 0.25});
}
}
window.onload = function() {
$('search-text').value = '';
$('search').onsubmit = function() {
$('search-text').value = 'site:rubyonrails.org ' + $F('search-text');
}
}
</script>
</head>
<body>
<div id="page">
<div id="sidebar">
<ul id="sidebar-items">
<li>
<form id="search" action="http://www.google.com/search" method="get">
<input type="hidden" name="hl" value="en" />
<input type="text" id="search-text" name="q" value="site:rubyonrails.org " />
<input type="submit" value="Search" /> the Rails site
</form>
</li>
<li>
<h3>Join the community</h3>
<ul class="links">
<li><a href="http://www.rubyonrails.org/">Ruby on Rails</a></li>
<li><a href="http://weblog.rubyonrails.org/">Official weblog</a></li>
<li><a href="http://lists.rubyonrails.org/">Mailing lists</a></li>
<li><a href="http://wiki.rubyonrails.org/rails/pages/IRC">IRC channel</a></li>
<li><a href="http://wiki.rubyonrails.org/">Wiki</a></li>
<li><a href="http://dev.rubyonrails.org/">Bug tracker</a></li>
</ul>
</li>
<li>
<h3>Browse the documentation</h3>
<ul class="links">
<li><a href="http://api.rubyonrails.org/">Rails API</a></li>
<li><a href="http://stdlib.rubyonrails.org/">Ruby standard library</a></li>
<li><a href="http://corelib.rubyonrails.org/">Ruby core</a></li>
</ul>
</li>
</ul>
</div>
<div id="content">
<div id="header">
<h1>Welcome aboard</h1>
<h2>You&rsquo;re riding the Rails!</h2>
</div>
<div id="about">
<h3><a href="rails/info/properties" onclick="about(); return false">About your application&rsquo;s environment</a></h3>
<div id="about-content" style="display: none"></div>
</div>
<div id="getting-started">
<h1>Getting started</h1>
<h2>Here&rsquo;s how to get rolling:</h2>
<ol>
<li>
<h2>Create your databases and edit <tt>config/database.yml</tt></h2>
<p>Rails needs to know your login and password.</p>
</li>
<li>
<h2>Use <tt>script/generate</tt> to create your models and controllers</h2>
<p>To see all available options, run it without parameters.</p>
</li>
<li>
<h2>Set up a default route and remove or rename this file</h2>
<p>Routes are setup in config/routes.rb.</p>
</li>
</ol>
</div>
</div>
<div id="footer">&nbsp;</div>
</div>
</body>
</html>

View File

@ -0,0 +1,2 @@
// Place your application-specific JavaScript functions and classes here
// This file is automatically included by javascript_include_tag :defaults

View File

@ -0,0 +1,833 @@
// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// (c) 2005, 2006 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
// (c) 2005, 2006 Jon Tirsen (http://www.tirsen.com)
// Contributors:
// Richard Livsey
// Rahul Bhargava
// Rob Wills
//
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/
// Autocompleter.Base handles all the autocompletion functionality
// that's independent of the data source for autocompletion. This
// includes drawing the autocompletion menu, observing keyboard
// and mouse events, and similar.
//
// Specific autocompleters need to provide, at the very least,
// a getUpdatedChoices function that will be invoked every time
// the text inside the monitored textbox changes. This method
// should get the text for which to provide autocompletion by
// invoking this.getToken(), NOT by directly accessing
// this.element.value. This is to allow incremental tokenized
// autocompletion. Specific auto-completion logic (AJAX, etc)
// belongs in getUpdatedChoices.
//
// Tokenized incremental autocompletion is enabled automatically
// when an autocompleter is instantiated with the 'tokens' option
// in the options parameter, e.g.:
// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' });
// will incrementally autocomplete with a comma as the token.
// Additionally, ',' in the above example can be replaced with
// a token array, e.g. { tokens: [',', '\n'] } which
// enables autocompletion on multiple tokens. This is most
// useful when one of the tokens is \n (a newline), as it
// allows smart autocompletion after linebreaks.
if(typeof Effect == 'undefined')
throw("controls.js requires including script.aculo.us' effects.js library");
var Autocompleter = {}
Autocompleter.Base = function() {};
Autocompleter.Base.prototype = {
baseInitialize: function(element, update, options) {
this.element = $(element);
this.update = $(update);
this.hasFocus = false;
this.changed = false;
this.active = false;
this.index = 0;
this.entryCount = 0;
if(this.setOptions)
this.setOptions(options);
else
this.options = options || {};
this.options.paramName = this.options.paramName || this.element.name;
this.options.tokens = this.options.tokens || [];
this.options.frequency = this.options.frequency || 0.4;
this.options.minChars = this.options.minChars || 1;
this.options.onShow = this.options.onShow ||
function(element, update){
if(!update.style.position || update.style.position=='absolute') {
update.style.position = 'absolute';
Position.clone(element, update, {
setHeight: false,
offsetTop: element.offsetHeight
});
}
Effect.Appear(update,{duration:0.15});
};
this.options.onHide = this.options.onHide ||
function(element, update){ new Effect.Fade(update,{duration:0.15}) };
if(typeof(this.options.tokens) == 'string')
this.options.tokens = new Array(this.options.tokens);
this.observer = null;
this.element.setAttribute('autocomplete','off');
Element.hide(this.update);
Event.observe(this.element, "blur", this.onBlur.bindAsEventListener(this));
Event.observe(this.element, "keypress", this.onKeyPress.bindAsEventListener(this));
},
show: function() {
if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
if(!this.iefix &&
(navigator.appVersion.indexOf('MSIE')>0) &&
(navigator.userAgent.indexOf('Opera')<0) &&
(Element.getStyle(this.update, 'position')=='absolute')) {
new Insertion.After(this.update,
'<iframe id="' + this.update.id + '_iefix" '+
'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' +
'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');
this.iefix = $(this.update.id+'_iefix');
}
if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50);
},
fixIEOverlapping: function() {
Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)});
this.iefix.style.zIndex = 1;
this.update.style.zIndex = 2;
Element.show(this.iefix);
},
hide: function() {
this.stopIndicator();
if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update);
if(this.iefix) Element.hide(this.iefix);
},
startIndicator: function() {
if(this.options.indicator) Element.show(this.options.indicator);
},
stopIndicator: function() {
if(this.options.indicator) Element.hide(this.options.indicator);
},
onKeyPress: function(event) {
if(this.active)
switch(event.keyCode) {
case Event.KEY_TAB:
case Event.KEY_RETURN:
this.selectEntry();
Event.stop(event);
case Event.KEY_ESC:
this.hide();
this.active = false;
Event.stop(event);
return;
case Event.KEY_LEFT:
case Event.KEY_RIGHT:
return;
case Event.KEY_UP:
this.markPrevious();
this.render();
if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);
return;
case Event.KEY_DOWN:
this.markNext();
this.render();
if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);
return;
}
else
if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN ||
(navigator.appVersion.indexOf('AppleWebKit') > 0 && event.keyCode == 0)) return;
this.changed = true;
this.hasFocus = true;
if(this.observer) clearTimeout(this.observer);
this.observer =
setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
},
activate: function() {
this.changed = false;
this.hasFocus = true;
this.getUpdatedChoices();
},
onHover: function(event) {
var element = Event.findElement(event, 'LI');
if(this.index != element.autocompleteIndex)
{
this.index = element.autocompleteIndex;
this.render();
}
Event.stop(event);
},
onClick: function(event) {
var element = Event.findElement(event, 'LI');
this.index = element.autocompleteIndex;
this.selectEntry();
this.hide();
},
onBlur: function(event) {
// needed to make click events working
setTimeout(this.hide.bind(this), 250);
this.hasFocus = false;
this.active = false;
},
render: function() {
if(this.entryCount > 0) {
for (var i = 0; i < this.entryCount; i++)
this.index==i ?
Element.addClassName(this.getEntry(i),"selected") :
Element.removeClassName(this.getEntry(i),"selected");
if(this.hasFocus) {
this.show();
this.active = true;
}
} else {
this.active = false;
this.hide();
}
},
markPrevious: function() {
if(this.index > 0) this.index--
else this.index = this.entryCount-1;
this.getEntry(this.index).scrollIntoView(true);
},
markNext: function() {
if(this.index < this.entryCount-1) this.index++
else this.index = 0;
this.getEntry(this.index).scrollIntoView(false);
},
getEntry: function(index) {
return this.update.firstChild.childNodes[index];
},
getCurrentEntry: function() {
return this.getEntry(this.index);
},
selectEntry: function() {
this.active = false;
this.updateElement(this.getCurrentEntry());
},
updateElement: function(selectedElement) {
if (this.options.updateElement) {
this.options.updateElement(selectedElement);
return;
}
var value = '';
if (this.options.select) {
var nodes = document.getElementsByClassName(this.options.select, selectedElement) || [];
if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select);
} else
value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
var lastTokenPos = this.findLastToken();
if (lastTokenPos != -1) {
var newValue = this.element.value.substr(0, lastTokenPos + 1);
var whitespace = this.element.value.substr(lastTokenPos + 1).match(/^\s+/);
if (whitespace)
newValue += whitespace[0];
this.element.value = newValue + value;
} else {
this.element.value = value;
}
this.element.focus();
if (this.options.afterUpdateElement)
this.options.afterUpdateElement(this.element, selectedElement);
},
updateChoices: function(choices) {
if(!this.changed && this.hasFocus) {
this.update.innerHTML = choices;
Element.cleanWhitespace(this.update);
Element.cleanWhitespace(this.update.down());
if(this.update.firstChild && this.update.down().childNodes) {
this.entryCount =
this.update.down().childNodes.length;
for (var i = 0; i < this.entryCount; i++) {
var entry = this.getEntry(i);
entry.autocompleteIndex = i;
this.addObservers(entry);
}
} else {
this.entryCount = 0;
}
this.stopIndicator();
this.index = 0;
if(this.entryCount==1 && this.options.autoSelect) {
this.selectEntry();
this.hide();
} else {
this.render();
}
}
},
addObservers: function(element) {
Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this));
Event.observe(element, "click", this.onClick.bindAsEventListener(this));
},
onObserverEvent: function() {
this.changed = false;
if(this.getToken().length>=this.options.minChars) {
this.startIndicator();
this.getUpdatedChoices();
} else {
this.active = false;
this.hide();
}
},
getToken: function() {
var tokenPos = this.findLastToken();
if (tokenPos != -1)
var ret = this.element.value.substr(tokenPos + 1).replace(/^\s+/,'').replace(/\s+$/,'');
else
var ret = this.element.value;
return /\n/.test(ret) ? '' : ret;
},
findLastToken: function() {
var lastTokenPos = -1;
for (var i=0; i<this.options.tokens.length; i++) {
var thisTokenPos = this.element.value.lastIndexOf(this.options.tokens[i]);
if (thisTokenPos > lastTokenPos)
lastTokenPos = thisTokenPos;
}
return lastTokenPos;
}
}
Ajax.Autocompleter = Class.create();
Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype), {
initialize: function(element, update, url, options) {
this.baseInitialize(element, update, options);
this.options.asynchronous = true;
this.options.onComplete = this.onComplete.bind(this);
this.options.defaultParams = this.options.parameters || null;
this.url = url;
},
getUpdatedChoices: function() {
entry = encodeURIComponent(this.options.paramName) + '=' +
encodeURIComponent(this.getToken());
this.options.parameters = this.options.callback ?
this.options.callback(this.element, entry) : entry;
if(this.options.defaultParams)
this.options.parameters += '&' + this.options.defaultParams;
new Ajax.Request(this.url, this.options);
},
onComplete: function(request) {
this.updateChoices(request.responseText);
}
});
// The local array autocompleter. Used when you'd prefer to
// inject an array of autocompletion options into the page, rather
// than sending out Ajax queries, which can be quite slow sometimes.
//
// The constructor takes four parameters. The first two are, as usual,
// the id of the monitored textbox, and id of the autocompletion menu.
// The third is the array you want to autocomplete from, and the fourth
// is the options block.
//
// Extra local autocompletion options:
// - choices - How many autocompletion choices to offer
//
// - partialSearch - If false, the autocompleter will match entered
// text only at the beginning of strings in the
// autocomplete array. Defaults to true, which will
// match text at the beginning of any *word* in the
// strings in the autocomplete array. If you want to
// search anywhere in the string, additionally set
// the option fullSearch to true (default: off).
//
// - fullSsearch - Search anywhere in autocomplete array strings.
//
// - partialChars - How many characters to enter before triggering
// a partial match (unlike minChars, which defines
// how many characters are required to do any match
// at all). Defaults to 2.
//
// - ignoreCase - Whether to ignore case when autocompleting.
// Defaults to true.
//
// It's possible to pass in a custom function as the 'selector'
// option, if you prefer to write your own autocompletion logic.
// In that case, the other options above will not apply unless
// you support them.
Autocompleter.Local = Class.create();
Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), {
initialize: function(element, update, array, options) {
this.baseInitialize(element, update, options);
this.options.array = array;
},
getUpdatedChoices: function() {
this.updateChoices(this.options.selector(this));
},
setOptions: function(options) {
this.options = Object.extend({
choices: 10,
partialSearch: true,
partialChars: 2,
ignoreCase: true,
fullSearch: false,
selector: function(instance) {
var ret = []; // Beginning matches
var partial = []; // Inside matches
var entry = instance.getToken();
var count = 0;
for (var i = 0; i < instance.options.array.length &&
ret.length < instance.options.choices ; i++) {
var elem = instance.options.array[i];
var foundPos = instance.options.ignoreCase ?
elem.toLowerCase().indexOf(entry.toLowerCase()) :
elem.indexOf(entry);
while (foundPos != -1) {
if (foundPos == 0 && elem.length != entry.length) {
ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" +
elem.substr(entry.length) + "</li>");
break;
} else if (entry.length >= instance.options.partialChars &&
instance.options.partialSearch && foundPos != -1) {
if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) {
partial.push("<li>" + elem.substr(0, foundPos) + "<strong>" +
elem.substr(foundPos, entry.length) + "</strong>" + elem.substr(
foundPos + entry.length) + "</li>");
break;
}
}
foundPos = instance.options.ignoreCase ?
elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) :
elem.indexOf(entry, foundPos + 1);
}
}
if (partial.length)
ret = ret.concat(partial.slice(0, instance.options.choices - ret.length))
return "<ul>" + ret.join('') + "</ul>";
}
}, options || {});
}
});
// AJAX in-place editor
//
// see documentation on http://wiki.script.aculo.us/scriptaculous/show/Ajax.InPlaceEditor
// Use this if you notice weird scrolling problems on some browsers,
// the DOM might be a bit confused when this gets called so do this
// waits 1 ms (with setTimeout) until it does the activation
Field.scrollFreeActivate = function(field) {
setTimeout(function() {
Field.activate(field);
}, 1);
}
Ajax.InPlaceEditor = Class.create();
Ajax.InPlaceEditor.defaultHighlightColor = "#FFFF99";
Ajax.InPlaceEditor.prototype = {
initialize: function(element, url, options) {
this.url = url;
this.element = $(element);
this.options = Object.extend({
paramName: "value",
okButton: true,
okText: "ok",
cancelLink: true,
cancelText: "cancel",
savingText: "Saving...",
clickToEditText: "Click to edit",
okText: "ok",
rows: 1,
onComplete: function(transport, element) {
new Effect.Highlight(element, {startcolor: this.options.highlightcolor});
},
onFailure: function(transport) {
alert("Error communicating with the server: " + transport.responseText.stripTags());
},
callback: function(form) {
return Form.serialize(form);
},
handleLineBreaks: true,
loadingText: 'Loading...',
savingClassName: 'inplaceeditor-saving',
loadingClassName: 'inplaceeditor-loading',
formClassName: 'inplaceeditor-form',
highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor,
highlightendcolor: "#FFFFFF",
externalControl: null,
submitOnBlur: false,
ajaxOptions: {},
evalScripts: false
}, options || {});
if(!this.options.formId && this.element.id) {
this.options.formId = this.element.id + "-inplaceeditor";
if ($(this.options.formId)) {
// there's already a form with that name, don't specify an id
this.options.formId = null;
}
}
if (this.options.externalControl) {
this.options.externalControl = $(this.options.externalControl);
}
this.originalBackground = Element.getStyle(this.element, 'background-color');
if (!this.originalBackground) {
this.originalBackground = "transparent";
}
this.element.title = this.options.clickToEditText;
this.onclickListener = this.enterEditMode.bindAsEventListener(this);
this.mouseoverListener = this.enterHover.bindAsEventListener(this);
this.mouseoutListener = this.leaveHover.bindAsEventListener(this);
Event.observe(this.element, 'click', this.onclickListener);
Event.observe(this.element, 'mouseover', this.mouseoverListener);
Event.observe(this.element, 'mouseout', this.mouseoutListener);
if (this.options.externalControl) {
Event.observe(this.options.externalControl, 'click', this.onclickListener);
Event.observe(this.options.externalControl, 'mouseover', this.mouseoverListener);
Event.observe(this.options.externalControl, 'mouseout', this.mouseoutListener);
}
},
enterEditMode: function(evt) {
if (this.saving) return;
if (this.editing) return;
this.editing = true;
this.onEnterEditMode();
if (this.options.externalControl) {
Element.hide(this.options.externalControl);
}
Element.hide(this.element);
this.createForm();
this.element.parentNode.insertBefore(this.form, this.element);
if (!this.options.loadTextURL) Field.scrollFreeActivate(this.editField);
// stop the event to avoid a page refresh in Safari
if (evt) {
Event.stop(evt);
}
return false;
},
createForm: function() {
this.form = document.createElement("form");
this.form.id = this.options.formId;
Element.addClassName(this.form, this.options.formClassName)
this.form.onsubmit = this.onSubmit.bind(this);
this.createEditField();
if (this.options.textarea) {
var br = document.createElement("br");
this.form.appendChild(br);
}
if (this.options.okButton) {
okButton = document.createElement("input");
okButton.type = "submit";
okButton.value = this.options.okText;
okButton.className = 'editor_ok_button';
this.form.appendChild(okButton);
}
if (this.options.cancelLink) {
cancelLink = document.createElement("a");
cancelLink.href = "#";
cancelLink.appendChild(document.createTextNode(this.options.cancelText));
cancelLink.onclick = this.onclickCancel.bind(this);
cancelLink.className = 'editor_cancel';
this.form.appendChild(cancelLink);
}
},
hasHTMLLineBreaks: function(string) {
if (!this.options.handleLineBreaks) return false;
return string.match(/<br/i) || string.match(/<p>/i);
},
convertHTMLLineBreaks: function(string) {
return string.replace(/<br>/gi, "\n").replace(/<br\/>/gi, "\n").replace(/<\/p>/gi, "\n").replace(/<p>/gi, "");
},
createEditField: function() {
var text;
if(this.options.loadTextURL) {
text = this.options.loadingText;
} else {
text = this.getText();
}
var obj = this;
if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) {
this.options.textarea = false;
var textField = document.createElement("input");
textField.obj = this;
textField.type = "text";
textField.name = this.options.paramName;
textField.value = text;
textField.style.backgroundColor = this.options.highlightcolor;
textField.className = 'editor_field';
var size = this.options.size || this.options.cols || 0;
if (size != 0) textField.size = size;
if (this.options.submitOnBlur)
textField.onblur = this.onSubmit.bind(this);
this.editField = textField;
} else {
this.options.textarea = true;
var textArea = document.createElement("textarea");
textArea.obj = this;
textArea.name = this.options.paramName;
textArea.value = this.convertHTMLLineBreaks(text);
textArea.rows = this.options.rows;
textArea.cols = this.options.cols || 40;
textArea.className = 'editor_field';
if (this.options.submitOnBlur)
textArea.onblur = this.onSubmit.bind(this);
this.editField = textArea;
}
if(this.options.loadTextURL) {
this.loadExternalText();
}
this.form.appendChild(this.editField);
},
getText: function() {
return this.element.innerHTML;
},
loadExternalText: function() {
Element.addClassName(this.form, this.options.loadingClassName);
this.editField.disabled = true;
new Ajax.Request(
this.options.loadTextURL,
Object.extend({
asynchronous: true,
onComplete: this.onLoadedExternalText.bind(this)
}, this.options.ajaxOptions)
);
},
onLoadedExternalText: function(transport) {
Element.removeClassName(this.form, this.options.loadingClassName);
this.editField.disabled = false;
this.editField.value = transport.responseText.stripTags();
Field.scrollFreeActivate(this.editField);
},
onclickCancel: function() {
this.onComplete();
this.leaveEditMode();
return false;
},
onFailure: function(transport) {
this.options.onFailure(transport);
if (this.oldInnerHTML) {
this.element.innerHTML = this.oldInnerHTML;
this.oldInnerHTML = null;
}
return false;
},
onSubmit: function() {
// onLoading resets these so we need to save them away for the Ajax call
var form = this.form;
var value = this.editField.value;
// do this first, sometimes the ajax call returns before we get a chance to switch on Saving...
// which means this will actually switch on Saving... *after* we've left edit mode causing Saving...
// to be displayed indefinitely
this.onLoading();
if (this.options.evalScripts) {
new Ajax.Request(
this.url, Object.extend({
parameters: this.options.callback(form, value),
onComplete: this.onComplete.bind(this),
onFailure: this.onFailure.bind(this),
asynchronous:true,
evalScripts:true
}, this.options.ajaxOptions));
} else {
new Ajax.Updater(
{ success: this.element,
// don't update on failure (this could be an option)
failure: null },
this.url, Object.extend({
parameters: this.options.callback(form, value),
onComplete: this.onComplete.bind(this),
onFailure: this.onFailure.bind(this)
}, this.options.ajaxOptions));
}
// stop the event to avoid a page refresh in Safari
if (arguments.length > 1) {
Event.stop(arguments[0]);
}
return false;
},
onLoading: function() {
this.saving = true;
this.removeForm();
this.leaveHover();
this.showSaving();
},
showSaving: function() {
this.oldInnerHTML = this.element.innerHTML;
this.element.innerHTML = this.options.savingText;
Element.addClassName(this.element, this.options.savingClassName);
this.element.style.backgroundColor = this.originalBackground;
Element.show(this.element);
},
removeForm: function() {
if(this.form) {
if (this.form.parentNode) Element.remove(this.form);
this.form = null;
}
},
enterHover: function() {
if (this.saving) return;
this.element.style.backgroundColor = this.options.highlightcolor;
if (this.effect) {
this.effect.cancel();
}
Element.addClassName(this.element, this.options.hoverClassName)
},
leaveHover: function() {
if (this.options.backgroundColor) {
this.element.style.backgroundColor = this.oldBackground;
}
Element.removeClassName(this.element, this.options.hoverClassName)
if (this.saving) return;
this.effect = new Effect.Highlight(this.element, {
startcolor: this.options.highlightcolor,
endcolor: this.options.highlightendcolor,
restorecolor: this.originalBackground
});
},
leaveEditMode: function() {
Element.removeClassName(this.element, this.options.savingClassName);
this.removeForm();
this.leaveHover();
this.element.style.backgroundColor = this.originalBackground;
Element.show(this.element);
if (this.options.externalControl) {
Element.show(this.options.externalControl);
}
this.editing = false;
this.saving = false;
this.oldInnerHTML = null;
this.onLeaveEditMode();
},
onComplete: function(transport) {
this.leaveEditMode();
this.options.onComplete.bind(this)(transport, this.element);
},
onEnterEditMode: function() {},
onLeaveEditMode: function() {},
dispose: function() {
if (this.oldInnerHTML) {
this.element.innerHTML = this.oldInnerHTML;
}
this.leaveEditMode();
Event.stopObserving(this.element, 'click', this.onclickListener);
Event.stopObserving(this.element, 'mouseover', this.mouseoverListener);
Event.stopObserving(this.element, 'mouseout', this.mouseoutListener);
if (this.options.externalControl) {
Event.stopObserving(this.options.externalControl, 'click', this.onclickListener);
Event.stopObserving(this.options.externalControl, 'mouseover', this.mouseoverListener);
Event.stopObserving(this.options.externalControl, 'mouseout', this.mouseoutListener);
}
}
};
Ajax.InPlaceCollectionEditor = Class.create();
Object.extend(Ajax.InPlaceCollectionEditor.prototype, Ajax.InPlaceEditor.prototype);
Object.extend(Ajax.InPlaceCollectionEditor.prototype, {
createEditField: function() {
if (!this.cached_selectTag) {
var selectTag = document.createElement("select");
var collection = this.options.collection || [];
var optionTag;
collection.each(function(e,i) {
optionTag = document.createElement("option");
optionTag.value = (e instanceof Array) ? e[0] : e;
if((typeof this.options.value == 'undefined') &&
((e instanceof Array) ? this.element.innerHTML == e[1] : e == optionTag.value)) optionTag.selected = true;
if(this.options.value==optionTag.value) optionTag.selected = true;
optionTag.appendChild(document.createTextNode((e instanceof Array) ? e[1] : e));
selectTag.appendChild(optionTag);
}.bind(this));
this.cached_selectTag = selectTag;
}
this.editField = this.cached_selectTag;
if(this.options.loadTextURL) this.loadExternalText();
this.form.appendChild(this.editField);
this.options.callback = function(form, value) {
return "value=" + encodeURIComponent(value);
}
}
});
// Delayed observer, like Form.Element.Observer,
// but waits for delay after last key input
// Ideal for live-search fields
Form.Element.DelayedObserver = Class.create();
Form.Element.DelayedObserver.prototype = {
initialize: function(element, delay, callback) {
this.delay = delay || 0.5;
this.element = $(element);
this.callback = callback;
this.timer = null;
this.lastValue = $F(this.element);
Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));
},
delayedListener: function(event) {
if(this.lastValue == $F(this.element)) return;
if(this.timer) clearTimeout(this.timer);
this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000);
this.lastValue = $F(this.element);
},
onTimerEvent: function() {
this.timer = null;
this.callback(this.element, $F(this.element));
}
};

View File

@ -0,0 +1,942 @@
// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// (c) 2005, 2006 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
//
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/
if(typeof Effect == 'undefined')
throw("dragdrop.js requires including script.aculo.us' effects.js library");
var Droppables = {
drops: [],
remove: function(element) {
this.drops = this.drops.reject(function(d) { return d.element==$(element) });
},
add: function(element) {
element = $(element);
var options = Object.extend({
greedy: true,
hoverclass: null,
tree: false
}, arguments[1] || {});
// cache containers
if(options.containment) {
options._containers = [];
var containment = options.containment;
if((typeof containment == 'object') &&
(containment.constructor == Array)) {
containment.each( function(c) { options._containers.push($(c)) });
} else {
options._containers.push($(containment));
}
}
if(options.accept) options.accept = [options.accept].flatten();
Element.makePositioned(element); // fix IE
options.element = element;
this.drops.push(options);
},
findDeepestChild: function(drops) {
deepest = drops[0];
for (i = 1; i < drops.length; ++i)
if (Element.isParent(drops[i].element, deepest.element))
deepest = drops[i];
return deepest;
},
isContained: function(element, drop) {
var containmentNode;
if(drop.tree) {
containmentNode = element.treeNode;
} else {
containmentNode = element.parentNode;
}
return drop._containers.detect(function(c) { return containmentNode == c });
},
isAffected: function(point, element, drop) {
return (
(drop.element!=element) &&
((!drop._containers) ||
this.isContained(element, drop)) &&
((!drop.accept) ||
(Element.classNames(element).detect(
function(v) { return drop.accept.include(v) } ) )) &&
Position.within(drop.element, point[0], point[1]) );
},
deactivate: function(drop) {
if(drop.hoverclass)
Element.removeClassName(drop.element, drop.hoverclass);
this.last_active = null;
},
activate: function(drop) {
if(drop.hoverclass)
Element.addClassName(drop.element, drop.hoverclass);
this.last_active = drop;
},
show: function(point, element) {
if(!this.drops.length) return;
var affected = [];
if(this.last_active) this.deactivate(this.last_active);
this.drops.each( function(drop) {
if(Droppables.isAffected(point, element, drop))
affected.push(drop);
});
if(affected.length>0) {
drop = Droppables.findDeepestChild(affected);
Position.within(drop.element, point[0], point[1]);
if(drop.onHover)
drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
Droppables.activate(drop);
}
},
fire: function(event, element) {
if(!this.last_active) return;
Position.prepare();
if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active))
if (this.last_active.onDrop)
this.last_active.onDrop(element, this.last_active.element, event);
},
reset: function() {
if(this.last_active)
this.deactivate(this.last_active);
}
}
var Draggables = {
drags: [],
observers: [],
register: function(draggable) {
if(this.drags.length == 0) {
this.eventMouseUp = this.endDrag.bindAsEventListener(this);
this.eventMouseMove = this.updateDrag.bindAsEventListener(this);
this.eventKeypress = this.keyPress.bindAsEventListener(this);
Event.observe(document, "mouseup", this.eventMouseUp);
Event.observe(document, "mousemove", this.eventMouseMove);
Event.observe(document, "keypress", this.eventKeypress);
}
this.drags.push(draggable);
},
unregister: function(draggable) {
this.drags = this.drags.reject(function(d) { return d==draggable });
if(this.drags.length == 0) {
Event.stopObserving(document, "mouseup", this.eventMouseUp);
Event.stopObserving(document, "mousemove", this.eventMouseMove);
Event.stopObserving(document, "keypress", this.eventKeypress);
}
},
activate: function(draggable) {
if(draggable.options.delay) {
this._timeout = setTimeout(function() {
Draggables._timeout = null;
window.focus();
Draggables.activeDraggable = draggable;
}.bind(this), draggable.options.delay);
} else {
window.focus(); // allows keypress events if window isn't currently focused, fails for Safari
this.activeDraggable = draggable;
}
},
deactivate: function() {
this.activeDraggable = null;
},
updateDrag: function(event) {
if(!this.activeDraggable) return;
var pointer = [Event.pointerX(event), Event.pointerY(event)];
// Mozilla-based browsers fire successive mousemove events with
// the same coordinates, prevent needless redrawing (moz bug?)
if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;
this._lastPointer = pointer;
this.activeDraggable.updateDrag(event, pointer);
},
endDrag: function(event) {
if(this._timeout) {
clearTimeout(this._timeout);
this._timeout = null;
}
if(!this.activeDraggable) return;
this._lastPointer = null;
this.activeDraggable.endDrag(event);
this.activeDraggable = null;
},
keyPress: function(event) {
if(this.activeDraggable)
this.activeDraggable.keyPress(event);
},
addObserver: function(observer) {
this.observers.push(observer);
this._cacheObserverCallbacks();
},
removeObserver: function(element) { // element instead of observer fixes mem leaks
this.observers = this.observers.reject( function(o) { return o.element==element });
this._cacheObserverCallbacks();
},
notify: function(eventName, draggable, event) { // 'onStart', 'onEnd', 'onDrag'
if(this[eventName+'Count'] > 0)
this.observers.each( function(o) {
if(o[eventName]) o[eventName](eventName, draggable, event);
});
if(draggable.options[eventName]) draggable.options[eventName](draggable, event);
},
_cacheObserverCallbacks: function() {
['onStart','onEnd','onDrag'].each( function(eventName) {
Draggables[eventName+'Count'] = Draggables.observers.select(
function(o) { return o[eventName]; }
).length;
});
}
}
/*--------------------------------------------------------------------------*/
var Draggable = Class.create();
Draggable._dragging = {};
Draggable.prototype = {
initialize: function(element) {
var defaults = {
handle: false,
reverteffect: function(element, top_offset, left_offset) {
var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;
new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur,
queue: {scope:'_draggable', position:'end'}
});
},
endeffect: function(element) {
var toOpacity = typeof element._opacity == 'number' ? element._opacity : 1.0;
new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity,
queue: {scope:'_draggable', position:'end'},
afterFinish: function(){
Draggable._dragging[element] = false
}
});
},
zindex: 1000,
revert: false,
scroll: false,
scrollSensitivity: 20,
scrollSpeed: 15,
snap: false, // false, or xy or [x,y] or function(x,y){ return [x,y] }
delay: 0
};
if(!arguments[1] || typeof arguments[1].endeffect == 'undefined')
Object.extend(defaults, {
starteffect: function(element) {
element._opacity = Element.getOpacity(element);
Draggable._dragging[element] = true;
new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7});
}
});
var options = Object.extend(defaults, arguments[1] || {});
this.element = $(element);
if(options.handle && (typeof options.handle == 'string'))
this.handle = this.element.down('.'+options.handle, 0);
if(!this.handle) this.handle = $(options.handle);
if(!this.handle) this.handle = this.element;
if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) {
options.scroll = $(options.scroll);
this._isScrollChild = Element.childOf(this.element, options.scroll);
}
Element.makePositioned(this.element); // fix IE
this.delta = this.currentDelta();
this.options = options;
this.dragging = false;
this.eventMouseDown = this.initDrag.bindAsEventListener(this);
Event.observe(this.handle, "mousedown", this.eventMouseDown);
Draggables.register(this);
},
destroy: function() {
Event.stopObserving(this.handle, "mousedown", this.eventMouseDown);
Draggables.unregister(this);
},
currentDelta: function() {
return([
parseInt(Element.getStyle(this.element,'left') || '0'),
parseInt(Element.getStyle(this.element,'top') || '0')]);
},
initDrag: function(event) {
if(typeof Draggable._dragging[this.element] != 'undefined' &&
Draggable._dragging[this.element]) return;
if(Event.isLeftClick(event)) {
// abort on form elements, fixes a Firefox issue
var src = Event.element(event);
if(src.tagName && (
src.tagName=='INPUT' ||
src.tagName=='SELECT' ||
src.tagName=='OPTION' ||
src.tagName=='BUTTON' ||
src.tagName=='TEXTAREA')) return;
var pointer = [Event.pointerX(event), Event.pointerY(event)];
var pos = Position.cumulativeOffset(this.element);
this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });
Draggables.activate(this);
Event.stop(event);
}
},
startDrag: function(event) {
this.dragging = true;
if(this.options.zindex) {
this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);
this.element.style.zIndex = this.options.zindex;
}
if(this.options.ghosting) {
this._clone = this.element.cloneNode(true);
Position.absolutize(this.element);
this.element.parentNode.insertBefore(this._clone, this.element);
}
if(this.options.scroll) {
if (this.options.scroll == window) {
var where = this._getWindowScroll(this.options.scroll);
this.originalScrollLeft = where.left;
this.originalScrollTop = where.top;
} else {
this.originalScrollLeft = this.options.scroll.scrollLeft;
this.originalScrollTop = this.options.scroll.scrollTop;
}
}
Draggables.notify('onStart', this, event);
if(this.options.starteffect) this.options.starteffect(this.element);
},
updateDrag: function(event, pointer) {
if(!this.dragging) this.startDrag(event);
Position.prepare();
Droppables.show(pointer, this.element);
Draggables.notify('onDrag', this, event);
this.draw(pointer);
if(this.options.change) this.options.change(this);
if(this.options.scroll) {
this.stopScrolling();
var p;
if (this.options.scroll == window) {
with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; }
} else {
p = Position.page(this.options.scroll);
p[0] += this.options.scroll.scrollLeft + Position.deltaX;
p[1] += this.options.scroll.scrollTop + Position.deltaY;
p.push(p[0]+this.options.scroll.offsetWidth);
p.push(p[1]+this.options.scroll.offsetHeight);
}
var speed = [0,0];
if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity);
if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity);
if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity);
if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity);
this.startScrolling(speed);
}
// fix AppleWebKit rendering
if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
Event.stop(event);
},
finishDrag: function(event, success) {
this.dragging = false;
if(this.options.ghosting) {
Position.relativize(this.element);
Element.remove(this._clone);
this._clone = null;
}
if(success) Droppables.fire(event, this.element);
Draggables.notify('onEnd', this, event);
var revert = this.options.revert;
if(revert && typeof revert == 'function') revert = revert(this.element);
var d = this.currentDelta();
if(revert && this.options.reverteffect) {
this.options.reverteffect(this.element,
d[1]-this.delta[1], d[0]-this.delta[0]);
} else {
this.delta = d;
}
if(this.options.zindex)
this.element.style.zIndex = this.originalZ;
if(this.options.endeffect)
this.options.endeffect(this.element);
Draggables.deactivate(this);
Droppables.reset();
},
keyPress: function(event) {
if(event.keyCode!=Event.KEY_ESC) return;
this.finishDrag(event, false);
Event.stop(event);
},
endDrag: function(event) {
if(!this.dragging) return;
this.stopScrolling();
this.finishDrag(event, true);
Event.stop(event);
},
draw: function(point) {
var pos = Position.cumulativeOffset(this.element);
if(this.options.ghosting) {
var r = Position.realOffset(this.element);
pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY;
}
var d = this.currentDelta();
pos[0] -= d[0]; pos[1] -= d[1];
if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) {
pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
}
var p = [0,1].map(function(i){
return (point[i]-pos[i]-this.offset[i])
}.bind(this));
if(this.options.snap) {
if(typeof this.options.snap == 'function') {
p = this.options.snap(p[0],p[1],this);
} else {
if(this.options.snap instanceof Array) {
p = p.map( function(v, i) {
return Math.round(v/this.options.snap[i])*this.options.snap[i] }.bind(this))
} else {
p = p.map( function(v) {
return Math.round(v/this.options.snap)*this.options.snap }.bind(this))
}
}}
var style = this.element.style;
if((!this.options.constraint) || (this.options.constraint=='horizontal'))
style.left = p[0] + "px";
if((!this.options.constraint) || (this.options.constraint=='vertical'))
style.top = p[1] + "px";
if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
},
stopScrolling: function() {
if(this.scrollInterval) {
clearInterval(this.scrollInterval);
this.scrollInterval = null;
Draggables._lastScrollPointer = null;
}
},
startScrolling: function(speed) {
if(!(speed[0] || speed[1])) return;
this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed];
this.lastScrolled = new Date();
this.scrollInterval = setInterval(this.scroll.bind(this), 10);
},
scroll: function() {
var current = new Date();
var delta = current - this.lastScrolled;
this.lastScrolled = current;
if(this.options.scroll == window) {
with (this._getWindowScroll(this.options.scroll)) {
if (this.scrollSpeed[0] || this.scrollSpeed[1]) {
var d = delta / 1000;
this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] );
}
}
} else {
this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000;
this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000;
}
Position.prepare();
Droppables.show(Draggables._lastPointer, this.element);
Draggables.notify('onDrag', this);
if (this._isScrollChild) {
Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer);
Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000;
Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000;
if (Draggables._lastScrollPointer[0] < 0)
Draggables._lastScrollPointer[0] = 0;
if (Draggables._lastScrollPointer[1] < 0)
Draggables._lastScrollPointer[1] = 0;
this.draw(Draggables._lastScrollPointer);
}
if(this.options.change) this.options.change(this);
},
_getWindowScroll: function(w) {
var T, L, W, H;
with (w.document) {
if (w.document.documentElement && documentElement.scrollTop) {
T = documentElement.scrollTop;
L = documentElement.scrollLeft;
} else if (w.document.body) {
T = body.scrollTop;
L = body.scrollLeft;
}
if (w.innerWidth) {
W = w.innerWidth;
H = w.innerHeight;
} else if (w.document.documentElement && documentElement.clientWidth) {
W = documentElement.clientWidth;
H = documentElement.clientHeight;
} else {
W = body.offsetWidth;
H = body.offsetHeight
}
}
return { top: T, left: L, width: W, height: H };
}
}
/*--------------------------------------------------------------------------*/
var SortableObserver = Class.create();
SortableObserver.prototype = {
initialize: function(element, observer) {
this.element = $(element);
this.observer = observer;
this.lastValue = Sortable.serialize(this.element);
},
onStart: function() {
this.lastValue = Sortable.serialize(this.element);
},
onEnd: function() {
Sortable.unmark();
if(this.lastValue != Sortable.serialize(this.element))
this.observer(this.element)
}
}
var Sortable = {
SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/,
sortables: {},
_findRootElement: function(element) {
while (element.tagName != "BODY") {
if(element.id && Sortable.sortables[element.id]) return element;
element = element.parentNode;
}
},
options: function(element) {
element = Sortable._findRootElement($(element));
if(!element) return;
return Sortable.sortables[element.id];
},
destroy: function(element){
var s = Sortable.options(element);
if(s) {
Draggables.removeObserver(s.element);
s.droppables.each(function(d){ Droppables.remove(d) });
s.draggables.invoke('destroy');
delete Sortable.sortables[s.element.id];
}
},
create: function(element) {
element = $(element);
var options = Object.extend({
element: element,
tag: 'li', // assumes li children, override with tag: 'tagname'
dropOnEmpty: false,
tree: false,
treeTag: 'ul',
overlap: 'vertical', // one of 'vertical', 'horizontal'
constraint: 'vertical', // one of 'vertical', 'horizontal', false
containment: element, // also takes array of elements (or id's); or false
handle: false, // or a CSS class
only: false,
delay: 0,
hoverclass: null,
ghosting: false,
scroll: false,
scrollSensitivity: 20,
scrollSpeed: 15,
format: this.SERIALIZE_RULE,
onChange: Prototype.emptyFunction,
onUpdate: Prototype.emptyFunction
}, arguments[1] || {});
// clear any old sortable with same element
this.destroy(element);
// build options for the draggables
var options_for_draggable = {
revert: true,
scroll: options.scroll,
scrollSpeed: options.scrollSpeed,
scrollSensitivity: options.scrollSensitivity,
delay: options.delay,
ghosting: options.ghosting,
constraint: options.constraint,
handle: options.handle };
if(options.starteffect)
options_for_draggable.starteffect = options.starteffect;
if(options.reverteffect)
options_for_draggable.reverteffect = options.reverteffect;
else
if(options.ghosting) options_for_draggable.reverteffect = function(element) {
element.style.top = 0;
element.style.left = 0;
};
if(options.endeffect)
options_for_draggable.endeffect = options.endeffect;
if(options.zindex)
options_for_draggable.zindex = options.zindex;
// build options for the droppables
var options_for_droppable = {
overlap: options.overlap,
containment: options.containment,
tree: options.tree,
hoverclass: options.hoverclass,
onHover: Sortable.onHover
}
var options_for_tree = {
onHover: Sortable.onEmptyHover,
overlap: options.overlap,
containment: options.containment,
hoverclass: options.hoverclass
}
// fix for gecko engine
Element.cleanWhitespace(element);
options.draggables = [];
options.droppables = [];
// drop on empty handling
if(options.dropOnEmpty || options.tree) {
Droppables.add(element, options_for_tree);
options.droppables.push(element);
}
(this.findElements(element, options) || []).each( function(e) {
// handles are per-draggable
var handle = options.handle ?
$(e).down('.'+options.handle,0) : e;
options.draggables.push(
new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
Droppables.add(e, options_for_droppable);
if(options.tree) e.treeNode = element;
options.droppables.push(e);
});
if(options.tree) {
(Sortable.findTreeElements(element, options) || []).each( function(e) {
Droppables.add(e, options_for_tree);
e.treeNode = element;
options.droppables.push(e);
});
}
// keep reference
this.sortables[element.id] = options;
// for onupdate
Draggables.addObserver(new SortableObserver(element, options.onUpdate));
},
// return all suitable-for-sortable elements in a guaranteed order
findElements: function(element, options) {
return Element.findChildren(
element, options.only, options.tree ? true : false, options.tag);
},
findTreeElements: function(element, options) {
return Element.findChildren(
element, options.only, options.tree ? true : false, options.treeTag);
},
onHover: function(element, dropon, overlap) {
if(Element.isParent(dropon, element)) return;
if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) {
return;
} else if(overlap>0.5) {
Sortable.mark(dropon, 'before');
if(dropon.previousSibling != element) {
var oldParentNode = element.parentNode;
element.style.visibility = "hidden"; // fix gecko rendering
dropon.parentNode.insertBefore(element, dropon);
if(dropon.parentNode!=oldParentNode)
Sortable.options(oldParentNode).onChange(element);
Sortable.options(dropon.parentNode).onChange(element);
}
} else {
Sortable.mark(dropon, 'after');
var nextElement = dropon.nextSibling || null;
if(nextElement != element) {
var oldParentNode = element.parentNode;
element.style.visibility = "hidden"; // fix gecko rendering
dropon.parentNode.insertBefore(element, nextElement);
if(dropon.parentNode!=oldParentNode)
Sortable.options(oldParentNode).onChange(element);
Sortable.options(dropon.parentNode).onChange(element);
}
}
},
onEmptyHover: function(element, dropon, overlap) {
var oldParentNode = element.parentNode;
var droponOptions = Sortable.options(dropon);
if(!Element.isParent(dropon, element)) {
var index;
var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only});
var child = null;
if(children) {
var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap);
for (index = 0; index < children.length; index += 1) {
if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) {
offset -= Element.offsetSize (children[index], droponOptions.overlap);
} else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) {
child = index + 1 < children.length ? children[index + 1] : null;
break;
} else {
child = children[index];
break;
}
}
}
dropon.insertBefore(element, child);
Sortable.options(oldParentNode).onChange(element);
droponOptions.onChange(element);
}
},
unmark: function() {
if(Sortable._marker) Sortable._marker.hide();
},
mark: function(dropon, position) {
// mark on ghosting only
var sortable = Sortable.options(dropon.parentNode);
if(sortable && !sortable.ghosting) return;
if(!Sortable._marker) {
Sortable._marker =
($('dropmarker') || Element.extend(document.createElement('DIV'))).
hide().addClassName('dropmarker').setStyle({position:'absolute'});
document.getElementsByTagName("body").item(0).appendChild(Sortable._marker);
}
var offsets = Position.cumulativeOffset(dropon);
Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'});
if(position=='after')
if(sortable.overlap == 'horizontal')
Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'});
else
Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'});
Sortable._marker.show();
},
_tree: function(element, options, parent) {
var children = Sortable.findElements(element, options) || [];
for (var i = 0; i < children.length; ++i) {
var match = children[i].id.match(options.format);
if (!match) continue;
var child = {
id: encodeURIComponent(match ? match[1] : null),
element: element,
parent: parent,
children: [],
position: parent.children.length,
container: $(children[i]).down(options.treeTag)
}
/* Get the element containing the children and recurse over it */
if (child.container)
this._tree(child.container, options, child)
parent.children.push (child);
}
return parent;
},
tree: function(element) {
element = $(element);
var sortableOptions = this.options(element);
var options = Object.extend({
tag: sortableOptions.tag,
treeTag: sortableOptions.treeTag,
only: sortableOptions.only,
name: element.id,
format: sortableOptions.format
}, arguments[1] || {});
var root = {
id: null,
parent: null,
children: [],
container: element,
position: 0
}
return Sortable._tree(element, options, root);
},
/* Construct a [i] index for a particular node */
_constructIndex: function(node) {
var index = '';
do {
if (node.id) index = '[' + node.position + ']' + index;
} while ((node = node.parent) != null);
return index;
},
sequence: function(element) {
element = $(element);
var options = Object.extend(this.options(element), arguments[1] || {});
return $(this.findElements(element, options) || []).map( function(item) {
return item.id.match(options.format) ? item.id.match(options.format)[1] : '';
});
},
setSequence: function(element, new_sequence) {
element = $(element);
var options = Object.extend(this.options(element), arguments[2] || {});
var nodeMap = {};
this.findElements(element, options).each( function(n) {
if (n.id.match(options.format))
nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode];
n.parentNode.removeChild(n);
});
new_sequence.each(function(ident) {
var n = nodeMap[ident];
if (n) {
n[1].appendChild(n[0]);
delete nodeMap[ident];
}
});
},
serialize: function(element) {
element = $(element);
var options = Object.extend(Sortable.options(element), arguments[1] || {});
var name = encodeURIComponent(
(arguments[1] && arguments[1].name) ? arguments[1].name : element.id);
if (options.tree) {
return Sortable.tree(element, arguments[1]).children.map( function (item) {
return [name + Sortable._constructIndex(item) + "[id]=" +
encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));
}).flatten().join('&');
} else {
return Sortable.sequence(element, arguments[1]).map( function(item) {
return name + "[]=" + encodeURIComponent(item);
}).join('&');
}
}
}
// Returns true if child is contained within element
Element.isParent = function(child, element) {
if (!child.parentNode || child == element) return false;
if (child.parentNode == element) return true;
return Element.isParent(child.parentNode, element);
}
Element.findChildren = function(element, only, recursive, tagName) {
if(!element.hasChildNodes()) return null;
tagName = tagName.toUpperCase();
if(only) only = [only].flatten();
var elements = [];
$A(element.childNodes).each( function(e) {
if(e.tagName && e.tagName.toUpperCase()==tagName &&
(!only || (Element.classNames(e).detect(function(v) { return only.include(v) }))))
elements.push(e);
if(recursive) {
var grandchildren = Element.findChildren(e, only, recursive, tagName);
if(grandchildren) elements.push(grandchildren);
}
});
return (elements.length>0 ? elements.flatten() : []);
}
Element.offsetSize = function (element, type) {
return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')];
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
# See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file

View File

@ -0,0 +1,74 @@
body { background-color: #fff; color: #333; }
body, p, ol, ul, td {
font-family: verdana, arial, helvetica, sans-serif;
font-size: 13px;
line-height: 18px;
}
pre {
background-color: #eee;
padding: 10px;
font-size: 11px;
}
a { color: #000; }
a:visited { color: #666; }
a:hover { color: #fff; background-color:#000; }
.fieldWithErrors {
padding: 2px;
background-color: red;
display: table;
}
#errorExplanation {
width: 400px;
border: 2px solid red;
padding: 7px;
padding-bottom: 12px;
margin-bottom: 20px;
background-color: #f0f0f0;
}
#errorExplanation h2 {
text-align: left;
font-weight: bold;
padding: 5px 5px 5px 15px;
font-size: 12px;
margin: -7px;
background-color: #c00;
color: #fff;
}
#errorExplanation p {
color: #333;
margin-bottom: 0;
padding: 5px;
}
#errorExplanation ul li {
font-size: 12px;
list-style: square;
}
div.uploadStatus {
margin: 5px;
}
div.progressBar {
margin: 5px;
}
div.progressBar div.border {
background-color: #fff;
border: 1px solid grey;
width: 100%;
}
div.progressBar div.background {
background-color: #333;
height: 18px;
width: 0%;
}

3
test/rails_root/script/about Executable file
View File

@ -0,0 +1,3 @@
#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../config/boot'
require 'commands/about'

View File

@ -0,0 +1,3 @@
#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../config/boot'
require 'commands/breakpointer'

3
test/rails_root/script/console Executable file
View File

@ -0,0 +1,3 @@
#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../config/boot'
require 'commands/console'

3
test/rails_root/script/destroy Executable file
View File

@ -0,0 +1,3 @@
#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../config/boot'
require 'commands/destroy'

View File

@ -0,0 +1,3 @@
#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../config/boot'
require 'commands/generate'

View File

@ -0,0 +1,3 @@
#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../../config/boot'
require 'commands/performance/benchmarker'

View File

@ -0,0 +1,3 @@
#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../../config/boot'
require 'commands/performance/profiler'

3
test/rails_root/script/plugin Executable file
View File

@ -0,0 +1,3 @@
#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../config/boot'
require 'commands/plugin'

View File

@ -0,0 +1,3 @@
#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../../config/boot'
require 'commands/process/inspector'

View File

@ -0,0 +1,3 @@
#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../../config/boot'
require 'commands/process/reaper'

View File

@ -0,0 +1,3 @@
#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../../config/boot'
require 'commands/process/spawner'

3
test/rails_root/script/runner Executable file
View File

@ -0,0 +1,3 @@
#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../config/boot'
require 'commands/runner'

3
test/rails_root/script/server Executable file
View File

@ -0,0 +1,3 @@
#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../config/boot'
require 'commands/server'

1
test/rails_root/vendor/plugins/shoulda vendored Symbolic link
View File

@ -0,0 +1 @@
../../../../

View File

@ -1,3 +0,0 @@
sqlite3:
adapter: sqlite3
database: ":memory:"

View File

@ -1,26 +0,0 @@
ActiveRecord::Schema.define(:version => 1) do
create_table :posts do |t|
t.column :title, :string
t.column :body, :text
t.column :user_id, :integer
end
create_table :users do |t|
t.column :name, :string
t.column :email, :string
t.column :age, :integer
t.column :password, :string
t.column :company_id, :integer
end
create_table :taggings do |t|
t.column :user_id, :integer
t.column :tag_id, :integer
end
create_table :tags do |t|
t.column :name, :string
end
end

View File

@ -1,28 +1,28 @@
BASE = File.dirname(__FILE__)
$LOAD_PATH << File.join(BASE, '..', 'lib')
require 'rubygems'
require 'test/unit'
require 'active_support'
require 'active_record'
require 'active_record/fixtures'
require 'shoulda'
config = YAML::load(IO.read(File.join(BASE, "support", 'database.yml')))
ActiveRecord::Base.logger = Logger.new(File.join(BASE, "support", "debug.log"))
ActiveRecord::Base.establish_connection(config['sqlite3'])
# Load the environment
ENV['RAILS_ENV'] = 'sqlite3'
require File.dirname(__FILE__) + '/rails_root/config/environment.rb'
# Load the testing framework
require 'test_help'
silence_warnings { RAILS_ENV = ENV['RAILS_ENV'] }
# Run the migrations
ActiveRecord::Migration.verbose = false
load(File.join(BASE, "support", "schema.rb"))
Test::Unit::TestCase.fixture_path = File.join(BASE, "support", "fixtures")
ActiveRecord::Migrator.migrate("#{RAILS_ROOT}/db/migrate")
# Setup the fixtures path
Test::Unit::TestCase.fixture_path = File.join(File.dirname(__FILE__), "fixtures")
# $LOAD_PATH.unshift(Test::Unit::TestCase.fixture_path)
class Test::Unit::TestCase #:nodoc:
def self.fixtures(*args)
Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, args)
end
def create_fixtures(*table_names)
if block_given?
Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, table_names) { yield }
else
Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, table_names)
end
end
self.use_transactional_fixtures = false
self.use_instantiated_fixtures = false
end

13
test/unit/post_test.rb Normal file
View File

@ -0,0 +1,13 @@
require File.dirname(__FILE__) + '/../test_helper'
class PostTest < Test::Unit::TestCase
load_all_fixtures
should_belong_to :user
should_have_many :tags, :through => :taggings
should_require_unique_attributes :title
should_require_attributes :body, :message => /wtf/
should_require_attributes :title
should_only_allow_numeric_values_for :user_id
end

8
test/unit/tag_test.rb Normal file
View File

@ -0,0 +1,8 @@
require File.dirname(__FILE__) + '/../test_helper'
class TagTest < Test::Unit::TestCase
load_all_fixtures
should_have_many :taggings
should_have_many :posts
end

View File

@ -0,0 +1,8 @@
require File.dirname(__FILE__) + '/../test_helper'
class TaggingTest < Test::Unit::TestCase
load_all_fixtures
should_belong_to :post
should_belong_to :tag
end

13
test/unit/user_test.rb Normal file
View File

@ -0,0 +1,13 @@
require File.dirname(__FILE__) + '/../test_helper'
class UserTest < Test::Unit::TestCase
load_all_fixtures
should_have_many :posts
should_not_allow_values_for :email, "blah", "b lah"
should_allow_values_for :email, "a@b.com", "asdf@asdf.com"
should_ensure_length_in_range :email, 1..100
should_ensure_value_in_range :age, 1..100
should_protect_attributes :password
end