Active Job: Difference between revisions
m (moved User:Ychen71 to Active Job) |
|||
(32 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
== Introduction == | == '''Introduction''' == | ||
Active Job is a framework that helps developers | Active Job is a framework that helps developers to write codes and run them on the background automatically under different scenarios. It’s an interface that adapts various queueing backends like [https://github.com/nesquena/backburner Backburner], [https://github.com/collectiveidea/delayed_job Delayed Job], [https://github.com/bkeepers/qu Qu] and so on. Jobs can vary from schedule newsletters, follow-up emails to database housekeeping. <ref name= "Active-Job-Basics">Rails Guides [http://guides.rubyonrails.org/active_job_basics.html “Active Job Basics” ]</ref> Overall, Active Job is an interface which you can work with common queueing backends. | ||
The reason to have Active Job in place is to make sure Rails apps can have a job infrastructure. Other existing gems can build on this framework without the limitation of API difference between different job runners such as Delayed Job and Resque. With this feature choosing queueing backends can become an operational concern. Also, switching between those queueing backends without rewrite jobs become possible.<ref name= "Active-Job-Basics">Rails Guides [http://guides.rubyonrails.org/active_job_basics.html “Active Job Basics” ]</ref> | |||
__TOC__ | __TOC__ | ||
Line 17: | Line 18: | ||
<br><br><br><br><br><br> | <br><br><br><br><br><br> | ||
====Active Job adapters<ref name="Active-Job-Adapter">Active Job Adapter[http://edgeapi.rubyonrails.org/classes/ActiveJob/QueueAdapters.html"Active Job Adapter" ]</ref>==== | ====Active Job adapters<ref name="Active-Job-Adapter">Active Job Adapter[http://edgeapi.rubyonrails.org/classes/ActiveJob/QueueAdapters.html"Active Job Adapter" ]</ref>==== | ||
List of queueing backends Active Job support: | |||
*Backburner[https://github.com/nesquena/backburner] | *Backburner[https://github.com/nesquena/backburner] | ||
*Delayed Job[https://github.com/collectiveidea/delayed_job] | *Delayed Job[https://github.com/collectiveidea/delayed_job] | ||
Line 30: | Line 32: | ||
=='''How to use <ref>http://guides.rubyonrails.org/active_job_basics.html</ref>'''== | =='''How to use <ref>http://guides.rubyonrails.org/active_job_basics.html</ref>'''== | ||
This chapter is an introduction on how to create a job and and how to add the job into a queue. <ref name= "Active-Job-Basics">Rails Guides [http://guides.rubyonrails.org/active_job_basics.html “Active Job Basics” 2014]</ref> <br> | |||
=== Download === | === Download === | ||
With RubyGems you can install | With RubyGems[https://en.wikipedia.org/wiki/RubyGems] you can install Active Job: | ||
<pre> | <pre> | ||
$ gem install activejob | $ gem install activejob | ||
</pre> | </pre> | ||
[https://github.com/rails/rails/tree/master/activejob Souce code of Active Job] available on GitHub, as part of Rails.<ref> GitHub [https://github.com/rails/rails/tree/master/activejob “Active Job -- Make work happen later” 2015] </ref> | [https://github.com/rails/rails/tree/master/activejob Souce code of Active Job] available on GitHub[https://en.wikipedia.org/wiki/GitHub], as part of Rails.<ref> GitHub [https://github.com/rails/rails/tree/master/activejob “Active Job -- Make work happen later” 2015] </ref> | ||
=== Create a Job === | === Create a Job === | ||
In Active Job, a process | In Active Job, a process inserted in a queue and waiting to carry out is called “Job”. It’s possible to generate a Job using the Generator provided by Rails. You can create a Job in app/jobs. By doing the following, we created a Job called “update_wiki”.<br> | ||
<pre> | <pre> | ||
$ bin/rails generate job update_wiki | $ bin/rails generate job update_wiki | ||
Line 47: | Line 49: | ||
create app/jobs/update_wiki_job.rb | create app/jobs/update_wiki_job.rb | ||
</pre> | </pre> | ||
Active Job provides the ability to run your Job on a specific queue by | Active Job provides the ability to run your Job on a specific queue by creating a job:<br> | ||
<pre> | <pre> | ||
$ bin/rails generate job update_wiki --queue urgent | $ bin/rails generate job update_wiki --queue urgent | ||
Line 67: | Line 69: | ||
end | end | ||
</pre> | </pre> | ||
There is a perform method to be called when the | There is a perform method to be called when the Job was first enqueued. <br> | ||
=== Adding a Job to the queue === | === Adding a Job to the queue === | ||
Enqueue the Job so it can be processed as soon as the queuing system is free: | |||
<pre> | <pre> | ||
UpdateWikiJob.perform_later wiki | UpdateWikiJob.perform_later wiki | ||
</pre> | </pre> | ||
Or | Or add a Job be performed tomorrow at noon: | ||
<pre> | <pre> | ||
UpdateWikiJob.set(wait_until: Date.tomorrow.noon).perform_later(wiki) | UpdateWikiJob.set(wait_until: Date.tomorrow.noon).perform_later(wiki) | ||
</pre> | </pre> | ||
Most of the queueing backends ( Sidekiq | |||
, Delayed Job, etc. ) allow you to set a delay time. | , Delayed Job, etc. ) allow you to set a delay time. | ||
<pre> | <pre> | ||
Line 85: | Line 87: | ||
=== Execution of Job === | === Execution of Job === | ||
Active Job provides adapters for multiple queueing backends ([https://github.com/mperham/sidekiq/wiki Sidekiq], [https://github.com/resque/resque Resque], [https://github.com/collectiveidea/delayed_job Delayed Job] and [http://edgeapi.rubyonrails.org/classes/ActiveJob/QueueAdapters.html others]).<ref name= "Active-Job-Basics">Rails Guides [http://guides.rubyonrails.org/active_job_basics.html “Active Job Basics” 2014]</ref> Without setting any adapter, the job would be performed immediately.<br> | Active Job provides adapters for multiple queueing backends ([https://github.com/mperham/sidekiq/wiki Sidekiq], [https://github.com/resque/resque Resque], [https://github.com/collectiveidea/delayed_job Delayed Job] and [http://edgeapi.rubyonrails.org/classes/ActiveJob/QueueAdapters.html others]).<ref name= "Active-Job-Basics">Rails Guides [http://guides.rubyonrails.org/active_job_basics.html “Active Job Basics” 2014]</ref> Without setting any adapter, the job would be performed immediately.<br> | ||
Queueing backend can be set at: /config/application.rb, | Queueing backend can be set at: /config/application.rb, this example uses the Sidekiq. | ||
<pre> | <pre> | ||
module YourApp | module YourApp | ||
Line 124: | Line 126: | ||
Control a job to run on a queue by passing a :queue option to #set : | |||
<pre> | <pre> | ||
MyJob.set(queue: :another_queue).perform_later(record) | MyJob.set(queue: :another_queue).perform_later(record) | ||
Line 132: | Line 134: | ||
== Examples == | == Examples == | ||
In this section, | In this section, a example is provided to demonstrate how to use ActiveJob in practice. | ||
=== Background Mail Sender === | === Background Mail Sender === | ||
Send emails asynchronously with Action Mailer which Active Job is already integrated in.<ref name= "Action-Mailer-Basics">Rails Guides [http://guides.rubyonrails.org/action_mailer_basics.html “Action Mailer Basics” 2014]</ref> Here in this example, we try to use Active Job with Action Mailer.<br> | |||
==== 1. Getting started with Rails | ==== 1. Getting started with Rails<ref name= "Welcome_to_Rails">GitHub [https://github.com/rails/rails “Welcome to Rails” 2015]</ref> ==== | ||
<pre> | <pre> | ||
# Install Rails if you haven’t done it yet: | # Install Rails if you haven’t done it yet: | ||
Line 154: | Line 156: | ||
==== 2. Resque setup<ref name= "Download_Redis">Redis [http://redis.io/download “Download Redis” 2016]</ref>==== | ==== 2. Resque setup<ref name= "Download_Redis">Redis [http://redis.io/download “Download Redis” 2016]</ref>==== | ||
This example uses [https://github.com/resque/resque Resque] as the enqueuing backend. It'll need [http://redis.io/ Redis] before running Resque. Redis can be installed using [http://brew.sh/ Homebrew]: | |||
<pre> | <pre> | ||
$ brew install redis | $ brew install redis | ||
</pre> | </pre> | ||
Or | Or download, extract and compile Redis using:<ref name= "Download_Redis">Redis [http://redis.io/download “Download Redis” 2016]</ref> | ||
<pre> | <pre> | ||
$ wget http://download.redis.io/releases/redis-3.0.7.tar.gz | $ wget http://download.redis.io/releases/redis-3.0.7.tar.gz | ||
Line 165: | Line 167: | ||
$ make | $ make | ||
</pre> | </pre> | ||
Redis does not officially support Windows, but | Redis does not officially support Microsoft [https://en.wikipedia.org/wiki/Microsoft_Windows Windows] platform, but it can be found [https://github.com/MSOpenTech/redis Redis on Windows] by Microsoft Open Tech group.<br> | ||
Next get Resque be installed. To use resque with Active Job, we also need resque-scheduler. | Next get Resque be installed. To use resque with Active Job, we also need resque-scheduler. | ||
Add the following into Gemfile, and run “$ bundle install”. | Add the following into Gemfile, and run “$ bundle install”. | ||
Line 199: | Line 201: | ||
==== 3. Creating a Mailer<ref name= "Action-Mailer-Basics">Rails Guides [http://guides.rubyonrails.org/action_mailer_basics.html “Action Mailer Basics” 2014]</ref> ==== | ==== 3. Creating a Mailer<ref name= "Action-Mailer-Basics">Rails Guides [http://guides.rubyonrails.org/action_mailer_basics.html “Action Mailer Basics” 2014]</ref> ==== | ||
By doing the things above, we already have our Rails project and the Resque for queuing get set. Next we will | By doing the things above, we already have our Rails project and the Resque for queuing get set. Next we will create a Mailer. | ||
<pre> | <pre> | ||
Line 205: | Line 207: | ||
</pre> | </pre> | ||
Create a method and a view for sending email.<br> | Create a method and a view for sending the email.<br> | ||
In app/mailer/user_mailer.rb: | In app/mailer/user_mailer.rb: | ||
Line 214: | Line 216: | ||
default from: 'from@example.com' | default from: 'from@example.com' | ||
def | def test_email(email) | ||
mail( | mail( | ||
to: email, | to: email, | ||
subject: 'We | subject: 'We are testing Active Job!' | ||
) | ) | ||
end | end | ||
end | end | ||
</pre> | </pre> | ||
In app/views/user_mailer/ | In app/views/user_mailer/test_email.text | ||
<pre> | <pre> | ||
#app/views/user_mailer/ | #app/views/user_mailer/test_email.text | ||
Hey, we | Hey, we are testing Active Job! | ||
</pre> | </pre> | ||
==== 4. Active Job<ref name= "Active-Job-Basics">Rails Guides [http://guides.rubyonrails.org/active_job_basics.html “Active Job Basics” 2014]</ref>==== | |||
==== 4. Active Job==== | |||
Create a configuration file active_job.rb in config/initializers/ , to set Resque as queue_adapter. | Create a configuration file active_job.rb in config/initializers/ , to set Resque as queue_adapter. | ||
<pre> | <pre> | ||
Line 241: | Line 241: | ||
Create a Job with generator. | Create a Job with generator. | ||
<pre> | <pre> | ||
$ bin/rails generate job | $ bin/rails generate job test_email | ||
</pre> | </pre> | ||
In the generated file app/jobs/ | In the generated file app/jobs/test_email_job.rb, define the perform method and set it’s queue_as. | ||
<pre> | <pre> | ||
#app/jobs/ | #app/jobs/test_email_job.rb | ||
class | class TestEmailJob < ActiveJob::Base | ||
queue_as :email | queue_as :email | ||
def perform(email) | def perform(email) | ||
UserMailer. | UserMailer.test_email(email).deliver_now | ||
end | end | ||
end | end | ||
</pre> | </pre> | ||
Now | Now a UserController is in place to put the job into the queue for later execution. Set the email to be sent one minute later for testing. | ||
<pre> | <pre> | ||
$ bin/rails generate job | $ bin/rails generate job test_email | ||
</pre> | </pre> | ||
Line 273: | Line 273: | ||
def create | def create | ||
@user = User.create(user_params) | @user = User.create(user_params) | ||
TestEmailJob.new(@user.email).deliver_later!(wait: 1.minute) | |||
# redirect somewhere | # redirect somewhere | ||
end | end | ||
Line 279: | Line 279: | ||
</pre> | </pre> | ||
Routes and | Routes and views need to be set in order to make it work. | ||
<pre> | <pre> | ||
#config/routes.rb | #config/routes.rb | ||
Line 298: | Line 298: | ||
==== 5. Try execution ==== | ==== 5. Try execution ==== | ||
Before | Before trying the Mailer, MailCatcher[https://rubygems.org/gems/mailcatcher/versions/0.6.1] is needed for the test. Add following into Gemfile and “$ bundle install” | ||
<pre> | <pre> | ||
gem 'mailcatcher' | gem 'mailcatcher' | ||
</pre> | </pre> | ||
To set the environment, add following | To set the environment, one need to add the following into config/environments/development.rb. | ||
<pre> | <pre> | ||
#config/environments/development.rb | #config/environments/development.rb | ||
Line 310: | Line 310: | ||
... | ... | ||
config.action_mailer.delivery_method = :smtp | config.action_mailer.delivery_method = :smtp | ||
config.action_mailer.smtp_settings = { : | config.action_mailer.smtp_settings = { address: "localhost", port: 1025 } | ||
end | end | ||
</pre> | </pre> | ||
Line 332: | Line 332: | ||
</pre> | </pre> | ||
Open the browser and visit localhost:3000/users/new. Then sign up as a new user. One minute later Resque scheduler has following output: | |||
<pre> | <pre> | ||
resque-scheduler: [INFO] 2016-02-05T22:53:15+09:00: Processing Delayed Items | resque-scheduler: [INFO] 2016-02-05T22:53:15+09:00: Processing Delayed Items | ||
</pre> | </pre> | ||
And in | And in MailCatcher: | ||
<pre> | <pre> | ||
==> SMTP: Received message from '<from@example.com>' (315 bytes) | ==> SMTP: Received message from '<from@example.com>' (315 bytes) | ||
</pre> | </pre> | ||
=='''External links'''== | |||
*[http://www.rubyonrails.org/ Ruby on Rails official website] – rubyonrails.org | |||
*[http://railscasts.com/ Railscasts.com] – (defunct) Short Screencasts that focus on Ruby on Rails technique | |||
*[http://rubycasts.io/ Rubycasts.io] – Weekly 15 minute screencasts on the whole Ruby/Rails development stack | |||
*[http://www.railstutorial.org/ The Rails Tutorial] – The Ruby on Rails Tutorial book and screencast series teach you how to develop and deploy Ruby on Rails apps | |||
*[https://github.com/rails/rails Rails source code] | |||
=='''References'''== | =='''References'''== | ||
<references/> | <references/> |
Latest revision as of 22:27, 28 March 2016
Introduction
Active Job is a framework that helps developers to write codes and run them on the background automatically under different scenarios. It’s an interface that adapts various queueing backends like Backburner, Delayed Job, Qu and so on. Jobs can vary from schedule newsletters, follow-up emails to database housekeeping. <ref name= "Active-Job-Basics">Rails Guides “Active Job Basics” </ref> Overall, Active Job is an interface which you can work with common queueing backends. The reason to have Active Job in place is to make sure Rails apps can have a job infrastructure. Other existing gems can build on this framework without the limitation of API difference between different job runners such as Delayed Job and Resque. With this feature choosing queueing backends can become an operational concern. Also, switching between those queueing backends without rewrite jobs become possible.<ref name= "Active-Job-Basics">Rails Guides “Active Job Basics” </ref>
Ruby On Rails versions support Active Job
Version | Date |
---|---|
4.2 | 2014/12/19 |
4.2.5 | 2015/11/13 |
Active Job adapters<ref name="Active-Job-Adapter">Active Job Adapter"Active Job Adapter" </ref>
List of queueing backends Active Job support:
- Backburner[1]
- Delayed Job[2]
- Qu[3]
- Que[4]
- queue_classic[5]
- Resque 1.x[6]
- Sidekiq[7]
- Sneakers[8]
- Sucker Punch[9]
- Active Job Async Job
- Active Job Inline[10]
How to use <ref>http://guides.rubyonrails.org/active_job_basics.html</ref>
This chapter is an introduction on how to create a job and and how to add the job into a queue. <ref name= "Active-Job-Basics">Rails Guides “Active Job Basics” 2014</ref>
Download
With RubyGems[11] you can install Active Job:
$ gem install activejob
Souce code of Active Job available on GitHub[12], as part of Rails.<ref> GitHub “Active Job -- Make work happen later” 2015 </ref>
Create a Job
In Active Job, a process inserted in a queue and waiting to carry out is called “Job”. It’s possible to generate a Job using the Generator provided by Rails. You can create a Job in app/jobs. By doing the following, we created a Job called “update_wiki”.
$ bin/rails generate job update_wiki invoke test_unit create test/jobs/update_wiki_job_test.rb create app/jobs/update_wiki_job.rb
Active Job provides the ability to run your Job on a specific queue by creating a job:
$ bin/rails generate job update_wiki --queue urgent
Files inside of app/jobs can be created manually, instead of using a generator. In Rails 4.2 an ActiveJob class inherits from ActiveJob::Base. In Rails 5.0, it has changed to now inherit from ApplicationJob. When upgrading from Rails 4.2 to Rails 5.0, an application_job.rb file is needed to be created in app/jobs/ and add the following content:<ref> Rails Guides “A Guide for Upgrading Ruby on Rails” 2015 </ref>
class ApplicationJob < ActiveJob::Base end
In Rails 4.2 a Job class defined a perform method and set a “queue_as” value:
class UpdateWikiJob < ActiveJob::Base queue_as :default def perform(*wiki) # Do something later wiki.update_contents end end
There is a perform method to be called when the Job was first enqueued.
Adding a Job to the queue
Enqueue the Job so it can be processed as soon as the queuing system is free:
UpdateWikiJob.perform_later wiki
Or add a Job be performed tomorrow at noon:
UpdateWikiJob.set(wait_until: Date.tomorrow.noon).perform_later(wiki)
Most of the queueing backends ( Sidekiq , Delayed Job, etc. ) allow you to set a delay time.
UpdateWikiJob.set(wait: 1.week).perform_later(wiki)
Execution of Job
Active Job provides adapters for multiple queueing backends (Sidekiq, Resque, Delayed Job and others).<ref name= "Active-Job-Basics">Rails Guides “Active Job Basics” 2014</ref> Without setting any adapter, the job would be performed immediately.
Queueing backend can be set at: /config/application.rb, this example uses the Sidekiq.
module YourApp class Application < Rails::Application # Be sure to have the adapter's gem in your Gemfile and follow # the adapter's specific installation and deployment instructions. config.active_job.queue_adapter = :sidekiq end end
Play with Queues
Active Job allows to schedule the job to be processed on a specific queue, this became helpful as common adapters support multiple queues.
class UpdateWikiJob < ActiveJob::Base queue_as :low_priority #.... end
Queue name can be prefixed for all jobs using config.active_job.queue_name_prefixin application.rb:
# config/application.rb module YourApp class Application < Rails::Application config.active_job.queue_name_prefix = Rails.env end end # app/jobs/update_wiki_job.rb class UpdateWikiJob < ActiveJob::Base queue_as :low_priority #.... end # Now your job will run on queue production_low_priority on your # production environment and on staging_low_priority on your staging # environment
Control a job to run on a queue by passing a :queue option to #set :
MyJob.set(queue: :another_queue).perform_later(record)
All the code snippets are referred from the source<ref name= "Active-Job-Basics">Rails Guides “Active Job Basics” 2014</ref>
Examples
In this section, a example is provided to demonstrate how to use ActiveJob in practice.
Background Mail Sender
Send emails asynchronously with Action Mailer which Active Job is already integrated in.<ref name= "Action-Mailer-Basics">Rails Guides “Action Mailer Basics” 2014</ref> Here in this example, we try to use Active Job with Action Mailer.
1. Getting started with Rails<ref name= "Welcome_to_Rails">GitHub “Welcome to Rails” 2015</ref>
# Install Rails if you haven’t done it yet: $ gem install rails # Create a new Rails application, “myapp_activejob” # is the name of the application: $ rails new myapp_activejob # Change your directory to myapp_activejob $ cd myapp_activejob
Edit the Gemfile in the folder, add following into it:
gem 'responders'
Run “ $ bundle update “ and make sure “$ rails server” works.
2. Resque setup<ref name= "Download_Redis">Redis “Download Redis” 2016</ref>
This example uses Resque as the enqueuing backend. It'll need Redis before running Resque. Redis can be installed using Homebrew:
$ brew install redis
Or download, extract and compile Redis using:<ref name= "Download_Redis">Redis “Download Redis” 2016</ref>
$ wget http://download.redis.io/releases/redis-3.0.7.tar.gz $ tar xzf redis-3.0.7.tar.gz $ cd redis-3.0.7 $ make
Redis does not officially support Microsoft Windows platform, but it can be found Redis on Windows by Microsoft Open Tech group.
Next get Resque be installed. To use resque with Active Job, we also need resque-scheduler.
Add the following into Gemfile, and run “$ bundle install”.
gem 'resque' gem 'resque-scheduler'
After the installation, create a Resque configuration file resque.rb in config/initializers/
#config/initializers/resque.rb Resque.redis = Redis.new(host: 'localhost', post: 6379) Resque.after_fork = Proc.new { ActiveRecord::Base.establish_connection }
As the Resque tasks and Resque Scheduler rake tasks are needed in this example, we need to create a resque.rake file in lib/tasks/:
#lib/tasks/resque.rake require 'resque/tasks' require 'resque/scheduler/tasks' namespace :resque do task setup: :environment do ENV['TERM_CHILD'] ||= '1' ENV['QUEUE'] ||= '*' require 'resque' require 'resque-scheduler' end end
3. Creating a Mailer<ref name= "Action-Mailer-Basics">Rails Guides “Action Mailer Basics” 2014</ref>
By doing the things above, we already have our Rails project and the Resque for queuing get set. Next we will create a Mailer.
$ bin/rails generate mailer user_mailer
Create a method and a view for sending the email.
In app/mailer/user_mailer.rb:
#app/mailers/user_mailer.rb class UserMailer < ActionMailer::Base default from: 'from@example.com' def test_email(email) mail( to: email, subject: 'We are testing Active Job!' ) end end
In app/views/user_mailer/test_email.text
#app/views/user_mailer/test_email.text Hey, we are testing Active Job!
4. Active Job<ref name= "Active-Job-Basics">Rails Guides “Active Job Basics” 2014</ref>
Create a configuration file active_job.rb in config/initializers/ , to set Resque as queue_adapter.
#config/initializers/active_job.rb ActiveJob::Base.queue_adapter = :resque
Create a Job with generator.
$ bin/rails generate job test_email
In the generated file app/jobs/test_email_job.rb, define the perform method and set it’s queue_as.
#app/jobs/test_email_job.rb class TestEmailJob < ActiveJob::Base queue_as :email def perform(email) UserMailer.test_email(email).deliver_now end end
Now a UserController is in place to put the job into the queue for later execution. Set the email to be sent one minute later for testing.
$ bin/rails generate job test_email
#app/controllers/users_controller.rb class UsersController < ApplicationController def new @user = User.new end def create @user = User.create(user_params) TestEmailJob.new(@user.email).deliver_later!(wait: 1.minute) # redirect somewhere end end
Routes and views need to be set in order to make it work.
#config/routes.rb Rails.application.routes.draw do resources :users, only: [:new, :create] end
#app/views/users/new.html.erb <%= form_for @user do |f| %> <%= f.email_field :email %> <%= f.submit %> <% end %>
5. Try execution
Before trying the Mailer, MailCatcher[13] is needed for the test. Add following into Gemfile and “$ bundle install”
gem 'mailcatcher'
To set the environment, one need to add the following into config/environments/development.rb.
#config/environments/development.rb Rails.application.configure do ... config.action_mailer.delivery_method = :smtp config.action_mailer.smtp_settings = { address: "localhost", port: 1025 } end
Run it!
# Start mailcatcher $ mailcatcher # Start redis-server $ redis-server # Start resque:work $ bundle exec rake resque:work # Start resque:scheduler $ rake environment resque:scheduler # Finally start rails server $ rails server
Open the browser and visit localhost:3000/users/new. Then sign up as a new user. One minute later Resque scheduler has following output:
resque-scheduler: [INFO] 2016-02-05T22:53:15+09:00: Processing Delayed Items
And in MailCatcher:
==> SMTP: Received message from '<from@example.com>' (315 bytes)
External links
- Ruby on Rails official website – rubyonrails.org
- Railscasts.com – (defunct) Short Screencasts that focus on Ruby on Rails technique
- Rubycasts.io – Weekly 15 minute screencasts on the whole Ruby/Rails development stack
- The Rails Tutorial – The Ruby on Rails Tutorial book and screencast series teach you how to develop and deploy Ruby on Rails apps
- Rails source code
References
<references/>