inital commit
This commit is contained in:
commit
351822e8ef
|
@ -0,0 +1,243 @@
|
||||||
|
== Welcome to Rails
|
||||||
|
|
||||||
|
Rails is a web-application framework that includes everything needed to create
|
||||||
|
database-backed web applications according to the Model-View-Control pattern.
|
||||||
|
|
||||||
|
This pattern splits the view (also called the presentation) into "dumb" templates
|
||||||
|
that are primarily responsible for inserting pre-built data in between HTML tags.
|
||||||
|
The model contains the "smart" domain objects (such as Account, Product, Person,
|
||||||
|
Post) that holds all the business logic and knows how to persist themselves to
|
||||||
|
a database. The controller handles the incoming requests (such as Save New Account,
|
||||||
|
Update Product, Show Post) by manipulating the model and directing data to the view.
|
||||||
|
|
||||||
|
In Rails, the model is handled by what's called an object-relational mapping
|
||||||
|
layer entitled Active Record. This layer allows you to present the data from
|
||||||
|
database rows as objects and embellish these data objects with business logic
|
||||||
|
methods. You can read more about Active Record in
|
||||||
|
link:files/vendor/rails/activerecord/README.html.
|
||||||
|
|
||||||
|
The controller and view are handled by the Action Pack, which handles both
|
||||||
|
layers by its two parts: Action View and Action Controller. These two layers
|
||||||
|
are bundled in a single package due to their heavy interdependence. This is
|
||||||
|
unlike the relationship between the Active Record and Action Pack that is much
|
||||||
|
more separate. Each of these packages can be used independently outside of
|
||||||
|
Rails. You can read more about Action Pack in
|
||||||
|
link:files/vendor/rails/actionpack/README.html.
|
||||||
|
|
||||||
|
|
||||||
|
== Getting Started
|
||||||
|
|
||||||
|
1. At the command prompt, start a new Rails application using the <tt>rails</tt> command
|
||||||
|
and your application name. Ex: rails myapp
|
||||||
|
2. Change directory into myapp and start the web server: <tt>script/server</tt> (run with --help for options)
|
||||||
|
3. Go to http://localhost:3000/ and get "Welcome aboard: You're riding the Rails!"
|
||||||
|
4. Follow the guidelines to start developing your application
|
||||||
|
|
||||||
|
|
||||||
|
== Web Servers
|
||||||
|
|
||||||
|
By default, Rails will try to use Mongrel if it's are installed when started with script/server, otherwise Rails will use WEBrick, the webserver that ships with Ruby. But you can also use Rails
|
||||||
|
with a variety of other web servers.
|
||||||
|
|
||||||
|
Mongrel is a Ruby-based webserver with a C component (which requires compilation) that is
|
||||||
|
suitable for development and deployment of Rails applications. If you have Ruby Gems installed,
|
||||||
|
getting up and running with mongrel is as easy as: <tt>gem install mongrel</tt>.
|
||||||
|
More info at: http://mongrel.rubyforge.org
|
||||||
|
|
||||||
|
Say other Ruby web servers like Thin and Ebb or regular web servers like Apache or LiteSpeed or
|
||||||
|
Lighttpd or IIS. The Ruby web servers are run through Rack and the latter can either be setup to use
|
||||||
|
FCGI or proxy to a pack of Mongrels/Thin/Ebb servers.
|
||||||
|
|
||||||
|
== Apache .htaccess example for FCGI/CGI
|
||||||
|
|
||||||
|
# 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"
|
||||||
|
|
||||||
|
|
||||||
|
== Debugging Rails
|
||||||
|
|
||||||
|
Sometimes your application goes wrong. Fortunately there are a lot of tools that
|
||||||
|
will help you debug it and get it back on the rails.
|
||||||
|
|
||||||
|
First area to check is the application log files. Have "tail -f" commands running
|
||||||
|
on the server.log and development.log. Rails will automatically display debugging
|
||||||
|
and runtime information to these files. Debugging info will also be shown in the
|
||||||
|
browser on requests from 127.0.0.1.
|
||||||
|
|
||||||
|
You can also log your own messages directly into the log file from your code using
|
||||||
|
the Ruby logger class from inside your controllers. Example:
|
||||||
|
|
||||||
|
class WeblogController < ActionController::Base
|
||||||
|
def destroy
|
||||||
|
@weblog = Weblog.find(params[:id])
|
||||||
|
@weblog.destroy
|
||||||
|
logger.info("#{Time.now} Destroyed Weblog ID ##{@weblog.id}!")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
The result will be a message in your log file along the lines of:
|
||||||
|
|
||||||
|
Mon Oct 08 14:22:29 +1000 2007 Destroyed Weblog ID #1
|
||||||
|
|
||||||
|
More information on how to use the logger is at http://www.ruby-doc.org/core/
|
||||||
|
|
||||||
|
Also, Ruby documentation can be found at http://www.ruby-lang.org/ including:
|
||||||
|
|
||||||
|
* The Learning Ruby (Pickaxe) Book: http://www.ruby-doc.org/docs/ProgrammingRuby/
|
||||||
|
* Learn to Program: http://pine.fm/LearnToProgram/ (a beginners guide)
|
||||||
|
|
||||||
|
These two online (and free) books will bring you up to speed on the Ruby language
|
||||||
|
and also on programming in general.
|
||||||
|
|
||||||
|
|
||||||
|
== Debugger
|
||||||
|
|
||||||
|
Debugger support is available through the debugger command when you start your Mongrel or
|
||||||
|
Webrick server with --debugger. This means that you can break out of execution at any point
|
||||||
|
in the code, investigate and change the model, AND then resume execution!
|
||||||
|
You need to install ruby-debug to run the server in debugging mode. With gems, use 'gem install ruby-debug'
|
||||||
|
Example:
|
||||||
|
|
||||||
|
class WeblogController < ActionController::Base
|
||||||
|
def index
|
||||||
|
@posts = Post.find(:all)
|
||||||
|
debugger
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
So the controller will accept the action, run the first line, then present you
|
||||||
|
with a IRB prompt in the server window. Here you can do things like:
|
||||||
|
|
||||||
|
>> @posts.inspect
|
||||||
|
=> "[#<Post:0x14a6be8 @attributes={\"title\"=>nil, \"body\"=>nil, \"id\"=>\"1\"}>,
|
||||||
|
#<Post:0x14a6620 @attributes={\"title\"=>\"Rails you know!\", \"body\"=>\"Only ten..\", \"id\"=>\"2\"}>]"
|
||||||
|
>> @posts.first.title = "hello from a debugger"
|
||||||
|
=> "hello from a debugger"
|
||||||
|
|
||||||
|
...and even better is that you can examine how your runtime objects actually work:
|
||||||
|
|
||||||
|
>> f = @posts.first
|
||||||
|
=> #<Post:0x13630c4 @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}>
|
||||||
|
>> f.
|
||||||
|
Display all 152 possibilities? (y or n)
|
||||||
|
|
||||||
|
Finally, when you're ready to resume execution, you enter "cont"
|
||||||
|
|
||||||
|
|
||||||
|
== Console
|
||||||
|
|
||||||
|
You can interact with the domain model by starting the console through <tt>script/console</tt>.
|
||||||
|
Here you'll have all parts of the application configured, just like it is when the
|
||||||
|
application is running. You can inspect domain models, change values, and save to the
|
||||||
|
database. Starting the script without arguments will launch it in the development environment.
|
||||||
|
Passing an argument will specify a different environment, like <tt>script/console production</tt>.
|
||||||
|
|
||||||
|
To reload your controllers and models after launching the console run <tt>reload!</tt>
|
||||||
|
|
||||||
|
== dbconsole
|
||||||
|
|
||||||
|
You can go to the command line of your database directly through <tt>script/dbconsole</tt>.
|
||||||
|
You would be connected to the database with the credentials defined in database.yml.
|
||||||
|
Starting the script without arguments will connect you to the development database. Passing an
|
||||||
|
argument will connect you to a different database, like <tt>script/dbconsole production</tt>.
|
||||||
|
Currently works for mysql, postgresql and sqlite.
|
||||||
|
|
||||||
|
== Description of Contents
|
||||||
|
|
||||||
|
app
|
||||||
|
Holds all the code that's specific to this particular application.
|
||||||
|
|
||||||
|
app/controllers
|
||||||
|
Holds controllers that should be named like weblogs_controller.rb for
|
||||||
|
automated URL mapping. All controllers should descend from ApplicationController
|
||||||
|
which itself descends from ActionController::Base.
|
||||||
|
|
||||||
|
app/models
|
||||||
|
Holds models that should be named like post.rb.
|
||||||
|
Most models will descend from ActiveRecord::Base.
|
||||||
|
|
||||||
|
app/views
|
||||||
|
Holds the template files for the view that should be named like
|
||||||
|
weblogs/index.html.erb for the WeblogsController#index action. All views use eRuby
|
||||||
|
syntax.
|
||||||
|
|
||||||
|
app/views/layouts
|
||||||
|
Holds the template files for layouts to be used with views. This models the common
|
||||||
|
header/footer method of wrapping views. In your views, define a layout using the
|
||||||
|
<tt>layout :default</tt> and create a file named default.html.erb. Inside default.html.erb,
|
||||||
|
call <% yield %> to render the view using this layout.
|
||||||
|
|
||||||
|
app/helpers
|
||||||
|
Holds view helpers that should be named like weblogs_helper.rb. These are generated
|
||||||
|
for you automatically when using script/generate for controllers. Helpers can be used to
|
||||||
|
wrap functionality for your views into methods.
|
||||||
|
|
||||||
|
config
|
||||||
|
Configuration files for the Rails environment, the routing map, the database, and other dependencies.
|
||||||
|
|
||||||
|
db
|
||||||
|
Contains the database schema in schema.rb. db/migrate contains all
|
||||||
|
the sequence of Migrations for your schema.
|
||||||
|
|
||||||
|
doc
|
||||||
|
This directory is where your application documentation will be stored when generated
|
||||||
|
using <tt>rake doc:app</tt>
|
||||||
|
|
||||||
|
lib
|
||||||
|
Application specific libraries. Basically, any kind of custom code that doesn't
|
||||||
|
belong under controllers, models, or helpers. This directory is in the load path.
|
||||||
|
|
||||||
|
public
|
||||||
|
The directory available for the web server. Contains subdirectories for images, stylesheets,
|
||||||
|
and javascripts. Also contains the dispatchers and the default HTML files. This should be
|
||||||
|
set as the DOCUMENT_ROOT of your web server.
|
||||||
|
|
||||||
|
script
|
||||||
|
Helper scripts for automation and generation.
|
||||||
|
|
||||||
|
test
|
||||||
|
Unit and functional tests along with fixtures. When using the script/generate scripts, template
|
||||||
|
test files will be generated for you and placed in this directory.
|
||||||
|
|
||||||
|
vendor
|
||||||
|
External libraries that the application depends on. Also includes the plugins subdirectory.
|
||||||
|
If the app has frozen rails, those gems also go here, under vendor/rails/.
|
||||||
|
This directory is in the load path.
|
|
@ -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'
|
|
@ -0,0 +1,10 @@
|
||||||
|
# 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
|
||||||
|
#helper :all # include all helpers, all the time
|
||||||
|
protect_from_forgery # See ActionController::RequestForgeryProtection for details
|
||||||
|
|
||||||
|
# Scrub sensitive parameters from your log
|
||||||
|
# filter_parameter_logging :password
|
||||||
|
end
|
|
@ -0,0 +1,85 @@
|
||||||
|
class ProjectsController < ApplicationController
|
||||||
|
# GET /projects
|
||||||
|
# GET /projects.xml
|
||||||
|
def index
|
||||||
|
@projects = Project.all
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
|
format.html # index.html.erb
|
||||||
|
format.xml { render :xml => @projects }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET /projects/1
|
||||||
|
# GET /projects/1.xml
|
||||||
|
def show
|
||||||
|
@project = Project.find(params[:id])
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
|
format.html # show.html.erb
|
||||||
|
format.xml { render :xml => @project }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET /projects/new
|
||||||
|
# GET /projects/new.xml
|
||||||
|
def new
|
||||||
|
@project = Project.new
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
|
format.html # new.html.erb
|
||||||
|
format.xml { render :xml => @project }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET /projects/1/edit
|
||||||
|
def edit
|
||||||
|
@project = Project.find(params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
# POST /projects
|
||||||
|
# POST /projects.xml
|
||||||
|
def create
|
||||||
|
@project = Project.new(params[:project])
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
|
if @project.save
|
||||||
|
flash[:notice] = 'Project was successfully created.'
|
||||||
|
format.html { redirect_to(@project) }
|
||||||
|
format.xml { render :xml => @project, :status => :created, :location => @project }
|
||||||
|
else
|
||||||
|
format.html { render :action => "new" }
|
||||||
|
format.xml { render :xml => @project.errors, :status => :unprocessable_entity }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# PUT /projects/1
|
||||||
|
# PUT /projects/1.xml
|
||||||
|
def update
|
||||||
|
@project = Project.find(params[:id])
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
|
if @project.update_attributes(params[:project])
|
||||||
|
flash[:notice] = 'Project was successfully updated.'
|
||||||
|
format.html { redirect_to(@project) }
|
||||||
|
format.xml { head :ok }
|
||||||
|
else
|
||||||
|
format.html { render :action => "edit" }
|
||||||
|
format.xml { render :xml => @project.errors, :status => :unprocessable_entity }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# DELETE /projects/1
|
||||||
|
# DELETE /projects/1.xml
|
||||||
|
def destroy
|
||||||
|
@project = Project.find(params[:id])
|
||||||
|
@project.destroy
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
|
format.html { redirect_to(projects_url) }
|
||||||
|
format.xml { head :ok }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,100 @@
|
||||||
|
class TasksController < ApplicationController
|
||||||
|
|
||||||
|
before_filter :load_project
|
||||||
|
|
||||||
|
def load_project
|
||||||
|
@project = Project.find(params[:project_id])
|
||||||
|
|
||||||
|
rescue ActiveRecord::RecordNotFound
|
||||||
|
flash[:error] = "There was an error finding the parent project"
|
||||||
|
redirect_to projects_path
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# GET /tasks
|
||||||
|
# GET /tasks.xml
|
||||||
|
def index
|
||||||
|
@tasks = Task.all
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
|
format.html # index.html.erb
|
||||||
|
format.xml { render :xml => @tasks }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET /tasks/1
|
||||||
|
# GET /tasks/1.xml
|
||||||
|
def show
|
||||||
|
@task = Task.find(params[:id])
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
|
format.html # show.html.erb
|
||||||
|
format.xml { render :xml => @task }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET /tasks/new
|
||||||
|
# GET /tasks/new.xml
|
||||||
|
def new
|
||||||
|
@task = Task.new
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
|
format.html # new.html.erb
|
||||||
|
format.xml { render :xml => @task }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET /tasks/1/edit
|
||||||
|
def edit
|
||||||
|
@task = Task.find(params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
# POST /tasks
|
||||||
|
# POST /tasks.xml
|
||||||
|
def create
|
||||||
|
params[:task][:project] = @project.id
|
||||||
|
@task = Task.new(params[:task])
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
|
if @task.save
|
||||||
|
flash[:success] = 'Task was successfully created.'
|
||||||
|
format.html { redirect_to project_task_path(@project, @task) }
|
||||||
|
format.xml { render :xml => @task, :status => :created, :location => @task }
|
||||||
|
else
|
||||||
|
format.html { render :action => "new" }
|
||||||
|
format.xml { render :xml => @task.errors, :status => :unprocessable_entity }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# PUT /tasks/1
|
||||||
|
# PUT /tasks/1.xml
|
||||||
|
def update
|
||||||
|
params[:task][:project] = @project
|
||||||
|
@task = Task.find(params[:id])
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
|
if @task.update_attributes(params[:task])
|
||||||
|
flash[:success] = 'Task was successfully updated.'
|
||||||
|
format.html { redirect_to project_task_path(@project, @task) }
|
||||||
|
format.xml { head :ok }
|
||||||
|
else
|
||||||
|
format.html { render :action => "edit" }
|
||||||
|
format.xml { render :xml => @task.errors, :status => :unprocessable_entity }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# DELETE /tasks/1
|
||||||
|
# DELETE /tasks/1.xml
|
||||||
|
def destroy
|
||||||
|
@task = Task.find(params[:id])
|
||||||
|
@task.destroy
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
|
format.html { redirect_to(tasks_url) }
|
||||||
|
format.xml { head :ok }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,10 @@
|
||||||
|
# Methods added to this helper will be available to all templates in the application.
|
||||||
|
module ApplicationHelper
|
||||||
|
|
||||||
|
def csrf_meta_tag
|
||||||
|
out = ''
|
||||||
|
out << tag(:meta, :name => 'csrf-token', :content => form_authenticity_token)
|
||||||
|
out << tag(:meta, :name => 'csrf-param', :content => 'authenticity_token')
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,2 @@
|
||||||
|
module ProjectsHelper
|
||||||
|
end
|
|
@ -0,0 +1,2 @@
|
||||||
|
module TasksHelper
|
||||||
|
end
|
|
@ -0,0 +1,4 @@
|
||||||
|
class Project < ActiveRecord::Base
|
||||||
|
has_many :tasks
|
||||||
|
validates_presence_of :name
|
||||||
|
end
|
|
@ -0,0 +1,7 @@
|
||||||
|
class Task < ActiveRecord::Base
|
||||||
|
belongs_to :project
|
||||||
|
has_many :tasks, :foreign_key => :parent
|
||||||
|
|
||||||
|
validates_presence_of :name, :description, :project_id
|
||||||
|
validates_associated :project
|
||||||
|
end
|
|
@ -0,0 +1,19 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<%= csrf_meta_tag %>
|
||||||
|
<%= javascript_include_tag "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js",
|
||||||
|
"http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js",
|
||||||
|
:defaults %>
|
||||||
|
<%= stylesheet_link_tag 'scaffold', 'style' %>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<% flash.each_key do |flash_key| %>
|
||||||
|
<div id='flash_<%= flash_key.to_s %>'>
|
||||||
|
<%= flash[flash_key] %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<%= yield %>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,16 @@
|
||||||
|
<h1>Editing project</h1>
|
||||||
|
|
||||||
|
<% form_for(@project) do |f| %>
|
||||||
|
<%= f.error_messages %>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<%= f.label :name %><br />
|
||||||
|
<%= f.text_field :name %>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<%= f.submit 'Update' %>
|
||||||
|
</p>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<%= link_to 'Show', @project %> |
|
||||||
|
<%= link_to 'Back', projects_path %>
|
|
@ -0,0 +1,20 @@
|
||||||
|
<h1>Listing projects</h1>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<% @projects.each do |project| %>
|
||||||
|
<tr>
|
||||||
|
<td><%=h project.name %></td>
|
||||||
|
<td><%= link_to 'Show', project %></td>
|
||||||
|
<td><%= link_to 'Edit', edit_project_path(project) %></td>
|
||||||
|
<td><%= link_to 'Destroy', project, :confirm => 'Are you sure?', :method => :delete %></td>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<%= link_to 'New project', new_project_path %>
|
|
@ -0,0 +1,15 @@
|
||||||
|
<h1>New project</h1>
|
||||||
|
|
||||||
|
<% form_for(@project) do |f| %>
|
||||||
|
<%= f.error_messages %>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<%= f.label :name %><br />
|
||||||
|
<%= f.text_field :name %>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<%= f.submit 'Create' %>
|
||||||
|
</p>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<%= link_to 'Back', projects_path %>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<p>
|
||||||
|
<b>Name:</b>
|
||||||
|
<%=h @project.name %>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<%= link_to 'Edit', edit_project_path(@project) %> |
|
||||||
|
<%= link_to 'Back', projects_path %>
|
|
@ -0,0 +1,28 @@
|
||||||
|
<h1>Editing task</h1>
|
||||||
|
|
||||||
|
<% form_for(@task, :url => project_task_path(@project, @task)) do |f| %>
|
||||||
|
<%= f.error_messages %>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<%= f.label :name %><br />
|
||||||
|
<%= f.text_field :name %>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<%= f.label :project %><br />
|
||||||
|
<%= f.select :project, Project.all.map {|p| [p.name, p.id]} %>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<%= f.label :description %><br />
|
||||||
|
<%= f.text_area :description %>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<%= f.label :parent %><br />
|
||||||
|
<%= f.text_field :parent %>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<%= f.submit 'Update' %>
|
||||||
|
</p>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<%= link_to 'show', project_task_path(@project, @task) %> |
|
||||||
|
<%= link_to 'Back', project_tasks_path(@project) %>
|
|
@ -0,0 +1,26 @@
|
||||||
|
<h1>Listing tasks</h1>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Project</th>
|
||||||
|
<th>Description</th>
|
||||||
|
<th>Parent</th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<% @tasks.each do |task| %>
|
||||||
|
<tr>
|
||||||
|
<td><%=h task.name %></td>
|
||||||
|
<td><%= link_to h(task.project.name), project_path(task.project) %></td>
|
||||||
|
<td><%=h task.description %></td>
|
||||||
|
<td><%=h task.parent %></td>
|
||||||
|
<td><%= link_to 'Show', project_task_path(@project, task) %></td>
|
||||||
|
<td><%= link_to 'Edit', edit_project_task_path(@project, task) %></td>
|
||||||
|
<td><%= link_to 'Destroy', project_task_path(@project, task), :confirm => 'Are you sure?', :method => :delete %></td>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<%= link_to 'New task', new_project_task_path(@project) %>
|
|
@ -0,0 +1,23 @@
|
||||||
|
<h1>New task</h1>
|
||||||
|
|
||||||
|
<% form_for(@task, :url => project_tasks_path(@project)) do |f| %>
|
||||||
|
<%= f.error_messages %>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<%= f.label :name %><br />
|
||||||
|
<%= f.text_field :name %>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<%= f.label :description %><br />
|
||||||
|
<%= f.text_area :description %>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<%= f.label :parent %><br />
|
||||||
|
<%= f.text_field :parent %>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<%= f.submit 'Create' %>
|
||||||
|
</p>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<%= link_to 'Back', project_tasks_path(@project) %>
|
|
@ -0,0 +1,23 @@
|
||||||
|
<p>
|
||||||
|
<b>Name:</b>
|
||||||
|
<%=h @task.name %>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<b>Project:</b>
|
||||||
|
<%=h @task.project.name %>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<b>Description:</b>
|
||||||
|
<%=h @task.description %>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<b>Parent:</b>
|
||||||
|
<%=h @task.parent %>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<%= link_to 'Edit', edit_project_task_path(@project, @task) %> |
|
||||||
|
<%= link_to 'Back', project_tasks_path(@project) %>
|
|
@ -0,0 +1,110 @@
|
||||||
|
# Don't change this file!
|
||||||
|
# Configure your app in config/environment.rb and config/environments/*.rb
|
||||||
|
|
||||||
|
RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT)
|
||||||
|
|
||||||
|
module Rails
|
||||||
|
class << self
|
||||||
|
def boot!
|
||||||
|
unless booted?
|
||||||
|
preinitialize
|
||||||
|
pick_boot.run
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def booted?
|
||||||
|
defined? Rails::Initializer
|
||||||
|
end
|
||||||
|
|
||||||
|
def pick_boot
|
||||||
|
(vendor_rails? ? VendorBoot : GemBoot).new
|
||||||
|
end
|
||||||
|
|
||||||
|
def vendor_rails?
|
||||||
|
File.exist?("#{RAILS_ROOT}/vendor/rails")
|
||||||
|
end
|
||||||
|
|
||||||
|
def preinitialize
|
||||||
|
load(preinitializer_path) if File.exist?(preinitializer_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
def preinitializer_path
|
||||||
|
"#{RAILS_ROOT}/config/preinitializer.rb"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Boot
|
||||||
|
def run
|
||||||
|
load_initializer
|
||||||
|
Rails::Initializer.run(:set_load_path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class VendorBoot < Boot
|
||||||
|
def load_initializer
|
||||||
|
require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer"
|
||||||
|
Rails::Initializer.run(:install_gem_spec_stubs)
|
||||||
|
Rails::GemDependency.add_frozen_gem_path
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class GemBoot < Boot
|
||||||
|
def load_initializer
|
||||||
|
self.class.load_rubygems
|
||||||
|
load_rails_gem
|
||||||
|
require 'initializer'
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_rails_gem
|
||||||
|
if version = self.class.gem_version
|
||||||
|
gem 'rails', version
|
||||||
|
else
|
||||||
|
gem 'rails'
|
||||||
|
end
|
||||||
|
rescue Gem::LoadError => load_error
|
||||||
|
$stderr.puts %(Missing the Rails #{version} gem. Please `gem install -v=#{version} rails`, update your RAILS_GEM_VERSION setting in config/environment.rb for the Rails version you do have installed, or comment out RAILS_GEM_VERSION to use the latest version installed.)
|
||||||
|
exit 1
|
||||||
|
end
|
||||||
|
|
||||||
|
class << self
|
||||||
|
def rubygems_version
|
||||||
|
Gem::RubyGemsVersion rescue nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def gem_version
|
||||||
|
if defined? RAILS_GEM_VERSION
|
||||||
|
RAILS_GEM_VERSION
|
||||||
|
elsif ENV.include?('RAILS_GEM_VERSION')
|
||||||
|
ENV['RAILS_GEM_VERSION']
|
||||||
|
else
|
||||||
|
parse_gem_version(read_environment_rb)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_rubygems
|
||||||
|
min_version = '1.3.2'
|
||||||
|
require 'rubygems'
|
||||||
|
unless rubygems_version >= min_version
|
||||||
|
$stderr.puts %Q(Rails requires RubyGems >= #{min_version} (you have #{rubygems_version}). Please `gem update --system` and try again.)
|
||||||
|
exit 1
|
||||||
|
end
|
||||||
|
|
||||||
|
rescue LoadError
|
||||||
|
$stderr.puts %Q(Rails requires RubyGems >= #{min_version}. Please install RubyGems and try again: http://rubygems.rubyforge.org)
|
||||||
|
exit 1
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_gem_version(text)
|
||||||
|
$1 if text =~ /^[^#]*RAILS_GEM_VERSION\s*=\s*["']([!~<>=]*\s*[\d.]+)["']/
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def read_environment_rb
|
||||||
|
File.read("#{RAILS_ROOT}/config/environment.rb")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# All that for this:
|
||||||
|
Rails.boot!
|
|
@ -0,0 +1,22 @@
|
||||||
|
# SQLite version 3.x
|
||||||
|
# gem install sqlite3-ruby (not necessary on OS X Leopard)
|
||||||
|
development:
|
||||||
|
adapter: sqlite3
|
||||||
|
database: db/development.sqlite3
|
||||||
|
pool: 5
|
||||||
|
timeout: 5000
|
||||||
|
|
||||||
|
# Warning: The database defined as "test" will be erased and
|
||||||
|
# re-generated from your development database when you run "rake".
|
||||||
|
# Do not set this db to the same as development or production.
|
||||||
|
test:
|
||||||
|
adapter: sqlite3
|
||||||
|
database: db/test.sqlite3
|
||||||
|
pool: 5
|
||||||
|
timeout: 5000
|
||||||
|
|
||||||
|
production:
|
||||||
|
adapter: sqlite3
|
||||||
|
database: db/production.sqlite3
|
||||||
|
pool: 5
|
||||||
|
timeout: 5000
|
|
@ -0,0 +1,41 @@
|
||||||
|
# Be sure to restart your server when you modify this file
|
||||||
|
|
||||||
|
# Specifies gem version of Rails to use when vendor/rails is not present
|
||||||
|
RAILS_GEM_VERSION = '2.3.5' unless defined? RAILS_GEM_VERSION
|
||||||
|
|
||||||
|
# Bootstrap the Rails environment, frameworks, and default configuration
|
||||||
|
require File.join(File.dirname(__FILE__), 'boot')
|
||||||
|
|
||||||
|
Rails::Initializer.run do |config|
|
||||||
|
# Settings in config/environments/* take precedence over those specified here.
|
||||||
|
# Application configuration should go into files in config/initializers
|
||||||
|
# -- all .rb files in that directory are automatically loaded.
|
||||||
|
|
||||||
|
# Add additional load paths for your own custom dirs
|
||||||
|
# config.load_paths += %W( #{RAILS_ROOT}/extras )
|
||||||
|
|
||||||
|
# Specify gems that this application depends on and have them installed with rake gems:install
|
||||||
|
# config.gem "bj"
|
||||||
|
# config.gem "hpricot", :version => '0.6', :source => "http://code.whytheluckystiff.net"
|
||||||
|
# config.gem "sqlite3-ruby", :lib => "sqlite3"
|
||||||
|
# config.gem "aws-s3", :lib => "aws/s3"
|
||||||
|
|
||||||
|
# Only load the plugins named here, in the order given (default is alphabetical).
|
||||||
|
# :all can be used as a placeholder for all plugins not explicitly named
|
||||||
|
# config.plugins = [ :exception_notification, :ssl_requirement, :all ]
|
||||||
|
|
||||||
|
# Skip frameworks you're not going to use. To use Rails without a database,
|
||||||
|
# you must remove the Active Record framework.
|
||||||
|
# config.frameworks -= [ :active_record, :active_resource, :action_mailer ]
|
||||||
|
|
||||||
|
# Activate observers that should always be running
|
||||||
|
# config.active_record.observers = :cacher, :garbage_collector, :forum_observer
|
||||||
|
|
||||||
|
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
|
||||||
|
# Run "rake -D time" for a list of tasks for finding time zone names.
|
||||||
|
config.time_zone = 'UTC'
|
||||||
|
|
||||||
|
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
|
||||||
|
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}')]
|
||||||
|
# config.i18n.default_locale = :de
|
||||||
|
end
|
|
@ -0,0 +1,17 @@
|
||||||
|
# Settings specified here will take precedence over those in config/environment.rb
|
||||||
|
|
||||||
|
# In the development environment your application's code is reloaded on
|
||||||
|
# every request. This slows down response time but is perfect for development
|
||||||
|
# since you don't have to restart the webserver when you make code changes.
|
||||||
|
config.cache_classes = false
|
||||||
|
|
||||||
|
# Log error messages when you accidentally call methods on nil.
|
||||||
|
config.whiny_nils = true
|
||||||
|
|
||||||
|
# Show full error reports and disable caching
|
||||||
|
config.action_controller.consider_all_requests_local = true
|
||||||
|
config.action_view.debug_rjs = true
|
||||||
|
config.action_controller.perform_caching = false
|
||||||
|
|
||||||
|
# Don't care if the mailer can't send
|
||||||
|
config.action_mailer.raise_delivery_errors = false
|
|
@ -0,0 +1,28 @@
|
||||||
|
# Settings specified here will take precedence over those in config/environment.rb
|
||||||
|
|
||||||
|
# The production environment is meant for finished, "live" apps.
|
||||||
|
# Code is not reloaded between requests
|
||||||
|
config.cache_classes = true
|
||||||
|
|
||||||
|
# Full error reports are disabled and caching is turned on
|
||||||
|
config.action_controller.consider_all_requests_local = false
|
||||||
|
config.action_controller.perform_caching = true
|
||||||
|
config.action_view.cache_template_loading = true
|
||||||
|
|
||||||
|
# See everything in the log (default is :info)
|
||||||
|
# config.log_level = :debug
|
||||||
|
|
||||||
|
# Use a different logger for distributed setups
|
||||||
|
# config.logger = SyslogLogger.new
|
||||||
|
|
||||||
|
# Use a different cache store in production
|
||||||
|
# config.cache_store = :mem_cache_store
|
||||||
|
|
||||||
|
# Enable serving of images, stylesheets, and javascripts from an asset server
|
||||||
|
# config.action_controller.asset_host = "http://assets.example.com"
|
||||||
|
|
||||||
|
# Disable delivery errors, bad email addresses will be ignored
|
||||||
|
# config.action_mailer.raise_delivery_errors = false
|
||||||
|
|
||||||
|
# Enable threaded mode
|
||||||
|
# config.threadsafe!
|
|
@ -0,0 +1,28 @@
|
||||||
|
# Settings specified here will take precedence over those in config/environment.rb
|
||||||
|
|
||||||
|
# The test environment is used exclusively to run your application's
|
||||||
|
# test suite. You never need to work with it otherwise. Remember that
|
||||||
|
# your test database is "scratch space" for the test suite and is wiped
|
||||||
|
# and recreated between test runs. Don't rely on the data there!
|
||||||
|
config.cache_classes = true
|
||||||
|
|
||||||
|
# Log error messages when you accidentally call methods on nil.
|
||||||
|
config.whiny_nils = true
|
||||||
|
|
||||||
|
# Show full error reports and disable caching
|
||||||
|
config.action_controller.consider_all_requests_local = true
|
||||||
|
config.action_controller.perform_caching = false
|
||||||
|
config.action_view.cache_template_loading = true
|
||||||
|
|
||||||
|
# Disable request forgery protection in test environment
|
||||||
|
config.action_controller.allow_forgery_protection = false
|
||||||
|
|
||||||
|
# Tell Action Mailer not to deliver emails to the real world.
|
||||||
|
# The :test delivery method accumulates sent emails in the
|
||||||
|
# ActionMailer::Base.deliveries array.
|
||||||
|
config.action_mailer.delivery_method = :test
|
||||||
|
|
||||||
|
# Use SQL instead of Active Record's schema dumper when creating the test database.
|
||||||
|
# This is necessary if your schema can't be completely dumped by the schema dumper,
|
||||||
|
# like if you have constraints or database-specific column types
|
||||||
|
# config.active_record.schema_format = :sql
|
|
@ -0,0 +1,7 @@
|
||||||
|
# Be sure to restart your server when you modify this file.
|
||||||
|
|
||||||
|
# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
|
||||||
|
# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
|
||||||
|
|
||||||
|
# You can also remove all the silencers if you're trying do debug a problem that might steem from framework code.
|
||||||
|
# Rails.backtrace_cleaner.remove_silencers!
|
|
@ -0,0 +1,10 @@
|
||||||
|
# Be sure to restart your server when you modify this file.
|
||||||
|
|
||||||
|
# Add new inflection rules using the following format
|
||||||
|
# (all these examples are active by default):
|
||||||
|
# ActiveSupport::Inflector.inflections do |inflect|
|
||||||
|
# inflect.plural /^(ox)$/i, '\1en'
|
||||||
|
# inflect.singular /^(ox)en/i, '\1'
|
||||||
|
# inflect.irregular 'person', 'people'
|
||||||
|
# inflect.uncountable %w( fish sheep )
|
||||||
|
# end
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Be sure to restart your server when you modify this file.
|
||||||
|
|
||||||
|
# Add new mime types for use in respond_to blocks:
|
||||||
|
# Mime::Type.register "text/richtext", :rtf
|
||||||
|
# Mime::Type.register_alias "text/html", :iphone
|
|
@ -0,0 +1,21 @@
|
||||||
|
# Be sure to restart your server when you modify this file.
|
||||||
|
|
||||||
|
# These settings change the behavior of Rails 2 apps and will be defaults
|
||||||
|
# for Rails 3. You can remove this initializer when Rails 3 is released.
|
||||||
|
|
||||||
|
if defined?(ActiveRecord)
|
||||||
|
# Include Active Record class name as root for JSON serialized output.
|
||||||
|
ActiveRecord::Base.include_root_in_json = true
|
||||||
|
|
||||||
|
# Store the full class name (including module namespace) in STI type column.
|
||||||
|
ActiveRecord::Base.store_full_sti_class = true
|
||||||
|
end
|
||||||
|
|
||||||
|
ActionController::Routing.generate_best_match = false
|
||||||
|
|
||||||
|
# Use ISO 8601 format for JSON serialized times and dates.
|
||||||
|
ActiveSupport.use_standard_json_time_format = true
|
||||||
|
|
||||||
|
# Don't escape HTML entities in JSON, leave that for the #json_escape helper.
|
||||||
|
# if you're including raw json in an HTML page.
|
||||||
|
ActiveSupport.escape_html_entities_in_json = false
|
|
@ -0,0 +1,15 @@
|
||||||
|
# Be sure to restart your server when you modify this file.
|
||||||
|
|
||||||
|
# Your secret key for verifying cookie session data integrity.
|
||||||
|
# If you change this key, all old sessions will become invalid!
|
||||||
|
# Make sure the secret is at least 30 characters and all random,
|
||||||
|
# no regular words or you'll be exposed to dictionary attacks.
|
||||||
|
ActionController::Base.session = {
|
||||||
|
:key => '_collab_session',
|
||||||
|
:secret => 'bae3c8270cc7ea60f86949290218ac4912db86f6f915babc14216e4f3e206a28854e72aae7ae28c5d36e74d1554e4159bfb94ec2669d924ad7192b85da6956cc'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Use the database for sessions instead of the cookie-based default,
|
||||||
|
# which shouldn't be used to store highly confidential information
|
||||||
|
# (create the session table with "rake db:sessions:create")
|
||||||
|
# ActionController::Base.session_store = :active_record_store
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Sample localization file for English. Add more files in this directory for other locales.
|
||||||
|
# See http://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.
|
||||||
|
|
||||||
|
en:
|
||||||
|
hello: "Hello world"
|
|
@ -0,0 +1,49 @@
|
||||||
|
ActionController::Routing::Routes.draw do |map|
|
||||||
|
# The priority is based upon order of creation: first created -> highest priority.
|
||||||
|
|
||||||
|
# Sample of regular route:
|
||||||
|
# map.connect 'products/:id', :controller => 'catalog', :action => 'view'
|
||||||
|
# Keep in mind you can assign values other than :controller and :action
|
||||||
|
|
||||||
|
# Sample of named route:
|
||||||
|
# map.purchase 'products/:id/purchase', :controller => 'catalog', :action => 'purchase'
|
||||||
|
# This route can be invoked with purchase_url(:id => product.id)
|
||||||
|
|
||||||
|
# Sample resource route (maps HTTP verbs to controller actions automatically):
|
||||||
|
# map.resources :products
|
||||||
|
|
||||||
|
# Sample resource route with options:
|
||||||
|
# map.resources :products, :member => { :short => :get, :toggle => :post }, :collection => { :sold => :get }
|
||||||
|
|
||||||
|
# Sample resource route with sub-resources:
|
||||||
|
# map.resources :products, :has_many => [ :comments, :sales ], :has_one => :seller
|
||||||
|
|
||||||
|
# Sample resource route with more complex sub-resources
|
||||||
|
# map.resources :products do |products|
|
||||||
|
# products.resources :comments
|
||||||
|
# products.resources :sales, :collection => { :recent => :get }
|
||||||
|
# end
|
||||||
|
|
||||||
|
# Sample resource route within a namespace:
|
||||||
|
# map.namespace :admin do |admin|
|
||||||
|
# # Directs /admin/products/* to Admin::ProductsController (app/controllers/admin/products_controller.rb)
|
||||||
|
# admin.resources :products
|
||||||
|
# end
|
||||||
|
|
||||||
|
# You can have the root of your site routed with map.root -- just remember to delete public/index.html.
|
||||||
|
# map.root :controller => "welcome"
|
||||||
|
|
||||||
|
# See how all your routes lay out with "rake routes"
|
||||||
|
|
||||||
|
map.resources :projects do |projects|
|
||||||
|
projects.resources :tasks
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# Install the default routes as the lowest priority.
|
||||||
|
# Note: These default routes make all actions in every controller accessible via GET requests. You should
|
||||||
|
# consider removing or commenting them out if you're using named routes and resources.
|
||||||
|
#map.connect ':controller/:action/:id'
|
||||||
|
#map.connect ':controller/:action/:id.:format'
|
||||||
|
map.root :controller => :projects, :action =>:index
|
||||||
|
end
|
Binary file not shown.
|
@ -0,0 +1,13 @@
|
||||||
|
class CreateProjects < ActiveRecord::Migration
|
||||||
|
def self.up
|
||||||
|
create_table :projects do |t|
|
||||||
|
t.string :name
|
||||||
|
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.down
|
||||||
|
drop_table :projects
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,16 @@
|
||||||
|
class CreateTasks < ActiveRecord::Migration
|
||||||
|
def self.up
|
||||||
|
create_table :tasks do |t|
|
||||||
|
t.string :name
|
||||||
|
t.belongs_to :project
|
||||||
|
t.text :description
|
||||||
|
t.integer :parent
|
||||||
|
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.down
|
||||||
|
drop_table :tasks
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,29 @@
|
||||||
|
# This file is auto-generated from the current state of the database. Instead of editing this file,
|
||||||
|
# please use the migrations feature of Active Record to incrementally modify your database, and
|
||||||
|
# then regenerate this schema definition.
|
||||||
|
#
|
||||||
|
# Note that this schema.rb definition is the authoritative source for your database schema. If you need
|
||||||
|
# to create the application database on another system, you should be using db:schema:load, not running
|
||||||
|
# all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations
|
||||||
|
# you'll amass, the slower it'll run and the greater likelihood for issues).
|
||||||
|
#
|
||||||
|
# It's strongly recommended to check this file into your version control system.
|
||||||
|
|
||||||
|
ActiveRecord::Schema.define(:version => 20100304040201) do
|
||||||
|
|
||||||
|
create_table "projects", :force => true do |t|
|
||||||
|
t.string "name"
|
||||||
|
t.datetime "created_at"
|
||||||
|
t.datetime "updated_at"
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table "tasks", :force => true do |t|
|
||||||
|
t.string "name"
|
||||||
|
t.integer "project_id"
|
||||||
|
t.text "description"
|
||||||
|
t.integer "parent"
|
||||||
|
t.datetime "created_at"
|
||||||
|
t.datetime "updated_at"
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,7 @@
|
||||||
|
# This file should contain all the record creation needed to seed the database with its default values.
|
||||||
|
# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup).
|
||||||
|
#
|
||||||
|
# Examples:
|
||||||
|
#
|
||||||
|
# cities = City.create([{ :name => 'Chicago' }, { :name => 'Copenhagen' }])
|
||||||
|
# Major.create(:name => 'Daley', :city => cities.first)
|
|
@ -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 doc:app" to generate API documentation for your models, controllers, helpers, and libraries.
|
File diff suppressed because it is too large
Load Diff
|
@ -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>
|
|
@ -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 change you wanted was rejected (422)</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/422.html -->
|
||||||
|
<div class="dialog">
|
||||||
|
<h1>The change you wanted was rejected.</h1>
|
||||||
|
<p>Maybe you tried to change something you didn't have access to.</p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -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 (500)</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>
|
Binary file not shown.
After Width: | Height: | Size: 6.5 KiB |
|
@ -0,0 +1,2 @@
|
||||||
|
// Place your application-specific JavaScript functions and classes here
|
||||||
|
// This file is automatically included by javascript_include_tag :defaults
|
|
@ -0,0 +1 @@
|
||||||
|
(function($){$().ajaxSend(function(a,xhr,s){xhr.setRequestHeader("Accept","text/javascript, text/html, application/xml, text/xml, */*")})})(jQuery);(function($){$.fn.reset=function(){return this.each(function(){if(typeof this.reset=="function"||(typeof this.reset=="object"&&!this.reset.nodeType)){this.reset()}})};$.fn.enable=function(){return this.each(function(){this.disabled=false})};$.fn.disable=function(){return this.each(function(){this.disabled=true})}})(jQuery);(function($){$.extend({fieldEvent:function(el,obs){var field=el[0]||el,e="change";if(field.type=="radio"||field.type=="checkbox"){e="click"}else{if(obs&&field.type=="text"||field.type=="textarea"){e="keyup"}}return e}});$.fn.extend({delayedObserver:function(delay,callback){var el=$(this);if(typeof window.delayedObserverStack=="undefined"){window.delayedObserverStack=[]}if(typeof window.delayedObserverCallback=="undefined"){window.delayedObserverCallback=function(stackPos){observed=window.delayedObserverStack[stackPos];if(observed.timer){clearTimeout(observed.timer)}observed.timer=setTimeout(function(){observed.timer=null;observed.callback(observed.obj,observed.obj.formVal())},observed.delay*1000);observed.oldVal=observed.obj.formVal()}}window.delayedObserverStack.push({obj:el,timer:null,delay:delay,oldVal:el.formVal(),callback:callback});var stackPos=window.delayedObserverStack.length-1;if(el[0].tagName=="FORM"){$(":input",el).each(function(){var field=$(this);field.bind($.fieldEvent(field,delay),function(){observed=window.delayedObserverStack[stackPos];if(observed.obj.formVal()==observed.obj.oldVal){return}else{window.delayedObserverCallback(stackPos)}})})}else{el.bind($.fieldEvent(el,delay),function(){observed=window.delayedObserverStack[stackPos];if(observed.obj.formVal()==observed.obj.oldVal){return}else{window.delayedObserverCallback(stackPos)}})}},formVal:function(){var el=this[0];if(el.tagName=="FORM"){return this.serialize()}if(el.type=="checkbox"||self.type=="radio"){return this.filter("input:checked").val()||""}else{return this.val()}}})})(jQuery);(function($){$.fn.extend({visualEffect:function(o){e=o.replace(/\_(.)/g,function(m,l){return l.toUpperCase()});return eval("$(this)."+e+"()")},appear:function(speed,callback){return this.fadeIn(speed,callback)},blindDown:function(speed,callback){return this.show("blind",{direction:"vertical"},speed,callback)},blindUp:function(speed,callback){return this.hide("blind",{direction:"vertical"},speed,callback)},blindRight:function(speed,callback){return this.show("blind",{direction:"horizontal"},speed,callback)},blindLeft:function(speed,callback){this.hide("blind",{direction:"horizontal"},speed,callback);return this},dropOut:function(speed,callback){return this.hide("drop",{direction:"down"},speed,callback)},dropIn:function(speed,callback){return this.show("drop",{direction:"up"},speed,callback)},fade:function(speed,callback){return this.fadeOut(speed,callback)},fadeToggle:function(speed,callback){return this.animate({opacity:"toggle"},speed,callback)},fold:function(speed,callback){return this.hide("fold",{},speed,callback)},foldOut:function(speed,callback){return this.show("fold",{},speed,callback)},grow:function(speed,callback){return this.show("scale",{},speed,callback)},highlight:function(speed,callback){return this.show("highlight",{},speed,callback)},puff:function(speed,callback){return this.hide("puff",{},speed,callback)},pulsate:function(speed,callback){return this.show("pulsate",{},speed,callback)},shake:function(speed,callback){return this.show("shake",{},speed,callback)},shrink:function(speed,callback){return this.hide("scale",{},speed,callback)},squish:function(speed,callback){return this.hide("scale",{origin:["top","left"]},speed,callback)},slideUp:function(speed,callback){return this.hide("slide",{direction:"up"},speed,callback)},slideDown:function(speed,callback){return this.show("slide",{direction:"up"},speed,callback)},switchOff:function(speed,callback){return this.hide("clip",{},speed,callback)},switchOn:function(speed,callback){return this.show("clip",{},speed,callback)}})})(jQuery);
|
|
@ -0,0 +1,5 @@
|
||||||
|
# See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file
|
||||||
|
#
|
||||||
|
# To ban all spiders from the entire site uncomment the next two lines:
|
||||||
|
# User-Agent: *
|
||||||
|
# Disallow: /
|
|
@ -0,0 +1,54 @@
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
#flash_error {
|
||||||
|
color:red;
|
||||||
|
}
|
||||||
|
|
||||||
|
#flash_notice {
|
||||||
|
color:blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
#flash_success {
|
||||||
|
color:green;
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
#!/usr/bin/env ruby
|
||||||
|
require File.expand_path('../../config/boot', __FILE__)
|
||||||
|
$LOAD_PATH.unshift "#{RAILTIES_PATH}/builtin/rails_info"
|
||||||
|
require 'commands/about'
|
|
@ -0,0 +1,3 @@
|
||||||
|
#!/usr/bin/env ruby
|
||||||
|
require File.expand_path('../../config/boot', __FILE__)
|
||||||
|
require 'commands/console'
|
|
@ -0,0 +1,3 @@
|
||||||
|
#!/usr/bin/env ruby
|
||||||
|
require File.expand_path('../../config/boot', __FILE__)
|
||||||
|
require 'commands/dbconsole'
|
|
@ -0,0 +1,3 @@
|
||||||
|
#!/usr/bin/env ruby
|
||||||
|
require File.expand_path('../../config/boot', __FILE__)
|
||||||
|
require 'commands/destroy'
|
|
@ -0,0 +1,3 @@
|
||||||
|
#!/usr/bin/env ruby
|
||||||
|
require File.expand_path('../../config/boot', __FILE__)
|
||||||
|
require 'commands/generate'
|
|
@ -0,0 +1,3 @@
|
||||||
|
#!/usr/bin/env ruby
|
||||||
|
require File.expand_path('../../../config/boot', __FILE__)
|
||||||
|
require 'commands/performance/benchmarker'
|
|
@ -0,0 +1,3 @@
|
||||||
|
#!/usr/bin/env ruby
|
||||||
|
require File.expand_path('../../../config/boot', __FILE__)
|
||||||
|
require 'commands/performance/profiler'
|
|
@ -0,0 +1,3 @@
|
||||||
|
#!/usr/bin/env ruby
|
||||||
|
require File.expand_path('../../config/boot', __FILE__)
|
||||||
|
require 'commands/plugin'
|
|
@ -0,0 +1,3 @@
|
||||||
|
#!/usr/bin/env ruby
|
||||||
|
require File.expand_path('../../config/boot', __FILE__)
|
||||||
|
require 'commands/runner'
|
|
@ -0,0 +1,3 @@
|
||||||
|
#!/usr/bin/env ruby
|
||||||
|
require File.expand_path('../../config/boot', __FILE__)
|
||||||
|
require 'commands/server'
|
|
@ -0,0 +1,7 @@
|
||||||
|
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
|
||||||
|
|
||||||
|
one:
|
||||||
|
name: MyString
|
||||||
|
|
||||||
|
two:
|
||||||
|
name: MyString
|
|
@ -0,0 +1,13 @@
|
||||||
|
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
|
||||||
|
|
||||||
|
one:
|
||||||
|
name: MyString
|
||||||
|
project:
|
||||||
|
description: MyText
|
||||||
|
parent: 1
|
||||||
|
|
||||||
|
two:
|
||||||
|
name: MyString
|
||||||
|
project:
|
||||||
|
description: MyText
|
||||||
|
parent: 1
|
|
@ -0,0 +1,45 @@
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class ProjectsControllerTest < ActionController::TestCase
|
||||||
|
test "should get index" do
|
||||||
|
get :index
|
||||||
|
assert_response :success
|
||||||
|
assert_not_nil assigns(:projects)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "should get new" do
|
||||||
|
get :new
|
||||||
|
assert_response :success
|
||||||
|
end
|
||||||
|
|
||||||
|
test "should create project" do
|
||||||
|
assert_difference('Project.count') do
|
||||||
|
post :create, :project => { }
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_redirected_to project_path(assigns(:project))
|
||||||
|
end
|
||||||
|
|
||||||
|
test "should show project" do
|
||||||
|
get :show, :id => projects(:one).to_param
|
||||||
|
assert_response :success
|
||||||
|
end
|
||||||
|
|
||||||
|
test "should get edit" do
|
||||||
|
get :edit, :id => projects(:one).to_param
|
||||||
|
assert_response :success
|
||||||
|
end
|
||||||
|
|
||||||
|
test "should update project" do
|
||||||
|
put :update, :id => projects(:one).to_param, :project => { }
|
||||||
|
assert_redirected_to project_path(assigns(:project))
|
||||||
|
end
|
||||||
|
|
||||||
|
test "should destroy project" do
|
||||||
|
assert_difference('Project.count', -1) do
|
||||||
|
delete :destroy, :id => projects(:one).to_param
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_redirected_to projects_path
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,45 @@
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class TasksControllerTest < ActionController::TestCase
|
||||||
|
test "should get index" do
|
||||||
|
get :index
|
||||||
|
assert_response :success
|
||||||
|
assert_not_nil assigns(:tasks)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "should get new" do
|
||||||
|
get :new
|
||||||
|
assert_response :success
|
||||||
|
end
|
||||||
|
|
||||||
|
test "should create task" do
|
||||||
|
assert_difference('Task.count') do
|
||||||
|
post :create, :task => { }
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_redirected_to task_path(assigns(:task))
|
||||||
|
end
|
||||||
|
|
||||||
|
test "should show task" do
|
||||||
|
get :show, :id => tasks(:one).to_param
|
||||||
|
assert_response :success
|
||||||
|
end
|
||||||
|
|
||||||
|
test "should get edit" do
|
||||||
|
get :edit, :id => tasks(:one).to_param
|
||||||
|
assert_response :success
|
||||||
|
end
|
||||||
|
|
||||||
|
test "should update task" do
|
||||||
|
put :update, :id => tasks(:one).to_param, :task => { }
|
||||||
|
assert_redirected_to task_path(assigns(:task))
|
||||||
|
end
|
||||||
|
|
||||||
|
test "should destroy task" do
|
||||||
|
assert_difference('Task.count', -1) do
|
||||||
|
delete :destroy, :id => tasks(:one).to_param
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_redirected_to tasks_path
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,9 @@
|
||||||
|
require 'test_helper'
|
||||||
|
require 'performance_test_help'
|
||||||
|
|
||||||
|
# Profiling results for each test method are written to tmp/performance.
|
||||||
|
class BrowsingTest < ActionController::PerformanceTest
|
||||||
|
def test_homepage
|
||||||
|
get '/'
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,38 @@
|
||||||
|
ENV["RAILS_ENV"] = "test"
|
||||||
|
require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
|
||||||
|
require 'test_help'
|
||||||
|
|
||||||
|
class ActiveSupport::TestCase
|
||||||
|
# Transactional fixtures accelerate your tests by wrapping each test method
|
||||||
|
# in a transaction that's rolled back on completion. This ensures that the
|
||||||
|
# test database remains unchanged so your fixtures don't have to be reloaded
|
||||||
|
# between every test method. Fewer database queries means faster tests.
|
||||||
|
#
|
||||||
|
# Read Mike Clark's excellent walkthrough at
|
||||||
|
# http://clarkware.com/cgi/blosxom/2005/10/24#Rails10FastTesting
|
||||||
|
#
|
||||||
|
# Every Active Record database supports transactions except MyISAM tables
|
||||||
|
# in MySQL. Turn off transactional fixtures in this case; however, if you
|
||||||
|
# don't care one way or the other, switching from MyISAM to InnoDB tables
|
||||||
|
# is recommended.
|
||||||
|
#
|
||||||
|
# The only drawback to using transactional fixtures is when you actually
|
||||||
|
# need to test transactions. Since your test is bracketed by a transaction,
|
||||||
|
# any transactions started in your code will be automatically rolled back.
|
||||||
|
self.use_transactional_fixtures = true
|
||||||
|
|
||||||
|
# Instantiated fixtures are slow, but give you @david where otherwise you
|
||||||
|
# would need people(:david). If you don't want to migrate your existing
|
||||||
|
# test cases which use the @david style and don't mind the speed hit (each
|
||||||
|
# instantiated fixtures translates to a database query per test method),
|
||||||
|
# then set this back to true.
|
||||||
|
self.use_instantiated_fixtures = false
|
||||||
|
|
||||||
|
# Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
|
||||||
|
#
|
||||||
|
# Note: You'll currently still have to declare fixtures explicitly in integration tests
|
||||||
|
# -- they do not yet inherit this setting
|
||||||
|
fixtures :all
|
||||||
|
|
||||||
|
# Add more helper methods to be used by all tests here...
|
||||||
|
end
|
|
@ -0,0 +1,4 @@
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class ProjectsHelperTest < ActionView::TestCase
|
||||||
|
end
|
|
@ -0,0 +1,4 @@
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class TasksHelperTest < ActionView::TestCase
|
||||||
|
end
|
|
@ -0,0 +1,8 @@
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class ProjectTest < ActiveSupport::TestCase
|
||||||
|
# Replace this with your real tests.
|
||||||
|
test "the truth" do
|
||||||
|
assert true
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,8 @@
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class TaskTest < ActiveSupport::TestCase
|
||||||
|
# Replace this with your real tests.
|
||||||
|
test "the truth" do
|
||||||
|
assert true
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,35 @@
|
||||||
|
SVN
|
||||||
|
* better approximate scriptaculous effect names
|
||||||
|
* add support for page[:element_id].visual_effect(:effect) as well as page.visual_effect(:effect, :element_id)
|
||||||
|
* added a reset form function to jrails.js (stolen from jquery form)
|
||||||
|
* can now use jquery selectors in all functions
|
||||||
|
* added javascript_function helper to render inline rjs helpers
|
||||||
|
* better support for sortable_element
|
||||||
|
* updated to jquery-ui 1.5.1
|
||||||
|
|
||||||
|
0.4.0 (16 June 2008)
|
||||||
|
* updated to jquery-ui 1.5 & merged js into single file
|
||||||
|
* Added jQuery.noConflict support
|
||||||
|
* support for value/val
|
||||||
|
* additional support for update/delete methods
|
||||||
|
* support for success/failure hash
|
||||||
|
* setRequestHeader now gets called globally
|
||||||
|
* Better support for droppables, sortables
|
||||||
|
* Add support for prototype AJAX callbacks
|
||||||
|
* better support for AJAX form calls
|
||||||
|
|
||||||
|
0.3.0 (22 Feb 2008)
|
||||||
|
* updated to jquery-fx 1.0b and jquery-ui 1.5b
|
||||||
|
* Add text/javascript request header to fix format.js
|
||||||
|
* Added Tasks (thanks ggarside)
|
||||||
|
* Improve visual_effects methods
|
||||||
|
* Fixed some RJS calls
|
||||||
|
* Fixed observer code for ie
|
||||||
|
|
||||||
|
0.2.0 (26 Nov 2007)
|
||||||
|
* Vastly Improved FX
|
||||||
|
* Improved Form Observers
|
||||||
|
* Fixed Rails <= 1.2.6 Compatibility
|
||||||
|
|
||||||
|
0.1.0 (15 Nov 2007)
|
||||||
|
* Initial release
|
|
@ -0,0 +1,21 @@
|
||||||
|
= jRails
|
||||||
|
|
||||||
|
jRails is a drop-in jQuery replacement for the Rails Prototype/script.aculo.us helpers.
|
||||||
|
|
||||||
|
== Resources
|
||||||
|
|
||||||
|
Install
|
||||||
|
|
||||||
|
* .script/plugin install http://ennerchi.googlecode.com/svn/trunk/plugins/jrails
|
||||||
|
|
||||||
|
Project Site
|
||||||
|
|
||||||
|
* http://code.google.com/p/ennerchi/
|
||||||
|
|
||||||
|
Web Site
|
||||||
|
|
||||||
|
* http://www.ennerchi.com/projects/jrails
|
||||||
|
|
||||||
|
Group Site
|
||||||
|
|
||||||
|
* http://groups.google.com/group/jrails
|
|
@ -0,0 +1,6 @@
|
||||||
|
# uncomment to use jQuery.noConflict()
|
||||||
|
#ActionView::Helpers::PrototypeHelper::JQUERY_VAR = 'jQuery'
|
||||||
|
|
||||||
|
ActionView::Helpers::AssetTagHelper::JAVASCRIPT_DEFAULT_SOURCES = ['jrails']
|
||||||
|
ActionView::Helpers::AssetTagHelper::reset_javascript_include_default
|
||||||
|
require 'jrails'
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Install hook code here
|
||||||
|
puts "Copying files..."
|
||||||
|
dir = "javascripts"
|
||||||
|
["jquery-ui.js", "jquery.js", "jrails.js"].each do |js_file|
|
||||||
|
dest_file = File.join(RAILS_ROOT, "public", dir, js_file)
|
||||||
|
src_file = File.join(File.dirname(__FILE__) , dir, js_file)
|
||||||
|
FileUtils.cp_r(src_file, dest_file)
|
||||||
|
end
|
||||||
|
puts "Files copied - Installation complete!"
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,128 @@
|
||||||
|
(function($){$().ajaxSend(function(a,xhr,s){xhr.setRequestHeader("Accept","text/javascript, text/html, application/xml, text/xml, */*")})})(jQuery);(function($){$.fn.reset=function(){return this.each(function(){if(typeof this.reset=="function"||(typeof this.reset=="object"&&!this.reset.nodeType)){this.reset()}})};$.fn.enable=function(){return this.each(function(){this.disabled=false})};$.fn.disable=function(){return this.each(function(){this.disabled=true})}})(jQuery);(function($){$.extend({fieldEvent:function(el,obs){var field=el[0]||el,e="change";if(field.type=="radio"||field.type=="checkbox"){e="click"}else{if(obs&&field.type=="text"||field.type=="textarea"){e="keyup"}}return e}});$.fn.extend({delayedObserver:function(delay,callback){var el=$(this);if(typeof window.delayedObserverStack=="undefined"){window.delayedObserverStack=[]}if(typeof window.delayedObserverCallback=="undefined"){window.delayedObserverCallback=function(stackPos){observed=window.delayedObserverStack[stackPos];if(observed.timer){clearTimeout(observed.timer)}observed.timer=setTimeout(function(){observed.timer=null;observed.callback(observed.obj,observed.obj.formVal())},observed.delay*1000);observed.oldVal=observed.obj.formVal()}}window.delayedObserverStack.push({obj:el,timer:null,delay:delay,oldVal:el.formVal(),callback:callback});var stackPos=window.delayedObserverStack.length-1;if(el[0].tagName=="FORM"){$(":input",el).each(function(){var field=$(this);field.bind($.fieldEvent(field,delay),function(){observed=window.delayedObserverStack[stackPos];if(observed.obj.formVal()==observed.obj.oldVal){return}else{window.delayedObserverCallback(stackPos)}})})}else{el.bind($.fieldEvent(el,delay),function(){observed=window.delayedObserverStack[stackPos];if(observed.obj.formVal()==observed.obj.oldVal){return}else{window.delayedObserverCallback(stackPos)}})}},formVal:function(){var el=this[0];if(el.tagName=="FORM"){return this.serialize()}if(el.type=="checkbox"||self.type=="radio"){return this.filter("input:checked").val()||""}else{return this.val()}}})})(jQuery);(function($){$.fn.extend({visualEffect:function(o){e=o.replace(/\_(.)/g,function(m,l){return l.toUpperCase()});return eval("$(this)."+e+"()")},appear:function(speed,callback){return this.fadeIn(speed,callback)},blindDown:function(speed,callback){return this.show("blind",{direction:"vertical"},speed,callback)},blindUp:function(speed,callback){return this.hide("blind",{direction:"vertical"},speed,callback)},blindRight:function(speed,callback){return this.show("blind",{direction:"horizontal"},speed,callback)},blindLeft:function(speed,callback){this.hide("blind",{direction:"horizontal"},speed,callback);return this},dropOut:function(speed,callback){return this.hide("drop",{direction:"down"},speed,callback)},dropIn:function(speed,callback){return this.show("drop",{direction:"up"},speed,callback)},fade:function(speed,callback){return this.fadeOut(speed,callback)},fadeToggle:function(speed,callback){return this.animate({opacity:"toggle"},speed,callback)},fold:function(speed,callback){return this.hide("fold",{},speed,callback)},foldOut:function(speed,callback){return this.show("fold",{},speed,callback)},grow:function(speed,callback){return this.show("scale",{},speed,callback)},highlight:function(speed,callback){return this.show("highlight",{},speed,callback)},puff:function(speed,callback){return this.hide("puff",{},speed,callback)},pulsate:function(speed,callback){return this.show("pulsate",{},speed,callback)},shake:function(speed,callback){return this.show("shake",{},speed,callback)},shrink:function(speed,callback){return this.hide("scale",{},speed,callback)},squish:function(speed,callback){return this.hide("scale",{origin:["top","left"]},speed,callback)},slideUp:function(speed,callback){return this.hide("slide",{direction:"up"},speed,callback)},slideDown:function(speed,callback){return this.show("slide",{direction:"up"},speed,callback)},switchOff:function(speed,callback){return this.hide("clip",{},speed,callback)},switchOn:function(speed,callback){return this.show("clip",{},speed,callback)}})})(jQuery);
|
||||||
|
|
||||||
|
jQuery(function ($) {
|
||||||
|
var csrf_token = $('meta[name=csrf-token]').attr('content'),
|
||||||
|
csrf_param = $('meta[name=csrf-param]').attr('content');
|
||||||
|
|
||||||
|
$.fn.extend({
|
||||||
|
/**
|
||||||
|
* Triggers a custom event on an element and returns the event result
|
||||||
|
* this is used to get around not being able to ensure callbacks are placed
|
||||||
|
* at the end of the chain.
|
||||||
|
*
|
||||||
|
* TODO: deprecate with jQuery 1.4.2 release, in favor of subscribing to our
|
||||||
|
* own events and placing ourselves at the end of the chain.
|
||||||
|
*/
|
||||||
|
triggerAndReturn: function (name, data) {
|
||||||
|
var event = new $.Event(name);
|
||||||
|
this.trigger(event, data);
|
||||||
|
|
||||||
|
return event.result !== false;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles execution of remote calls firing overridable events along the way
|
||||||
|
*/
|
||||||
|
callRemote: function () {
|
||||||
|
var el = this,
|
||||||
|
data = el.is('form') ? el.serializeArray() : [],
|
||||||
|
method = el.attr('method') || el.attr('data-method') || 'GET',
|
||||||
|
url = el.attr('action') || el.attr('href');
|
||||||
|
|
||||||
|
if (url === undefined) {
|
||||||
|
throw "No URL specified for remote call (action or href must be present).";
|
||||||
|
} else {
|
||||||
|
if (el.triggerAndReturn('ajax:before')) {
|
||||||
|
$.ajax({
|
||||||
|
url: url,
|
||||||
|
data: data,
|
||||||
|
dataType: 'script',
|
||||||
|
type: method.toUpperCase(),
|
||||||
|
beforeSend: function (xhr) {
|
||||||
|
el.trigger('ajax:loading', xhr);
|
||||||
|
},
|
||||||
|
success: function (data, status, xhr) {
|
||||||
|
el.trigger('ajax:success', [data, status, xhr]);
|
||||||
|
},
|
||||||
|
complete: function (xhr) {
|
||||||
|
el.trigger('ajax:complete', xhr);
|
||||||
|
},
|
||||||
|
error: function (xhr, status, error) {
|
||||||
|
el.trigger('ajax:failure', [xhr, status, error]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
el.trigger('ajax:after');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* confirmation handler
|
||||||
|
*/
|
||||||
|
$('a[data-confirm],input[data-confirm]').live('click', function () {
|
||||||
|
var el = $(this);
|
||||||
|
if (el.triggerAndReturn('confirm')) {
|
||||||
|
if (!confirm(el.attr('data-confirm'))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* remote handlers
|
||||||
|
*/
|
||||||
|
$('form[data-remote]').live('submit', function (e) {
|
||||||
|
$(this).callRemote();
|
||||||
|
e.preventDefault();
|
||||||
|
});
|
||||||
|
|
||||||
|
$('a[data-remote],input[data-remote]').live('click', function (e) {
|
||||||
|
$(this).callRemote();
|
||||||
|
e.preventDefault();
|
||||||
|
});
|
||||||
|
|
||||||
|
$('a[data-method]:not([data-remote])').live('click', function (e){
|
||||||
|
var link = $(this),
|
||||||
|
href = link.attr('href'),
|
||||||
|
method = link.attr('data-method'),
|
||||||
|
form = $('<form method="post" action="'+href+'">'),
|
||||||
|
metadata_input = '<input name="_method" value="'+method+'" type="hidden" />';
|
||||||
|
|
||||||
|
if (csrf_param != null && csrf_token != null) {
|
||||||
|
metadata_input += '<input name="'+csrf_param+'" value="'+csrf_token+'" type="hidden" />';
|
||||||
|
}
|
||||||
|
|
||||||
|
form.hide()
|
||||||
|
.append(metadata_input)
|
||||||
|
.appendTo('body');
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
form.submit();
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* disable-with handlers
|
||||||
|
*/
|
||||||
|
var disable_with_input_selector = 'input[data-disable-with]';
|
||||||
|
var disable_with_form_selector = 'form[data-remote]:has(' + disable_with_input_selector + ')';
|
||||||
|
|
||||||
|
$(disable_with_form_selector).live('ajax:before', function () {
|
||||||
|
$(this).find(disable_with_input_selector).each(function () {
|
||||||
|
var input = $(this);
|
||||||
|
input.data('enable-with', input.val())
|
||||||
|
.attr('value', input.attr('data-disable-with'))
|
||||||
|
.attr('disabled', 'disabled');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$(disable_with_form_selector).live('ajax:after', function () {
|
||||||
|
$(this).find(disable_with_input_selector).each(function () {
|
||||||
|
var input = $(this);
|
||||||
|
input.removeAttr('disabled')
|
||||||
|
.val(input.data('enable-with'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,194 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* jRails ajax extras
|
||||||
|
* version 0.1
|
||||||
|
* <aaron@ennerchi.com> | http://www.ennerchi.com
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function($) {
|
||||||
|
$().ajaxSend(function(a, xhr, s){ //Set request headers globally
|
||||||
|
xhr.setRequestHeader("Accept", "text/javascript, text/html, application/xml, text/xml, */*");
|
||||||
|
});
|
||||||
|
})(jQuery);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* jRails form extras
|
||||||
|
* <aaron@ennerchi.com> | http://www.ennerchi.com
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
(function($) {
|
||||||
|
// reset a form
|
||||||
|
$.fn.reset = function() {
|
||||||
|
return this.each(function() {
|
||||||
|
// guard against an input with the name of 'reset'
|
||||||
|
// note that IE reports the reset function as an 'object'
|
||||||
|
if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType))
|
||||||
|
this.reset();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// enable a form element
|
||||||
|
$.fn.enable = function() {
|
||||||
|
return this.each(function() {
|
||||||
|
this.disabled = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// disable a form element
|
||||||
|
$.fn.disable = function() {
|
||||||
|
return this.each(function() {
|
||||||
|
this.disabled = true;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
})(jQuery);
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* jRails form observer plugin
|
||||||
|
* version 0.2
|
||||||
|
* <aaron@ennerchi.com> | http://www.ennerchi.com
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function($) {
|
||||||
|
$.extend({ // Translate field to event
|
||||||
|
fieldEvent: function(el, obs) {
|
||||||
|
var field = el[0] || el, e = 'change';
|
||||||
|
if (field.type == 'radio' || field.type == 'checkbox') e = 'click';
|
||||||
|
else if (obs && field.type == 'text' || field.type == 'textarea') e = 'keyup';
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$.fn.extend({ // Delayed observer for fields and forms
|
||||||
|
delayedObserver: function(delay, callback){
|
||||||
|
var el = $(this);
|
||||||
|
if (typeof window.delayedObserverStack == 'undefined') window.delayedObserverStack = [];
|
||||||
|
if (typeof window.delayedObserverCallback == 'undefined') {
|
||||||
|
window.delayedObserverCallback = function(stackPos) {
|
||||||
|
var observed = window.delayedObserverStack[stackPos];
|
||||||
|
if (observed.timer) clearTimeout(observed.timer);
|
||||||
|
observed.timer = setTimeout(function(){
|
||||||
|
observed.timer = null;
|
||||||
|
observed.callback(observed.obj, observed.obj.formVal());
|
||||||
|
}, observed.delay * 1000);
|
||||||
|
observed.oldVal = observed.obj.formVal();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
window.delayedObserverStack.push({
|
||||||
|
obj: el, timer: null, delay: delay,
|
||||||
|
oldVal: el.formVal(), callback: callback
|
||||||
|
});
|
||||||
|
var stackPos = window.delayedObserverStack.length-1;
|
||||||
|
if (el[0].tagName == 'FORM') {
|
||||||
|
$(':input', el).each(function(){
|
||||||
|
var field = $(this);
|
||||||
|
field.bind($.fieldEvent(field, delay), function(){
|
||||||
|
var observed = window.delayedObserverStack[stackPos];
|
||||||
|
if (observed.obj.formVal() == observed.oldVal) return;
|
||||||
|
else window.delayedObserverCallback(stackPos);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
el.bind($.fieldEvent(el, delay), function(){
|
||||||
|
var observed = window.delayedObserverStack[stackPos];
|
||||||
|
if (observed.obj.formVal() == observed.oldVal) return;
|
||||||
|
else window.delayedObserverCallback(stackPos);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
},
|
||||||
|
formVal: function() { // Gets form values
|
||||||
|
var el = this[0];
|
||||||
|
if(el.tagName == 'FORM') return this.serialize();
|
||||||
|
if(el.type == 'checkbox' || el.type == 'radio') return this.filter('input:checked').val() || '';
|
||||||
|
else return this.val();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})(jQuery);
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* jRails visual effects stubs
|
||||||
|
* version 0.2
|
||||||
|
* <aaron@ennerchi.com> | http://www.ennerchi.com
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function($) {
|
||||||
|
$.fn.extend({
|
||||||
|
visualEffect : function(o) {
|
||||||
|
e = o.replace(/\_(.)/g, function(m, l){return l.toUpperCase()});
|
||||||
|
return eval('$(this).'+e+'()');
|
||||||
|
},
|
||||||
|
appear : function(speed, callback) {
|
||||||
|
return this.fadeIn(speed, callback);
|
||||||
|
},
|
||||||
|
blindDown : function(speed, callback) {
|
||||||
|
return this.show('blind', { direction: 'vertical' }, speed, callback);
|
||||||
|
},
|
||||||
|
blindUp : function(speed, callback) {
|
||||||
|
return this.hide('blind', { direction: 'vertical' }, speed, callback);
|
||||||
|
},
|
||||||
|
blindRight : function(speed, callback) {
|
||||||
|
return this.show('blind', { direction: 'horizontal' }, speed, callback);
|
||||||
|
},
|
||||||
|
blindLeft : function(speed, callback) {
|
||||||
|
this.hide('blind', { direction: 'horizontal' }, speed, callback);
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
dropOut : function(speed, callback) {
|
||||||
|
return this.hide('drop', {direction: 'down' }, speed, callback);
|
||||||
|
},
|
||||||
|
dropIn : function(speed, callback) {
|
||||||
|
return this.show('drop', { direction: 'up' }, speed, callback);
|
||||||
|
},
|
||||||
|
fade : function(speed, callback) {
|
||||||
|
return this.fadeOut(speed, callback);
|
||||||
|
},
|
||||||
|
fadeToggle : function(speed, callback) {
|
||||||
|
return this.animate({opacity: 'toggle'}, speed, callback);
|
||||||
|
},
|
||||||
|
fold : function(speed, callback) {
|
||||||
|
return this.hide('fold', {}, speed, callback);
|
||||||
|
},
|
||||||
|
foldOut : function(speed, callback) {
|
||||||
|
return this.show('fold', {}, speed, callback);
|
||||||
|
},
|
||||||
|
grow : function(speed, callback) {
|
||||||
|
return this.show('scale', {}, speed, callback);
|
||||||
|
},
|
||||||
|
highlight : function(speed, callback) {
|
||||||
|
return this.show('highlight', {}, speed, callback);
|
||||||
|
},
|
||||||
|
puff : function(speed, callback) {
|
||||||
|
return this.hide('puff', {}, speed, callback);
|
||||||
|
},
|
||||||
|
pulsate : function(speed, callback) {
|
||||||
|
return this.show('pulsate', {}, speed, callback);
|
||||||
|
},
|
||||||
|
shake : function(speed, callback) {
|
||||||
|
return this.show('shake', {}, speed, callback);
|
||||||
|
},
|
||||||
|
shrink : function(speed, callback) {
|
||||||
|
return this.hide('scale', {}, speed, callback);
|
||||||
|
},
|
||||||
|
squish : function(speed, callback) {
|
||||||
|
return this.hide('scale', { origin: ['top', 'left'] }, speed, callback);
|
||||||
|
},
|
||||||
|
slideUp : function(speed, callback) {
|
||||||
|
return this.hide('slide', { direction: 'up'}, speed, callback);
|
||||||
|
},
|
||||||
|
slideDown : function(speed, callback) {
|
||||||
|
return this.show('slide', { direction: 'up'}, speed, callback);
|
||||||
|
},
|
||||||
|
switchOff : function(speed, callback) {
|
||||||
|
return this.hide('clip', {}, speed, callback);
|
||||||
|
},
|
||||||
|
switchOn : function(speed, callback) {
|
||||||
|
return this.show('clip', {}, speed, callback);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})(jQuery);
|
|
@ -0,0 +1,406 @@
|
||||||
|
module ActionView
|
||||||
|
module Helpers
|
||||||
|
|
||||||
|
module JavaScriptHelper
|
||||||
|
|
||||||
|
# This function can be used to render rjs inline
|
||||||
|
#
|
||||||
|
# <%= javascript_function do |page|
|
||||||
|
# page.replace_html :list, :partial => 'list', :object => @list
|
||||||
|
# end %>
|
||||||
|
#
|
||||||
|
def javascript_function(*args, &block)
|
||||||
|
html_options = args.extract_options!
|
||||||
|
function = args[0] || ''
|
||||||
|
|
||||||
|
html_options.symbolize_keys!
|
||||||
|
function = update_page(&block) if block_given?
|
||||||
|
javascript_tag(function)
|
||||||
|
end
|
||||||
|
|
||||||
|
def jquery_id(id)
|
||||||
|
id.to_s.count('#.*,>+~:[/ ') == 0 ? "##{id}" : id
|
||||||
|
end
|
||||||
|
|
||||||
|
def jquery_ids(ids)
|
||||||
|
Array(ids).map{|id| jquery_id(id)}.join(',')
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
module PrototypeHelper
|
||||||
|
|
||||||
|
unless const_defined? :JQUERY_VAR
|
||||||
|
JQUERY_VAR = '$'
|
||||||
|
end
|
||||||
|
|
||||||
|
unless const_defined? :JQCALLBACKS
|
||||||
|
JQCALLBACKS = Set.new([ :beforeSend, :complete, :error, :success ] + (100..599).to_a)
|
||||||
|
AJAX_OPTIONS = Set.new([ :before, :after, :condition, :url,
|
||||||
|
:asynchronous, :method, :insertion, :position,
|
||||||
|
:form, :with, :update, :script ]).merge(JQCALLBACKS)
|
||||||
|
end
|
||||||
|
|
||||||
|
def periodically_call_remote(options = {})
|
||||||
|
frequency = options[:frequency] || 10 # every ten seconds by default
|
||||||
|
code = "setInterval(function() {#{remote_function(options)}}, #{frequency} * 1000)"
|
||||||
|
javascript_tag(code)
|
||||||
|
end
|
||||||
|
|
||||||
|
def remote_function(options)
|
||||||
|
javascript_options = options_for_ajax(options)
|
||||||
|
|
||||||
|
update = ''
|
||||||
|
if options[:update] && options[:update].is_a?(Hash)
|
||||||
|
update = []
|
||||||
|
update << "success:'#{options[:update][:success]}'" if options[:update][:success]
|
||||||
|
update << "failure:'#{options[:update][:failure]}'" if options[:update][:failure]
|
||||||
|
update = '{' + update.join(',') + '}'
|
||||||
|
elsif options[:update]
|
||||||
|
update << "'#{options[:update]}'"
|
||||||
|
end
|
||||||
|
|
||||||
|
function = "#{JQUERY_VAR}.ajax(#{javascript_options})"
|
||||||
|
|
||||||
|
function = "#{options[:before]}; #{function}" if options[:before]
|
||||||
|
function = "#{function}; #{options[:after]}" if options[:after]
|
||||||
|
function = "if (#{options[:condition]}) { #{function}; }" if options[:condition]
|
||||||
|
function = "if (confirm('#{escape_javascript(options[:confirm])}')) { #{function}; }" if options[:confirm]
|
||||||
|
return function
|
||||||
|
end
|
||||||
|
|
||||||
|
class JavaScriptGenerator
|
||||||
|
module GeneratorMethods
|
||||||
|
|
||||||
|
def insert_html(position, id, *options_for_render)
|
||||||
|
insertion = position.to_s.downcase
|
||||||
|
insertion = 'append' if insertion == 'bottom'
|
||||||
|
insertion = 'prepend' if insertion == 'top'
|
||||||
|
call "#{JQUERY_VAR}(\"#{jquery_id(id)}\").#{insertion}", render(*options_for_render)
|
||||||
|
end
|
||||||
|
|
||||||
|
def replace_html(id, *options_for_render)
|
||||||
|
insert_html(:html, id, *options_for_render)
|
||||||
|
end
|
||||||
|
|
||||||
|
def replace(id, *options_for_render)
|
||||||
|
call "#{JQUERY_VAR}(\"#{jquery_id(id)}\").replaceWith", render(*options_for_render)
|
||||||
|
end
|
||||||
|
|
||||||
|
def remove(*ids)
|
||||||
|
call "#{JQUERY_VAR}(\"#{jquery_ids(ids)}\").remove"
|
||||||
|
end
|
||||||
|
|
||||||
|
def show(*ids)
|
||||||
|
call "#{JQUERY_VAR}(\"#{jquery_ids(ids)}\").show"
|
||||||
|
end
|
||||||
|
|
||||||
|
def hide(*ids)
|
||||||
|
call "#{JQUERY_VAR}(\"#{jquery_ids(ids)}\").hide"
|
||||||
|
end
|
||||||
|
|
||||||
|
def toggle(*ids)
|
||||||
|
call "#{JQUERY_VAR}(\"#{jquery_ids(ids)}\").toggle"
|
||||||
|
end
|
||||||
|
|
||||||
|
def jquery_id(id)
|
||||||
|
id.to_s.count('#.*,>+~:[/ ') == 0 ? "##{id}" : id
|
||||||
|
end
|
||||||
|
|
||||||
|
def jquery_ids(ids)
|
||||||
|
Array(ids).map{|id| jquery_id(id)}.join(',')
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
def options_for_ajax(options)
|
||||||
|
js_options = build_callbacks(options)
|
||||||
|
|
||||||
|
url_options = options[:url]
|
||||||
|
url_options = url_options.merge(:escape => false) if url_options.is_a?(Hash)
|
||||||
|
js_options['url'] = "'#{url_for(url_options)}'"
|
||||||
|
js_options['async'] = false if options[:type] == :synchronous
|
||||||
|
js_options['type'] = options[:method] ? method_option_to_s(options[:method]) : ( options[:form] ? "'post'" : nil )
|
||||||
|
js_options['dataType'] = options[:datatype] ? "'#{options[:datatype]}'" : (options[:update] ? nil : "'script'")
|
||||||
|
|
||||||
|
if options[:form]
|
||||||
|
js_options['data'] = "#{JQUERY_VAR}.param(#{JQUERY_VAR}(this).serializeArray())"
|
||||||
|
elsif options[:submit]
|
||||||
|
js_options['data'] = "#{JQUERY_VAR}(\"##{options[:submit]} :input\").serialize()"
|
||||||
|
elsif options[:with]
|
||||||
|
js_options['data'] = options[:with].gsub("Form.serialize(this.form)","#{JQUERY_VAR}.param(#{JQUERY_VAR}(this.form).serializeArray())")
|
||||||
|
end
|
||||||
|
|
||||||
|
js_options['type'] ||= "'post'"
|
||||||
|
if options[:method]
|
||||||
|
if method_option_to_s(options[:method]) == "'put'" || method_option_to_s(options[:method]) == "'delete'"
|
||||||
|
js_options['type'] = "'post'"
|
||||||
|
if js_options['data']
|
||||||
|
js_options['data'] << " + '&"
|
||||||
|
else
|
||||||
|
js_options['data'] = "'"
|
||||||
|
end
|
||||||
|
js_options['data'] << "_method=#{options[:method]}'"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if respond_to?('protect_against_forgery?') && protect_against_forgery?
|
||||||
|
if js_options['data']
|
||||||
|
js_options['data'] << " + '&"
|
||||||
|
else
|
||||||
|
js_options['data'] = "'"
|
||||||
|
end
|
||||||
|
js_options['data'] << "#{request_forgery_protection_token}=' + encodeURIComponent('#{escape_javascript form_authenticity_token}')"
|
||||||
|
end
|
||||||
|
js_options['data'] = "''" if js_options['type'] == "'post'" && js_options['data'].nil?
|
||||||
|
options_for_javascript(js_options.reject {|key, value| value.nil?})
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_update_for_success(html_id, insertion=nil)
|
||||||
|
insertion = build_insertion(insertion)
|
||||||
|
"#{JQUERY_VAR}('#{jquery_id(html_id)}').#{insertion}(request);"
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_update_for_error(html_id, insertion=nil)
|
||||||
|
insertion = build_insertion(insertion)
|
||||||
|
"#{JQUERY_VAR}('#{jquery_id(html_id)}').#{insertion}(request.responseText);"
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_insertion(insertion)
|
||||||
|
insertion = insertion ? insertion.to_s.downcase : 'html'
|
||||||
|
insertion = 'append' if insertion == 'bottom'
|
||||||
|
insertion = 'prepend' if insertion == 'top'
|
||||||
|
insertion
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_observer(klass, name, options = {})
|
||||||
|
if options[:with] && (options[:with] !~ /[\{=(.]/)
|
||||||
|
options[:with] = "'#{options[:with]}=' + value"
|
||||||
|
else
|
||||||
|
options[:with] ||= 'value' unless options[:function]
|
||||||
|
end
|
||||||
|
|
||||||
|
callback = options[:function] || remote_function(options)
|
||||||
|
javascript = "#{JQUERY_VAR}('#{jquery_id(name)}').delayedObserver("
|
||||||
|
javascript << "#{options[:frequency] || 0}, "
|
||||||
|
javascript << "function(element, value) {"
|
||||||
|
javascript << "#{callback}}"
|
||||||
|
#javascript << ", '#{options[:on]}'" if options[:on]
|
||||||
|
javascript << ")"
|
||||||
|
javascript_tag(javascript)
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_callbacks(options)
|
||||||
|
callbacks = {}
|
||||||
|
options[:beforeSend] = '';
|
||||||
|
[:uninitialized,:loading,:loaded].each do |key|
|
||||||
|
options[:beforeSend] << (options[key].last == ';' ? options.delete(key) : options.delete(key) << ';') if options[key]
|
||||||
|
end
|
||||||
|
options.delete(:beforeSend) if options[:beforeSend].blank?
|
||||||
|
options[:error] = options.delete(:failure) if options[:failure]
|
||||||
|
if options[:update]
|
||||||
|
if options[:update].is_a?(Hash)
|
||||||
|
options[:update][:error] = options[:update].delete(:failure) if options[:update][:failure]
|
||||||
|
if options[:update][:success]
|
||||||
|
options[:success] = build_update_for_success(options[:update][:success], options[:position]) << (options[:success] ? options[:success] : '')
|
||||||
|
end
|
||||||
|
if options[:update][:error]
|
||||||
|
options[:error] = build_update_for_error(options[:update][:error], options[:position]) << (options[:error] ? options[:error] : '')
|
||||||
|
end
|
||||||
|
else
|
||||||
|
options[:success] = build_update_for_success(options[:update], options[:position]) << (options[:success] ? options[:success] : '')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
options.each do |callback, code|
|
||||||
|
if JQCALLBACKS.include?(callback)
|
||||||
|
callbacks[callback] = "function(request){#{code}}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
callbacks
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
class JavaScriptElementProxy < JavaScriptProxy #:nodoc:
|
||||||
|
|
||||||
|
unless const_defined? :JQUERY_VAR
|
||||||
|
JQUERY_VAR = ActionView::Helpers::PrototypeHelper::JQUERY_VAR
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(generator, id)
|
||||||
|
id = id.to_s.count('#.*,>+~:[/ ') == 0 ? "##{id}" : id
|
||||||
|
@id = id
|
||||||
|
super(generator, "#{JQUERY_VAR}(\"#{id}\")")
|
||||||
|
end
|
||||||
|
|
||||||
|
def replace_html(*options_for_render)
|
||||||
|
call 'html', @generator.send(:render, *options_for_render)
|
||||||
|
end
|
||||||
|
|
||||||
|
def replace(*options_for_render)
|
||||||
|
call 'replaceWith', @generator.send(:render, *options_for_render)
|
||||||
|
end
|
||||||
|
|
||||||
|
def value()
|
||||||
|
call 'val()'
|
||||||
|
end
|
||||||
|
|
||||||
|
def value=(value)
|
||||||
|
call 'val', value
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
class JavaScriptElementCollectionProxy < JavaScriptCollectionProxy #:nodoc:\
|
||||||
|
|
||||||
|
unless const_defined? :JQUERY_VAR
|
||||||
|
JQUERY_VAR = ActionView::Helpers::PrototypeHelper::JQUERY_VAR
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(generator, pattern)
|
||||||
|
super(generator, "#{JQUERY_VAR}(#{pattern.to_json})")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
module ScriptaculousHelper
|
||||||
|
|
||||||
|
unless const_defined? :JQUERY_VAR
|
||||||
|
JQUERY_VAR = ActionView::Helpers::PrototypeHelper::JQUERY_VAR
|
||||||
|
end
|
||||||
|
|
||||||
|
unless const_defined? :SCRIPTACULOUS_EFFECTS
|
||||||
|
SCRIPTACULOUS_EFFECTS = {
|
||||||
|
:appear => {:method => 'fadeIn'},
|
||||||
|
:blind_down => {:method => 'blind', :mode => 'show', :options => {:direction => 'vertical'}},
|
||||||
|
:blind_up => {:method => 'blind', :mode => 'hide', :options => {:direction => 'vertical'}},
|
||||||
|
:blind_right => {:method => 'blind', :mode => 'show', :options => {:direction => 'horizontal'}},
|
||||||
|
:blind_left => {:method => 'blind', :mode => 'hide', :options => {:direction => 'horizontal'}},
|
||||||
|
:bounce_in => {:method => 'bounce', :mode => 'show', :options => {:direction => 'up'}},
|
||||||
|
:bounce_out => {:method => 'bounce', :mode => 'hide', :options => {:direction => 'up'}},
|
||||||
|
:drop_in => {:method => 'drop', :mode => 'show', :options => {:direction => 'up'}},
|
||||||
|
:drop_out => {:method => 'drop', :mode => 'hide', :options => {:direction => 'down'}},
|
||||||
|
:fade => {:method => 'fadeOut'},
|
||||||
|
:fold_in => {:method => 'fold', :mode => 'hide'},
|
||||||
|
:fold_out => {:method => 'fold', :mode => 'show'},
|
||||||
|
:grow => {:method => 'scale', :mode => 'show'},
|
||||||
|
:shrink => {:method => 'scale', :mode => 'hide'},
|
||||||
|
:slide_down => {:method => 'slide', :mode => 'show', :options => {:direction => 'up'}},
|
||||||
|
:slide_up => {:method => 'slide', :mode => 'hide', :options => {:direction => 'up'}},
|
||||||
|
:slide_right => {:method => 'slide', :mode => 'show', :options => {:direction => 'left'}},
|
||||||
|
:slide_left => {:method => 'slide', :mode => 'hide', :options => {:direction => 'left'}},
|
||||||
|
:squish => {:method => 'scale', :mode => 'hide', :options => {:origin => "['top','left']"}},
|
||||||
|
:switch_on => {:method => 'clip', :mode => 'show', :options => {:direction => 'vertical'}},
|
||||||
|
:switch_off => {:method => 'clip', :mode => 'hide', :options => {:direction => 'vertical'}},
|
||||||
|
:toggle_appear => {:method => 'fadeToggle'},
|
||||||
|
:toggle_slide => {:method => 'slide', :mode => 'toggle', :options => {:direction => 'up'}},
|
||||||
|
:toggle_blind => {:method => 'blind', :mode => 'toggle', :options => {:direction => 'vertical'}},
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def visual_effect(name, element_id = false, js_options = {})
|
||||||
|
element = element_id ? element_id : "this"
|
||||||
|
|
||||||
|
if SCRIPTACULOUS_EFFECTS.has_key? name.to_sym
|
||||||
|
effect = SCRIPTACULOUS_EFFECTS[name.to_sym]
|
||||||
|
name = effect[:method]
|
||||||
|
mode = effect[:mode]
|
||||||
|
js_options = js_options.merge(effect[:options]) if effect[:options]
|
||||||
|
end
|
||||||
|
|
||||||
|
[:color, :direction].each do |option|
|
||||||
|
js_options[option] = "'#{js_options[option]}'" if js_options[option]
|
||||||
|
end
|
||||||
|
|
||||||
|
if js_options.has_key? :duration
|
||||||
|
speed = js_options.delete :duration
|
||||||
|
speed = (speed * 1000).to_i unless speed.nil?
|
||||||
|
else
|
||||||
|
speed = js_options.delete :speed
|
||||||
|
end
|
||||||
|
|
||||||
|
if ['fadeIn','fadeOut','fadeToggle'].include?(name)
|
||||||
|
javascript = "#{JQUERY_VAR}('#{jquery_id(element_id)}').#{name}("
|
||||||
|
javascript << "#{speed}" unless speed.nil?
|
||||||
|
javascript << ");"
|
||||||
|
else
|
||||||
|
javascript = "#{JQUERY_VAR}('#{jquery_id(element_id)}').#{mode || 'effect'}('#{name}'"
|
||||||
|
javascript << ",#{options_for_javascript(js_options)}" unless speed.nil? && js_options.empty?
|
||||||
|
javascript << ",#{speed}" unless speed.nil?
|
||||||
|
javascript << ");"
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def sortable_element_js(element_id, options = {}) #:nodoc:
|
||||||
|
#convert similar attributes
|
||||||
|
options[:handle] = ".#{options[:handle]}" if options[:handle]
|
||||||
|
if options[:tag] || options[:only]
|
||||||
|
options[:items] = "> "
|
||||||
|
options[:items] << options.delete(:tag) if options[:tag]
|
||||||
|
options[:items] << ".#{options.delete(:only)}" if options[:only]
|
||||||
|
end
|
||||||
|
options[:connectWith] = options.delete(:containment).map {|x| "##{x}"} if options[:containment]
|
||||||
|
options[:containment] = options.delete(:container) if options[:container]
|
||||||
|
options[:dropOnEmpty] = false unless options[:dropOnEmpty]
|
||||||
|
options[:helper] = "'clone'" if options[:ghosting] == true
|
||||||
|
options[:axis] = case options.delete(:constraint)
|
||||||
|
when "vertical"
|
||||||
|
"y"
|
||||||
|
when "horizontal"
|
||||||
|
"x"
|
||||||
|
when false
|
||||||
|
nil
|
||||||
|
when nil
|
||||||
|
"y"
|
||||||
|
end
|
||||||
|
options.delete(:axis) if options[:axis].nil?
|
||||||
|
options.delete(:overlap)
|
||||||
|
options.delete(:ghosting)
|
||||||
|
|
||||||
|
if options[:onUpdate] || options[:url]
|
||||||
|
options[:with] ||= "#{JQUERY_VAR}(this).sortable('serialize',{key:'#{element_id}'})"
|
||||||
|
options[:onUpdate] ||= "function(){" + remote_function(options) + "}"
|
||||||
|
end
|
||||||
|
|
||||||
|
options.delete_if { |key, value| PrototypeHelper::AJAX_OPTIONS.include?(key) }
|
||||||
|
options[:update] = options.delete(:onUpdate) if options[:onUpdate]
|
||||||
|
|
||||||
|
[:axis, :cancel, :containment, :cursor, :handle, :tolerance, :items, :placeholder].each do |option|
|
||||||
|
options[option] = "'#{options[option]}'" if options[option]
|
||||||
|
end
|
||||||
|
|
||||||
|
options[:connectWith] = array_or_string_for_javascript(options[:connectWith]) if options[:connectWith]
|
||||||
|
|
||||||
|
%(#{JQUERY_VAR}('#{jquery_id(element_id)}').sortable(#{options_for_javascript(options)});)
|
||||||
|
end
|
||||||
|
|
||||||
|
def draggable_element_js(element_id, options = {})
|
||||||
|
%(#{JQUERY_VAR}("#{jquery_id(element_id)}").draggable(#{options_for_javascript(options)});)
|
||||||
|
end
|
||||||
|
|
||||||
|
def drop_receiving_element_js(element_id, options = {})
|
||||||
|
#convert similar options
|
||||||
|
options[:hoverClass] = options.delete(:hoverclass) if options[:hoverclass]
|
||||||
|
options[:drop] = options.delete(:onDrop) if options[:onDrop]
|
||||||
|
|
||||||
|
if options[:drop] || options[:url]
|
||||||
|
options[:with] ||= "'id=' + encodeURIComponent(#{JQUERY_VAR}(ui.draggable).attr('id'))"
|
||||||
|
options[:drop] ||= "function(ev, ui){" + remote_function(options) + "}"
|
||||||
|
end
|
||||||
|
|
||||||
|
options.delete_if { |key, value| PrototypeHelper::AJAX_OPTIONS.include?(key) }
|
||||||
|
|
||||||
|
options[:accept] = array_or_string_for_javascript(options[:accept]) if options[:accept]
|
||||||
|
[:activeClass, :hoverClass, :tolerance].each do |option|
|
||||||
|
options[option] = "'#{options[option]}'" if options[option]
|
||||||
|
end
|
||||||
|
|
||||||
|
%(#{JQUERY_VAR}('#{jquery_id(element_id)}').droppable(#{options_for_javascript(options)});)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,19 @@
|
||||||
|
namespace :jrails do
|
||||||
|
namespace :update do
|
||||||
|
desc "Copies the jQuery and jRails javascripts to public/javascripts"
|
||||||
|
task :javascripts do
|
||||||
|
puts "Copying files..."
|
||||||
|
project_dir = RAILS_ROOT + '/public/javascripts/'
|
||||||
|
scripts = Dir[File.join(File.dirname(__FILE__), '..') + '/javascripts/*.js']
|
||||||
|
FileUtils.cp(scripts, project_dir)
|
||||||
|
puts "files copied successfully."
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
namespace :install do
|
||||||
|
desc "Installs the jQuery and jRails javascripts to public/javascripts"
|
||||||
|
task :javascripts do
|
||||||
|
Rake::Task['jrails:update:javascripts'].invoke
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue