Your SlideShare is downloading. ×
  • Like
Techmosis Rails
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Now you can save presentations on your phone or tablet

Available for both IPhone and Android

Text the download link to your phone

Standard text messaging rates apply

Techmosis Rails

  • 807 views
Published

Slides from a talk given at Techmosis Friday, Last.fm office London, Feb 2009

Slides from a talk given at Techmosis Friday, Last.fm office London, Feb 2009

Published in Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
807
On SlideShare
0
From Embeds
0
Number of Embeds
0

Actions

Shares
Downloads
7
Comments
0
Likes
1

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Ruby on Rails techmosis @last.fm, feb 2009
  • 2. ... some fundamentals
  • 3. “one stack” approach [M+V+C]
  • 4. “thou shalt not repeat thyself” (it’s a religion)
  • 5. convention over configuration (table names)
  • 6. brought established software engineering principles into “scripting” environments
  • 7. model: ActiveRecord
  • 8. class Foo < ActiveRecord::Base belongs_to :bar # insert rails magic here end
  • 9. # standard query Foo.find(:all, :conditions=>["name=?", "kittens"]) # provided by AR Foo.find_by_name("kittens") # avoid N+1 Foo.find(:all, :include=>:bar) # custom Foo.find_by_sql("select foos.* from foos where....")
  • 10. view: erb or haml?
  • 11. erb: php style <%= foo %>
  • 12. haml: nested structure
  • 13. !!! %html{ :xmlns => "http://www.w3.org/1999/xhtml", "xml:lang" => "en" } %head %meta{ "http-equiv" => "content-type", :content => "text/html; charset=utf-8" }/ %title= page_title = render :partial => "shared/icon" = stylesheet_link_tag 'screen', :media => 'screen' /[if IE] %style{:type=>"text/css"} * html { overflow-y: scroll; overflow-x: hidden; } = javascript_include_tag 'prototype' = javascript_include_tag 'lowpro' = javascript_include_tag 'velcro' = controller_assets /[if IE] = stylesheet_link_tag 'ie', :media => 'screen' %body %div#page %div#content = @content_for_layout %div#footer = render :partial => "shared/footer"
  • 14. testing: rspec {model, view, controller}
  • 15. BDD (behaviour driven development)
  • 16. # model spec describe "generating api key" do it "should create an api key entry in the db" do lambda { @howard.generate_api_key! }.should change(ApiKey, :count).by(1) end end # controller spec describe "an admin" do describe "with a valid API key" do before do @howard.generate_api_key! end it "should be able to fetch the latest graph" do get :latest, :params=>{:api_key => @howard.api_key}, :response=>200 end it "should be able to fetch meta data" do #... end end end
  • 17. deployment
  • 18. historically very painful (mod_fcgi, mongrel+ mod_proxy_balancer, mod_rewrite...) too many options...
  • 19. complicated to set up.
  • 20. <VirtualHost *:80> ServerName <%= servername>> DocumentRoot "/rails_root/public" <Directory "/rails_root/public"> Options FollowSymLinks AllowOverride None Order allow,deny Allow from all Header append Cache-Control "private, must-revalidate, max-age=0" </Directory> <Proxy balancer://<%= clustername %>> <% startport.upto(startport + servers - 1) do |p| -%> BalancerMember http://127.0.0.1:<%= p %> <% end -%> ProxySet lbmethod=bytraffic ProxySet maxattempts=5 </Proxy> ProxyTimeout 300 RewriteEngine On # Check for maintenance file and redirect all requests RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f RewriteCond %{SCRIPT_FILENAME} !maintenance.html RewriteRule ^.*$ /system/maintenance.html [L] # Rewrite index to check for static RewriteRule ^/$ /index.html [QSA] # Rewrite to check for Rails cached page RewriteRule ^([^.]+)$ $1.html [QSA] # Redirect all non-static requests to cluster RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f RewriteRule ^/(.*)$ balancer://<%= clustername %>%{REQUEST_URI} [P,QSA,L]
  • 21. btw: don’t use mongrel (it leaks memory)
  • 22. a new standard emerges: rack
  • 23. not tied to rails, can be used with many ruby based frameworks
  • 24. call a method... app.call(env)
  • 25. which returns an array with 3 elements... [200, 'Content-Type'=>'text/plain', 'Hello World']
  • 26. for apache2 there is...
  • 27. mod_rails / mod_rack (phusion passenger)
  • 28. it’s quite simple...
  • 29. LoadModule passenger_module /usr/lib/passenger/mod_passenger.so PassengerRoot /usr PassengerRuby /usr/bin/ruby1.8 <VirtualHost *:80> ServerName myserver.com DocumentRoot "/rails_root/public" </VirtualHost>
  • 30. but...
  • 31. how to get the code deployed?
  • 32. capistrano
  • 33. what cap does for you: • remote code checkout via VCS • shell execution on remote servers (in parallel) • rollback to last release (symlink) • extensible (not just for rails!)
  • 34. set :repository, "http://myrepo.com/myapp/trunk/" role :web, "www.example.com" role :db, "db1.example.com", :primary => true desc "reloads apache config" task :reload , :roles=>:web do sudo "/etc/init.d/httpd reload", :pty => true end
  • 35. monitoring apps: god (“like monit, but awesome”)
  • 36. start_port = 3000 count =5 (start_port...start_port+count).each do |port| God.watch do |w| w.start = "sh -c 'mongrel_rails start -p #{port} -c #{RAILS_ROOT}" w.interval = 5.seconds w.grace = 5.seconds # restart if memory or cpu is too high w.restart_if do |restart| restart.condition(:memory_usage) do |c| c.interval = 20 c.above = 500 * 1024 # max_mem MB c.times = [3, 5] end end w.notify = “foo@bar.com” end end
  • 37. exception_notifier
  • 38. console
  • 39. scaling rails
  • 40. processes vs threads
  • 41. new in rails 2.2: multithreading! def dispatch if ActionController::Base.allow_concurrency dispatch_unlocked else @@guard.synchronize do dispatch_unlocked end end end (finally...)
  • 42. new: connection pooling (actually required for multithreaded apps)
  • 43. what’s good / interesting?
  • 44. active community (some call it “ghetto”)
  • 45. some really good plugins (acts_as_*)
  • 46. quick development + testing
  • 47. ActiveRecord scopes
  • 48. Post.with_scope(:find => {:conditions => ["user_id = ?", current_user.id]} do @user_posts = Post.find(:all) end
  • 49. easy RESTful development
  • 50. map.resources :tasks, :member => { :run => :post }, :collection => { :run_all => :post } # tasks => GET /tasks # new_task => PUT /tasks/new # update_task(@task) => POST /tasks/1/update # run_task(@task) => POST /tasks/1/run # run_all_tasks => POST /tasks/run_all class TasksController < ApplicationController def index @task = Task.find(:all) end def update @task = Task.find(params[:id]) @task.update_attributes!(params[:task]) end def run @task = Task.find(params[:id]) @task.run! end end
  • 51. ActiveResource
  • 52. class Task < ActiveResource::Base self.site = "http://api.example.com" end @task = Task.new(:when=>Time.now) @task.save # POST http://api.example.com/tasks/create @task.id # => 1 @task = Task.find(1) # GET http://api.example.com/tasks/1.xml
  • 53. creating feeds
  • 54. class TasksController < ApplicationController def index @tasks = Task.find(:all) respond_to do |format| format.html format.atom end end end # from tasks/index.atom.builder atom_feed(:url => formatted_tasks_url(:atom)) do |feed| feed.title("Tasks") feed.updated(Time.now.utc) for task in @tasks feed.entry(task) do |entry| entry.title(task.name) entry.content(task.content) end end end
  • 55. what’s bad?
  • 56. too much magic (method_missing, really...)
  • 57. monkey patching / metaprogramming (too much !)
  • 58. module ActiveSupport #:nodoc: module CoreExtensions #:nodoc: module Array #:nodoc: # Makes it easier to access parts of an array. module Access # Equal to <tt>self[1]</tt>. def second self[1] end # Equal to <tt>self[2]</tt>. def third self[2] end # Equal to <tt>self[3]</tt>. def fourth self[3] end #.... #WTF? # Equal to <tt>self[41]</tt>. Also known as accessing "the reddit". def forty_two self[41] end end end end
  • 59. monolithic architecture
  • 60. “If you’re not doing it the ‘Rails way’...
  • 61. ...ur doing it wrong!”
  • 62. DHH
  • 63. native extensions = deployment headaches
  • 64. alternatively...
  • 65. deploy your app on the JVM: JRuby on Rails
  • 66. you need: ActiveRecord-JDBC (more options)
  • 67. integrate with java libraries
  • 68. deploy on: jetty, glassfish, ...
  • 69. it’s faster! (about twice as fast)
  • 70. future
  • 71. rails3 aka merb
  • 72. merb? (mongrel+erb)
  • 73. “clean-room” implementation of rails
  • 74. modular design, choice of frameworks (no “merb way”)
  • 75. merb-slices (apps in django?)
  • 76. current trends
  • 77. micro-frameworks: sinatra