SlideShare a Scribd company logo
1 of 72
Download to read offline
Rails in the
Enterprise     Staying Railsy
               while scaling complexity
David Williams
  @metakube
Of all the terms I hate with a passion,
 “professional” would probably rank
   above “enterprise” and just below
                        “potty mouth”.

                       –@dhh in 2009
What does
ENTERPRISE
   mean?
EDI




                            Workflow
 XML
             SOAP
                    COBOL

BPEL    ABAP/4
automation
visibility
compliance
it comes down to



     $
But we’re software people.
        Start talking tech.

            –y’all, just now
COMPLEXITY
What does
COMPLEXITY
   mean?
5   languages
    14   standard user roles
  166    controllers
  183    database tables
 1577    permissions
  58k    lines of code
>100k    API calls / day
   3m    rows in biggest table
 $5.6b   spend through system
Internationalization
    Localization
   XSS protection
   Single sign-on
    Data security
    Extensibility
   Customization
   API integration
        S*@P
co sta
  m te

        m
          e
    pl m
            i
      ex a  t
         m ac
           ch
              xo
                 s


        qu i
               i d
                n e


          er ne
             ie s
               s
   RU
     LE
co sta
  m te

        m
          e
    pl m
            i
      ex a  t
         m ac
           ch
              xo
                 s


        qu i
               i d
                n e


          er ne
             ie s
               s
   RU
     LE
Pointcuts
                Cross Cutting Concerns

Decorator Pattern

     Aspect Oriented
       Programming
Adapter Pattern
                Separation of Concerns

Multiple Inheritance
Mixins
class RequisitionHeader
         < ActiveRecord::Base
      has_custom_fields
      acts_as_revisionable
      securable_by_account
      api_in
      api_out
end
class RequisitionHeader
         < ActiveRecord::Base
      has_custom_fields
      acts_as_revisionable
      securable_by_account
      api_in
                     Let’s talk about these
      api_out
end
co sta
  m te

        m
          e
    pl m
            i
      ex a  t
         m ac
           ch
              xo
                 s


        qu i
               i d
                n e


          er ne
             ie s
               s
   RU
     LE
S
I♥
ruby
class Api::DepartmentsController
       < Api::BaseController
    api_scaffold :department
end

Coupa::Application.routes.draw do
    namespace :api do
        resources :departments
    end
end
class Department
       < ActiveRecord::Base

      api_in [:name, :active], [],
         {:keys => ["id", "name"]}

      api_out [:name, :active]

end
(lack of)
class Department            associations
       < ActiveRecord::Base

      api_in [:name, :active], [],
         {:keys => ["id", "name"]}

      api_out [:name, :active]

end
(lack of)
class Department            associations
       < ActiveRecord::Base

      api_in [:name, :active], [],
         {:keys => ["id", "name"]}

      api_out [:name, :active]

end
class Api::BaseController < AppController

  def self.api_scaffold(model_id, options={})
   options.assert_valid_keys(:class_name,
     :scope, :user_scope, :validate_if,
     :before_save)
   singular_name = model_id.to_s
   class_name    = options[:class_name] ||
                   singular_name.camelize
   model_class   = class_name.constantize
        [way more code than I can fit]
   self.module_eval(overlay_methods)
  end

end
APIs and...
APIs and... bulk loaders
            custom fields
            searchable table views
            budgeting
            approval workflows
            revision tracking
            reporting
            notifications
            caching
            and more...
co sta
  m te

        m
          e
    pl m
            i
      ex a  t
         m ac
           ch
              xo
                 s


        qu i
               i d
                n e


          er ne
             ie s
               s
   RU
     LE
We use AASM*
* Monkeypatched for transactional error handling,
  and for the event transitions to work like they used
  to.
class RequisitionHeader < ActiveRecord::Base
  state :pending_buyer_action,
      :enter => Proc.new { |r|
        Notifier.req_requires_action(r) }


  state :pending_approval,
      :after_enter => Proc.new { |r|
        ApprovalNotify.next_approver(r)}


  state :ordered,
      :enter => Proc.new { |r|
        OrderHeader.create_from_req(r) }
end
class RequisitionHeader < ActiveRecord::Base
  state :pending_buyer_action,
      :enter => Proc.new { |r|
        Notifier.req_requires_action(r) }


  state :pending_approval,
      :after_enter => Proc.new { |r|
        ApprovalNotify.next_approver(r) }


  state :ordered,
      :enter => Proc.new { |r|
        OrderHeader.create_from_req(r) }
end
class RequisitionHeader < ActiveRecord::Base
  event :submit_for_approval do
      transitions :to => :pending_approval,
                  :from => [:draft, :cart],
                  :guard => :approvable?
      transitions :to => :pending_buyer_action,
                  :from => [:draft, :cart],
                  :guard => :submittable?
  end
end
class RequisitionHeader < ActiveRecord::Base
  event :submit_for_approval do
      transitions :to => :pending_approval,
                  :from => [:draft, :cart],
                  :guard => :approvable?
      transitions :to => :pending_buyer_action,
                  :from => [:draft, :cart],
                  :guard => :submittable?
  end
end
class RequisitionHeader < ActiveRecord::Base
  event :submit_for_approval do
      transitions :to => :pending_approval,
                  :from => [:draft, :cart],
                  :guard => :approvable?
      transitions :to => :pending_buyer_action,
                  :from => [:draft, :cart],
                  :guard => :submittable?
  end
end
What’s the point?
class RequisitionHeader < ActiveRecord::Base
  validates_presence_of :ship_to_address,
      :if => Proc.new { |requisition_header|
             requisition_header.status &&
              !%w(draft cart pending_buyer_action).
               include?(requisition_header.status)
         }
end
class RequisitionHeader < ActiveRecord::Base
 def editable?
      user = User.current_user
      case self.status
      when 'pending_approval'
        approvable_by? && user && user.authorized?('approver', 'edit')
      when 'cart', 'draft'
        user == self.requested_by || user == self.created_by
      when 'pending_buyer_action'
        user && user.authorized?('buying', 'edit')
      else
        false
      end
  end
end
Yawn. Show me a hack.

       –y’all, just now
I18n loose end tying: Ugly but useful
module ActiveSupport::Inflector
  def humanize_with_translation(underscored_word)
      begin
        (I18n.translate!("statuses.#{underscored_word}",
            :default => :"activerecord.models.#{underscored_word}",
            :count => 1) unless underscored_word.blank?) || ''
      rescue I18n::MissingTranslationData => e
        humanize_without_translation(underscored_word)
      end
  end


  alias_method_chain :humanize, :translation
end
co sta
  m te

        m
          e
    pl m
            i
      ex a  t
         m ac
           ch
              xo
                 s


        qu i
               i d
                n e


          er ne
             ie s
               s
   RU
     LE
IF YOU TREAT YOUR DB AS DUMB




   HOW CAN IT LOVE YOU?
SELECT distinct suppliers.id
 FROM suppliers
 JOIN supplier_items ON supplier_items.supplier_id = suppliers.id
 LEFT OUTER JOIN catalogs ON catalogs.id = supplier_items.catalog_id
 LEFT OUTER JOIN contracts ON contracts.id =
supplier_items.contract_id
 LEFT OUTER JOIN business_group_assignments ON
(business_group_assignments.securable_id = contracts.id AND
business_group_assignments.securable_type = 'Contract')
 STRAIGHT_JOIN items ON (items.id = supplier_items.item_id AND
items.active = 1 AND (items.connect_item_id IS NULL OR
items.imported_from_connect = 1))
 WHERE ( suppliers.status = 'active'
 AND (supplier_items.catalog_id IS NULL
 OR ( catalogs.status = 'accepted'
 AND (catalogs.start_date IS NULL OR '2011-11-15 18:30:00' >=
catalogs.start_date)
 AND (catalogs.end_date IS NULL OR '2011-11-15 18:30:00' <
catalogs.end_date) ))
 AND (supplier_items.contract_id IS NULL
 OR (contracts.status = 'published'
 AND business_group_assignments.business_group_id in (3,2,1)
 AND contracts.start_date <= '2011-11-15 18:30:00'
 AND (contracts.end_date IS NULL OR contracts.end_date > '2011-11-15
18:30:00') ))
SELECT distinct suppliers.id
 FROM suppliers




                                       sy
 JOIN supplier_items ON supplier_items.supplier_id = suppliers.id
 LEFT OUTER JOIN catalogs ON catalogs.id = supplier_items.catalog_id
 LEFT OUTER JOIN contracts ON contracts.id =




                                     il
supplier_items.contract_id
 LEFT OUTER JOIN business_group_assignments ON
(business_group_assignments.securable_id = contracts.id AND




                              Ra
business_group_assignments.securable_type = 'Contract')
 STRAIGHT_JOIN items ON (items.id = supplier_items.item_id AND
items.active = 1 AND (items.connect_item_id IS NULL OR
items.imported_from_connect = 1))


                ry
 WHERE ( suppliers.status = 'active'
 AND (supplier_items.catalog_id IS NULL
 OR ( catalogs.status = 'accepted'
 AND (catalogs.start_date IS NULL OR '2011-11-15 18:30:00' >=
              ve
catalogs.start_date)
 AND (catalogs.end_date IS NULL OR '2011-11-15 18:30:00' <
catalogs.end_date) ))
 AND (supplier_items.contract_id IS NULL
 OR (contracts.status = 'published'
    t

 AND business_group_assignments.business_group_id in (3,2,1)
  No


 AND contracts.start_date <= '2011-11-15 18:30:00'
 AND (contracts.end_date IS NULL OR contracts.end_date > '2011-11-15
18:30:00') ))
So let’s step back a moment and
talk about a common problem...
Displaying paginated
   search results
What you’re querying on doesn’t
  always match what you’re
          displaying
Users         Roles       Permissions




Suppliers     Addresses      Countries




Commodities   Contacts
                          And this is a
                          simple one...
Users                  Roles               Permissions


 Online                 Shipping               Payment
 Stores                  Terms                  Terms


            Suppliers              Addresses             Countries


 Parent                                         Phone
Suppliers                                      Numbers


          Commodities              Contacts
                                                   And this is a
                                                   simple one...
outer join != :include
Depends on a Ruby monkeypatch


.joins(begin
        options[:include].deep_exec{|c|
           c.to_sym.send(:outer)
         }
      rescue
       []
      end)
          Depends on Ernie Miller’s awesome
                Metawhere / Squeel
Wow, that’s nasty.
Why would you do that?

        –y’all, just now
30% improvement in common cases
30% improvement in common cases

90% improvement in some nasty cases
30% improvement in common cases

90% improvement in some nasty cases

              YMMV
MySQL doesn’t ♥ sorting
Narrow your SELECT clauses
.paginate({
 :select => 'SQL_CALC_FOUND_ROWS
             DISTINCT #{table}.id',
 :per_page => 20,
 :page => options[:page]
 })
MySQL count query avoidance hack. YMMV.


.paginate({
 :select => 'SQL_CALC_FOUND_ROWS
             DISTINCT #{table}.id',
 :per_page => 20,
 :page => options[:page]
 })
MySQL count query avoidance hack. YMMV.


.paginate({
 :select => 'SQL_CALC_FOUND_ROWS
             DISTINCT #{table}.id',
 :per_page => 20,
 :page => options[:page]
 })

      [Then query just the rows you want]
Like deep_clone? Try deep_exec.
class Array
  def deep_exec(&blk)
      result = []
      each do |e|
        if e.respond_to?(:deep_exec)
            result << e.deep_exec(&blk)
        else
            result << yield(e)
        end
      end
      result
  end
end
Like deep_clone? Try deep_exec.
class Array                          class Hash
                                       def deep_exec(&blk)
  def deep_exec(&blk)
                                            result = {}
      result = []
                                            each do |k,v|
      each do |e|
                                                result[yield k] =
        if e.respond_to?(:deep_exec)
                                                  if v.respond_to?(:deep_exec)
            result << e.deep_exec(&blk)
                                                    v.deep_exec(&blk)
        else
                                                  else
            result << yield(e)
                                                    yield v
        end
                                                  end
      end
                                            end
      result
                                            result
  end
                                          end
end
                                     end
Totally out of time...
We’re Hiring!
 (I know, total surprise.)
Photo Credits
Used under Creative Commons from typedow


Used under Creative Commons from gaymerbear


Used under Creative Commons from Mandy_Jansen



http://popartmachine.com/blog/pop-art-based-on-hawaiian-shirt-pattern.html



Used under Creative Commons from casey.marshall
Staying railsy - while scaling complexity or Ruby on Rails in Enterprise Software

More Related Content

What's hot

Advanced Internationalization with Rails
Advanced Internationalization with RailsAdvanced Internationalization with Rails
Advanced Internationalization with RailsClinton Dreisbach
 
Error Reporting in ZF2: form messages, custom error pages, logging
Error Reporting in ZF2: form messages, custom error pages, loggingError Reporting in ZF2: form messages, custom error pages, logging
Error Reporting in ZF2: form messages, custom error pages, loggingSteve Maraspin
 
Lecture4 php by okello erick
Lecture4 php by okello erickLecture4 php by okello erick
Lecture4 php by okello erickokelloerick
 
Alloy Tips & Tricks #TiLon
Alloy Tips & Tricks #TiLonAlloy Tips & Tricks #TiLon
Alloy Tips & Tricks #TiLonFokke Zandbergen
 
Meet Elcodi, the flexible e-commerce components built on Symfony2
Meet Elcodi, the flexible e-commerce components built on Symfony2Meet Elcodi, the flexible e-commerce components built on Symfony2
Meet Elcodi, the flexible e-commerce components built on Symfony2Aldo Chiecchia
 
Ruby On Rails Pitfalls
Ruby On Rails PitfallsRuby On Rails Pitfalls
Ruby On Rails PitfallsRobin Lu
 
Laravel Security Standards
Laravel Security Standards Laravel Security Standards
Laravel Security Standards Singsys Pte Ltd
 
Apostrophe (improved Paris edition)
Apostrophe (improved Paris edition)Apostrophe (improved Paris edition)
Apostrophe (improved Paris edition)tompunk
 
Contagion的Ruby/Rails投影片
Contagion的Ruby/Rails投影片Contagion的Ruby/Rails投影片
Contagion的Ruby/Rails投影片cfc
 
Drupal Form API 101 (PHP) - DrupalCamp LA 2012
Drupal Form API 101 (PHP) - DrupalCamp LA 2012Drupal Form API 101 (PHP) - DrupalCamp LA 2012
Drupal Form API 101 (PHP) - DrupalCamp LA 2012Chris Charlton
 
Dealing With Legacy PHP Applications
Dealing With Legacy PHP ApplicationsDealing With Legacy PHP Applications
Dealing With Legacy PHP ApplicationsViget Labs
 
Zend_Form to the Rescue - A Brief Introduction to Zend_Form
Zend_Form to the Rescue - A Brief Introduction to Zend_FormZend_Form to the Rescue - A Brief Introduction to Zend_Form
Zend_Form to the Rescue - A Brief Introduction to Zend_FormJeremy Kendall
 
Moderne backends mit dem aktor programmiermodell
Moderne backends mit dem aktor programmiermodellModerne backends mit dem aktor programmiermodell
Moderne backends mit dem aktor programmiermodellDamir Dobric
 
Top 5 Magento Secure Coding Best Practices
Top 5 Magento Secure Coding Best PracticesTop 5 Magento Secure Coding Best Practices
Top 5 Magento Secure Coding Best PracticesOleksandr Zarichnyi
 
Quality assurance for php projects with PHPStorm
Quality assurance for php projects with PHPStormQuality assurance for php projects with PHPStorm
Quality assurance for php projects with PHPStormMichelangelo van Dam
 

What's hot (20)

Advanced Internationalization with Rails
Advanced Internationalization with RailsAdvanced Internationalization with Rails
Advanced Internationalization with Rails
 
Session 2- day 3
Session 2- day 3Session 2- day 3
Session 2- day 3
 
Error Reporting in ZF2: form messages, custom error pages, logging
Error Reporting in ZF2: form messages, custom error pages, loggingError Reporting in ZF2: form messages, custom error pages, logging
Error Reporting in ZF2: form messages, custom error pages, logging
 
Lecture4 php by okello erick
Lecture4 php by okello erickLecture4 php by okello erick
Lecture4 php by okello erick
 
Data Validation models
Data Validation modelsData Validation models
Data Validation models
 
Alloy Tips & Tricks #TiLon
Alloy Tips & Tricks #TiLonAlloy Tips & Tricks #TiLon
Alloy Tips & Tricks #TiLon
 
Meet Elcodi, the flexible e-commerce components built on Symfony2
Meet Elcodi, the flexible e-commerce components built on Symfony2Meet Elcodi, the flexible e-commerce components built on Symfony2
Meet Elcodi, the flexible e-commerce components built on Symfony2
 
Ruby On Rails Pitfalls
Ruby On Rails PitfallsRuby On Rails Pitfalls
Ruby On Rails Pitfalls
 
Laravel Security Standards
Laravel Security Standards Laravel Security Standards
Laravel Security Standards
 
Apostrophe (improved Paris edition)
Apostrophe (improved Paris edition)Apostrophe (improved Paris edition)
Apostrophe (improved Paris edition)
 
Contagion的Ruby/Rails投影片
Contagion的Ruby/Rails投影片Contagion的Ruby/Rails投影片
Contagion的Ruby/Rails投影片
 
Practical Object Oriented Models In Sql
Practical Object Oriented Models In SqlPractical Object Oriented Models In Sql
Practical Object Oriented Models In Sql
 
IoC with PHP
IoC with PHPIoC with PHP
IoC with PHP
 
Drupal Form API 101 (PHP) - DrupalCamp LA 2012
Drupal Form API 101 (PHP) - DrupalCamp LA 2012Drupal Form API 101 (PHP) - DrupalCamp LA 2012
Drupal Form API 101 (PHP) - DrupalCamp LA 2012
 
Dealing With Legacy PHP Applications
Dealing With Legacy PHP ApplicationsDealing With Legacy PHP Applications
Dealing With Legacy PHP Applications
 
Zend_Form to the Rescue - A Brief Introduction to Zend_Form
Zend_Form to the Rescue - A Brief Introduction to Zend_FormZend_Form to the Rescue - A Brief Introduction to Zend_Form
Zend_Form to the Rescue - A Brief Introduction to Zend_Form
 
Extensible Data Modeling
Extensible Data ModelingExtensible Data Modeling
Extensible Data Modeling
 
Moderne backends mit dem aktor programmiermodell
Moderne backends mit dem aktor programmiermodellModerne backends mit dem aktor programmiermodell
Moderne backends mit dem aktor programmiermodell
 
Top 5 Magento Secure Coding Best Practices
Top 5 Magento Secure Coding Best PracticesTop 5 Magento Secure Coding Best Practices
Top 5 Magento Secure Coding Best Practices
 
Quality assurance for php projects with PHPStorm
Quality assurance for php projects with PHPStormQuality assurance for php projects with PHPStorm
Quality assurance for php projects with PHPStorm
 

Viewers also liked

Testing Experience - Evolution of Test Automation Frameworks
Testing Experience - Evolution of Test Automation FrameworksTesting Experience - Evolution of Test Automation Frameworks
Testing Experience - Evolution of Test Automation FrameworksŁukasz Morawski
 
Engaging IV&V Testing Services for Agile Projects
Engaging IV&V Testing Services for Agile ProjectsEngaging IV&V Testing Services for Agile Projects
Engaging IV&V Testing Services for Agile ProjectsRavi Kumar
 
Card &amp; Payments Industry Overview
Card &amp; Payments Industry OverviewCard &amp; Payments Industry Overview
Card &amp; Payments Industry Overviewankitinxs
 
Mathematics of life
Mathematics of lifeMathematics of life
Mathematics of lifeMar Zafar
 
Software Testing for International Students
Software Testing for International StudentsSoftware Testing for International Students
Software Testing for International Studentscristianoribeirosilva
 
Evolution of Software Testing - Chuan Chuan Law
Evolution of Software Testing - Chuan Chuan Law Evolution of Software Testing - Chuan Chuan Law
Evolution of Software Testing - Chuan Chuan Law Chuan Chuan Law
 
Fundamentals of Software Testing
Fundamentals of Software TestingFundamentals of Software Testing
Fundamentals of Software TestingSagar Joshi
 
スクラム概要とチーム開発環境の要点
スクラム概要とチーム開発環境の要点スクラム概要とチーム開発環境の要点
スクラム概要とチーム開発環境の要点智治 長沢
 
うちではこうやっています UI構築のルールとPlaymakerを使った画面遷移
うちではこうやっています UI構築のルールとPlaymakerを使った画面遷移うちではこうやっています UI構築のルールとPlaymakerを使った画面遷移
うちではこうやっています UI構築のルールとPlaymakerを使った画面遷移まべ☆てっく運営
 
UX, ethnography and possibilities: for Libraries, Museums and Archives
UX, ethnography and possibilities: for Libraries, Museums and ArchivesUX, ethnography and possibilities: for Libraries, Museums and Archives
UX, ethnography and possibilities: for Libraries, Museums and ArchivesNed Potter
 

Viewers also liked (10)

Testing Experience - Evolution of Test Automation Frameworks
Testing Experience - Evolution of Test Automation FrameworksTesting Experience - Evolution of Test Automation Frameworks
Testing Experience - Evolution of Test Automation Frameworks
 
Engaging IV&V Testing Services for Agile Projects
Engaging IV&V Testing Services for Agile ProjectsEngaging IV&V Testing Services for Agile Projects
Engaging IV&V Testing Services for Agile Projects
 
Card &amp; Payments Industry Overview
Card &amp; Payments Industry OverviewCard &amp; Payments Industry Overview
Card &amp; Payments Industry Overview
 
Mathematics of life
Mathematics of lifeMathematics of life
Mathematics of life
 
Software Testing for International Students
Software Testing for International StudentsSoftware Testing for International Students
Software Testing for International Students
 
Evolution of Software Testing - Chuan Chuan Law
Evolution of Software Testing - Chuan Chuan Law Evolution of Software Testing - Chuan Chuan Law
Evolution of Software Testing - Chuan Chuan Law
 
Fundamentals of Software Testing
Fundamentals of Software TestingFundamentals of Software Testing
Fundamentals of Software Testing
 
スクラム概要とチーム開発環境の要点
スクラム概要とチーム開発環境の要点スクラム概要とチーム開発環境の要点
スクラム概要とチーム開発環境の要点
 
うちではこうやっています UI構築のルールとPlaymakerを使った画面遷移
うちではこうやっています UI構築のルールとPlaymakerを使った画面遷移うちではこうやっています UI構築のルールとPlaymakerを使った画面遷移
うちではこうやっています UI構築のルールとPlaymakerを使った画面遷移
 
UX, ethnography and possibilities: for Libraries, Museums and Archives
UX, ethnography and possibilities: for Libraries, Museums and ArchivesUX, ethnography and possibilities: for Libraries, Museums and Archives
UX, ethnography and possibilities: for Libraries, Museums and Archives
 

Similar to Staying railsy - while scaling complexity or Ruby on Rails in Enterprise Software

Ruby on rails
Ruby on rails Ruby on rails
Ruby on rails Mohit Jain
 
Intro to-rails-webperf
Intro to-rails-webperfIntro to-rails-webperf
Intro to-rails-webperfNew Relic
 
Intro to Ruby on Rails
Intro to Ruby on RailsIntro to Ruby on Rails
Intro to Ruby on RailsMark Menard
 
Rails MVC by Sergiy Koshovyi
Rails MVC by Sergiy KoshovyiRails MVC by Sergiy Koshovyi
Rails MVC by Sergiy KoshovyiPivorak MeetUp
 
Código Saudável => Programador Feliz - Rs on Rails 2010
Código Saudável => Programador Feliz - Rs on Rails 2010Código Saudável => Programador Feliz - Rs on Rails 2010
Código Saudável => Programador Feliz - Rs on Rails 2010Plataformatec
 
OSDC 2009 Rails Turtorial
OSDC 2009 Rails TurtorialOSDC 2009 Rails Turtorial
OSDC 2009 Rails TurtorialYi-Ting Cheng
 
Ruby/Rails
Ruby/RailsRuby/Rails
Ruby/Railsrstankov
 
What's new in Rails 4
What's new in Rails 4What's new in Rails 4
What's new in Rails 4Fabio Akita
 
Intro to Rails ActiveRecord
Intro to Rails ActiveRecordIntro to Rails ActiveRecord
Intro to Rails ActiveRecordMark Menard
 
Altitude NY 2018: Leveraging Log Streaming to Build the Best Dashboards, Ever
Altitude NY 2018: Leveraging Log Streaming to Build the Best Dashboards, EverAltitude NY 2018: Leveraging Log Streaming to Build the Best Dashboards, Ever
Altitude NY 2018: Leveraging Log Streaming to Build the Best Dashboards, EverFastly
 
Action Controller Overview, Season 2
Action Controller Overview, Season 2Action Controller Overview, Season 2
Action Controller Overview, Season 2RORLAB
 
Advanced RESTful Rails
Advanced RESTful RailsAdvanced RESTful Rails
Advanced RESTful RailsViget Labs
 
Advanced RESTful Rails
Advanced RESTful RailsAdvanced RESTful Rails
Advanced RESTful RailsBen Scofield
 
Apex Enterprise Patterns: Building Strong Foundations
Apex Enterprise Patterns: Building Strong FoundationsApex Enterprise Patterns: Building Strong Foundations
Apex Enterprise Patterns: Building Strong FoundationsSalesforce Developers
 
Migrating PriceChirp to Rails 3.0: The Pain Points
Migrating PriceChirp to Rails 3.0: The Pain PointsMigrating PriceChirp to Rails 3.0: The Pain Points
Migrating PriceChirp to Rails 3.0: The Pain PointsSteven Evatt
 
От Rails-way к модульной архитектуре
От Rails-way к модульной архитектуреОт Rails-way к модульной архитектуре
От Rails-way к модульной архитектуреIvan Nemytchenko
 
Agile data presentation 3 - cambridge
Agile data   presentation 3 - cambridgeAgile data   presentation 3 - cambridge
Agile data presentation 3 - cambridgeRomans Malinovskis
 
Introduction à Ruby
Introduction à RubyIntroduction à Ruby
Introduction à RubyMicrosoft
 

Similar to Staying railsy - while scaling complexity or Ruby on Rails in Enterprise Software (20)

Ruby on rails
Ruby on rails Ruby on rails
Ruby on rails
 
Intro to-rails-webperf
Intro to-rails-webperfIntro to-rails-webperf
Intro to-rails-webperf
 
SOLID Ruby, SOLID Rails
SOLID Ruby, SOLID RailsSOLID Ruby, SOLID Rails
SOLID Ruby, SOLID Rails
 
Intro to Ruby on Rails
Intro to Ruby on RailsIntro to Ruby on Rails
Intro to Ruby on Rails
 
Rails MVC by Sergiy Koshovyi
Rails MVC by Sergiy KoshovyiRails MVC by Sergiy Koshovyi
Rails MVC by Sergiy Koshovyi
 
Código Saudável => Programador Feliz - Rs on Rails 2010
Código Saudável => Programador Feliz - Rs on Rails 2010Código Saudável => Programador Feliz - Rs on Rails 2010
Código Saudável => Programador Feliz - Rs on Rails 2010
 
OSDC 2009 Rails Turtorial
OSDC 2009 Rails TurtorialOSDC 2009 Rails Turtorial
OSDC 2009 Rails Turtorial
 
Ruby/Rails
Ruby/RailsRuby/Rails
Ruby/Rails
 
What's new in Rails 4
What's new in Rails 4What's new in Rails 4
What's new in Rails 4
 
Intro to Rails ActiveRecord
Intro to Rails ActiveRecordIntro to Rails ActiveRecord
Intro to Rails ActiveRecord
 
Altitude NY 2018: Leveraging Log Streaming to Build the Best Dashboards, Ever
Altitude NY 2018: Leveraging Log Streaming to Build the Best Dashboards, EverAltitude NY 2018: Leveraging Log Streaming to Build the Best Dashboards, Ever
Altitude NY 2018: Leveraging Log Streaming to Build the Best Dashboards, Ever
 
The Rails Way
The Rails WayThe Rails Way
The Rails Way
 
Action Controller Overview, Season 2
Action Controller Overview, Season 2Action Controller Overview, Season 2
Action Controller Overview, Season 2
 
Advanced RESTful Rails
Advanced RESTful RailsAdvanced RESTful Rails
Advanced RESTful Rails
 
Advanced RESTful Rails
Advanced RESTful RailsAdvanced RESTful Rails
Advanced RESTful Rails
 
Apex Enterprise Patterns: Building Strong Foundations
Apex Enterprise Patterns: Building Strong FoundationsApex Enterprise Patterns: Building Strong Foundations
Apex Enterprise Patterns: Building Strong Foundations
 
Migrating PriceChirp to Rails 3.0: The Pain Points
Migrating PriceChirp to Rails 3.0: The Pain PointsMigrating PriceChirp to Rails 3.0: The Pain Points
Migrating PriceChirp to Rails 3.0: The Pain Points
 
От Rails-way к модульной архитектуре
От Rails-way к модульной архитектуреОт Rails-way к модульной архитектуре
От Rails-way к модульной архитектуре
 
Agile data presentation 3 - cambridge
Agile data   presentation 3 - cambridgeAgile data   presentation 3 - cambridge
Agile data presentation 3 - cambridge
 
Introduction à Ruby
Introduction à RubyIntroduction à Ruby
Introduction à Ruby
 

More from Coupa Software

The Coupa Organic Platform from A to Z: Maximizing the Value
The Coupa Organic Platform from A to Z: Maximizing the ValueThe Coupa Organic Platform from A to Z: Maximizing the Value
The Coupa Organic Platform from A to Z: Maximizing the ValueCoupa Software
 
The Rise of Postmodern ERP
The Rise of Postmodern ERP The Rise of Postmodern ERP
The Rise of Postmodern ERP Coupa Software
 
Supplier Enablement: The Path to 100%
Supplier Enablement: The Path to 100%Supplier Enablement: The Path to 100%
Supplier Enablement: The Path to 100%Coupa Software
 
Unified Spend Visibility and Control with Expenses that Employees Love
Unified Spend Visibility and Control with Expenses that Employees LoveUnified Spend Visibility and Control with Expenses that Employees Love
Unified Spend Visibility and Control with Expenses that Employees LoveCoupa Software
 
Get Your Head in the Cloud
Get Your Head in the CloudGet Your Head in the Cloud
Get Your Head in the CloudCoupa Software
 
Reinventing Procurement by Putting People First
Reinventing Procurement by Putting People First Reinventing Procurement by Putting People First
Reinventing Procurement by Putting People First Coupa Software
 
Managing Growth: Scaling Financial Processes and Spend Management with Coupa
Managing Growth: Scaling Financial Processes and Spend Management with Coupa Managing Growth: Scaling Financial Processes and Spend Management with Coupa
Managing Growth: Scaling Financial Processes and Spend Management with Coupa Coupa Software
 
Invoicing Innovation - Taking Accounts Payable to the Next Level
Invoicing Innovation - Taking Accounts Payable to the Next Level Invoicing Innovation - Taking Accounts Payable to the Next Level
Invoicing Innovation - Taking Accounts Payable to the Next Level Coupa Software
 
Integrating Coupa with Your Enterprise
Integrating Coupa with Your EnterpriseIntegrating Coupa with Your Enterprise
Integrating Coupa with Your EnterpriseCoupa Software
 
How Coupa Contracts Can Increase Compliance
How Coupa Contracts Can Increase ComplianceHow Coupa Contracts Can Increase Compliance
How Coupa Contracts Can Increase ComplianceCoupa Software
 
Fastest Path to Supplier Enablement
Fastest Path to Supplier Enablement Fastest Path to Supplier Enablement
Fastest Path to Supplier Enablement Coupa Software
 
Eliminate Redundant Spend and Increase Savings with Coupa Inventory
Eliminate Redundant Spend and Increase Savings with Coupa Inventory Eliminate Redundant Spend and Increase Savings with Coupa Inventory
Eliminate Redundant Spend and Increase Savings with Coupa Inventory Coupa Software
 
Coupa for High Technology
Coupa for High TechnologyCoupa for High Technology
Coupa for High TechnologyCoupa Software
 
Coupa Savings-as-a-Service for Healthcare
Coupa Savings-as-a-Service for Healthcare Coupa Savings-as-a-Service for Healthcare
Coupa Savings-as-a-Service for Healthcare Coupa Software
 
Coupa Analytics: Actionable Insights to Optimize Your Spend
Coupa Analytics: Actionable Insights to Optimize Your Spend Coupa Analytics: Actionable Insights to Optimize Your Spend
Coupa Analytics: Actionable Insights to Optimize Your Spend Coupa Software
 
Business Agility: Leveraging the Power of Coupa Configuration
Business Agility: Leveraging the Power of Coupa ConfigurationBusiness Agility: Leveraging the Power of Coupa Configuration
Business Agility: Leveraging the Power of Coupa ConfigurationCoupa Software
 
Procurement to the People - Coupa Bourne Leisure Webcast
Procurement to the People - Coupa Bourne Leisure WebcastProcurement to the People - Coupa Bourne Leisure Webcast
Procurement to the People - Coupa Bourne Leisure WebcastCoupa Software
 
Manufacturing Success - $200M in Cost Reduction at Armstrong
Manufacturing Success - $200M in Cost Reduction at ArmstrongManufacturing Success - $200M in Cost Reduction at Armstrong
Manufacturing Success - $200M in Cost Reduction at ArmstrongCoupa Software
 

More from Coupa Software (20)

The Coupa Organic Platform from A to Z: Maximizing the Value
The Coupa Organic Platform from A to Z: Maximizing the ValueThe Coupa Organic Platform from A to Z: Maximizing the Value
The Coupa Organic Platform from A to Z: Maximizing the Value
 
The Rise of Postmodern ERP
The Rise of Postmodern ERP The Rise of Postmodern ERP
The Rise of Postmodern ERP
 
Supplier Enablement: The Path to 100%
Supplier Enablement: The Path to 100%Supplier Enablement: The Path to 100%
Supplier Enablement: The Path to 100%
 
Power of Collective
Power of CollectivePower of Collective
Power of Collective
 
Unified Spend Visibility and Control with Expenses that Employees Love
Unified Spend Visibility and Control with Expenses that Employees LoveUnified Spend Visibility and Control with Expenses that Employees Love
Unified Spend Visibility and Control with Expenses that Employees Love
 
Get Your Head in the Cloud
Get Your Head in the CloudGet Your Head in the Cloud
Get Your Head in the Cloud
 
Reinventing Procurement by Putting People First
Reinventing Procurement by Putting People First Reinventing Procurement by Putting People First
Reinventing Procurement by Putting People First
 
Managing Growth: Scaling Financial Processes and Spend Management with Coupa
Managing Growth: Scaling Financial Processes and Spend Management with Coupa Managing Growth: Scaling Financial Processes and Spend Management with Coupa
Managing Growth: Scaling Financial Processes and Spend Management with Coupa
 
Invoicing Innovation - Taking Accounts Payable to the Next Level
Invoicing Innovation - Taking Accounts Payable to the Next Level Invoicing Innovation - Taking Accounts Payable to the Next Level
Invoicing Innovation - Taking Accounts Payable to the Next Level
 
Integrating Coupa with Your Enterprise
Integrating Coupa with Your EnterpriseIntegrating Coupa with Your Enterprise
Integrating Coupa with Your Enterprise
 
How Coupa Contracts Can Increase Compliance
How Coupa Contracts Can Increase ComplianceHow Coupa Contracts Can Increase Compliance
How Coupa Contracts Can Increase Compliance
 
Fastest Path to Supplier Enablement
Fastest Path to Supplier Enablement Fastest Path to Supplier Enablement
Fastest Path to Supplier Enablement
 
Coupa Sourcing
Coupa SourcingCoupa Sourcing
Coupa Sourcing
 
Eliminate Redundant Spend and Increase Savings with Coupa Inventory
Eliminate Redundant Spend and Increase Savings with Coupa Inventory Eliminate Redundant Spend and Increase Savings with Coupa Inventory
Eliminate Redundant Spend and Increase Savings with Coupa Inventory
 
Coupa for High Technology
Coupa for High TechnologyCoupa for High Technology
Coupa for High Technology
 
Coupa Savings-as-a-Service for Healthcare
Coupa Savings-as-a-Service for Healthcare Coupa Savings-as-a-Service for Healthcare
Coupa Savings-as-a-Service for Healthcare
 
Coupa Analytics: Actionable Insights to Optimize Your Spend
Coupa Analytics: Actionable Insights to Optimize Your Spend Coupa Analytics: Actionable Insights to Optimize Your Spend
Coupa Analytics: Actionable Insights to Optimize Your Spend
 
Business Agility: Leveraging the Power of Coupa Configuration
Business Agility: Leveraging the Power of Coupa ConfigurationBusiness Agility: Leveraging the Power of Coupa Configuration
Business Agility: Leveraging the Power of Coupa Configuration
 
Procurement to the People - Coupa Bourne Leisure Webcast
Procurement to the People - Coupa Bourne Leisure WebcastProcurement to the People - Coupa Bourne Leisure Webcast
Procurement to the People - Coupa Bourne Leisure Webcast
 
Manufacturing Success - $200M in Cost Reduction at Armstrong
Manufacturing Success - $200M in Cost Reduction at ArmstrongManufacturing Success - $200M in Cost Reduction at Armstrong
Manufacturing Success - $200M in Cost Reduction at Armstrong
 

Recently uploaded

Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdflior mazor
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...DianaGray10
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...apidays
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodJuan lago vázquez
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...apidays
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsJoaquim Jorge
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MIND CTI
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Principled Technologies
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024The Digital Insurer
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024The Digital Insurer
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Top 10 Most Downloaded Games on Play Store in 2024
Top 10 Most Downloaded Games on Play Store in 2024Top 10 Most Downloaded Games on Play Store in 2024
Top 10 Most Downloaded Games on Play Store in 2024SynarionITSolutions
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CVKhem
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 

Recently uploaded (20)

Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Top 10 Most Downloaded Games on Play Store in 2024
Top 10 Most Downloaded Games on Play Store in 2024Top 10 Most Downloaded Games on Play Store in 2024
Top 10 Most Downloaded Games on Play Store in 2024
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 

Staying railsy - while scaling complexity or Ruby on Rails in Enterprise Software

  • 1. Rails in the Enterprise Staying Railsy while scaling complexity
  • 2. David Williams @metakube
  • 3.
  • 4. Of all the terms I hate with a passion, “professional” would probably rank above “enterprise” and just below “potty mouth”. –@dhh in 2009
  • 6. EDI Workflow XML SOAP COBOL BPEL ABAP/4
  • 9. But we’re software people. Start talking tech. –y’all, just now
  • 12. 5 languages 14 standard user roles 166 controllers 183 database tables 1577 permissions 58k lines of code >100k API calls / day 3m rows in biggest table $5.6b spend through system
  • 13. Internationalization Localization XSS protection Single sign-on Data security Extensibility Customization API integration S*@P
  • 14. co sta m te m e pl m i ex a t m ac ch xo s qu i i d n e er ne ie s s RU LE
  • 15. co sta m te m e pl m i ex a t m ac ch xo s qu i i d n e er ne ie s s RU LE
  • 16. Pointcuts Cross Cutting Concerns Decorator Pattern Aspect Oriented Programming Adapter Pattern Separation of Concerns Multiple Inheritance
  • 18. class RequisitionHeader < ActiveRecord::Base has_custom_fields acts_as_revisionable securable_by_account api_in api_out end
  • 19. class RequisitionHeader < ActiveRecord::Base has_custom_fields acts_as_revisionable securable_by_account api_in Let’s talk about these api_out end
  • 20. co sta m te m e pl m i ex a t m ac ch xo s qu i i d n e er ne ie s s RU LE S
  • 22.
  • 23.
  • 24. class Api::DepartmentsController < Api::BaseController api_scaffold :department end Coupa::Application.routes.draw do namespace :api do resources :departments end end
  • 25. class Department < ActiveRecord::Base api_in [:name, :active], [], {:keys => ["id", "name"]} api_out [:name, :active] end
  • 26. (lack of) class Department associations < ActiveRecord::Base api_in [:name, :active], [], {:keys => ["id", "name"]} api_out [:name, :active] end
  • 27. (lack of) class Department associations < ActiveRecord::Base api_in [:name, :active], [], {:keys => ["id", "name"]} api_out [:name, :active] end
  • 28. class Api::BaseController < AppController def self.api_scaffold(model_id, options={}) options.assert_valid_keys(:class_name, :scope, :user_scope, :validate_if, :before_save) singular_name = model_id.to_s class_name = options[:class_name] || singular_name.camelize model_class = class_name.constantize [way more code than I can fit] self.module_eval(overlay_methods) end end
  • 30. APIs and... bulk loaders custom fields searchable table views budgeting approval workflows revision tracking reporting notifications caching and more...
  • 31. co sta m te m e pl m i ex a t m ac ch xo s qu i i d n e er ne ie s s RU LE
  • 32.
  • 33.
  • 34. We use AASM* * Monkeypatched for transactional error handling, and for the event transitions to work like they used to.
  • 35. class RequisitionHeader < ActiveRecord::Base state :pending_buyer_action, :enter => Proc.new { |r| Notifier.req_requires_action(r) } state :pending_approval, :after_enter => Proc.new { |r| ApprovalNotify.next_approver(r)} state :ordered, :enter => Proc.new { |r| OrderHeader.create_from_req(r) } end
  • 36. class RequisitionHeader < ActiveRecord::Base state :pending_buyer_action, :enter => Proc.new { |r| Notifier.req_requires_action(r) } state :pending_approval, :after_enter => Proc.new { |r| ApprovalNotify.next_approver(r) } state :ordered, :enter => Proc.new { |r| OrderHeader.create_from_req(r) } end
  • 37. class RequisitionHeader < ActiveRecord::Base event :submit_for_approval do transitions :to => :pending_approval, :from => [:draft, :cart], :guard => :approvable? transitions :to => :pending_buyer_action, :from => [:draft, :cart], :guard => :submittable? end end
  • 38. class RequisitionHeader < ActiveRecord::Base event :submit_for_approval do transitions :to => :pending_approval, :from => [:draft, :cart], :guard => :approvable? transitions :to => :pending_buyer_action, :from => [:draft, :cart], :guard => :submittable? end end
  • 39. class RequisitionHeader < ActiveRecord::Base event :submit_for_approval do transitions :to => :pending_approval, :from => [:draft, :cart], :guard => :approvable? transitions :to => :pending_buyer_action, :from => [:draft, :cart], :guard => :submittable? end end
  • 41. class RequisitionHeader < ActiveRecord::Base validates_presence_of :ship_to_address, :if => Proc.new { |requisition_header| requisition_header.status && !%w(draft cart pending_buyer_action). include?(requisition_header.status) } end
  • 42. class RequisitionHeader < ActiveRecord::Base def editable? user = User.current_user case self.status when 'pending_approval' approvable_by? && user && user.authorized?('approver', 'edit') when 'cart', 'draft' user == self.requested_by || user == self.created_by when 'pending_buyer_action' user && user.authorized?('buying', 'edit') else false end end end
  • 43. Yawn. Show me a hack. –y’all, just now
  • 44. I18n loose end tying: Ugly but useful module ActiveSupport::Inflector def humanize_with_translation(underscored_word) begin (I18n.translate!("statuses.#{underscored_word}", :default => :"activerecord.models.#{underscored_word}", :count => 1) unless underscored_word.blank?) || '' rescue I18n::MissingTranslationData => e humanize_without_translation(underscored_word) end end alias_method_chain :humanize, :translation end
  • 45. co sta m te m e pl m i ex a t m ac ch xo s qu i i d n e er ne ie s s RU LE
  • 46. IF YOU TREAT YOUR DB AS DUMB HOW CAN IT LOVE YOU?
  • 47. SELECT distinct suppliers.id FROM suppliers JOIN supplier_items ON supplier_items.supplier_id = suppliers.id LEFT OUTER JOIN catalogs ON catalogs.id = supplier_items.catalog_id LEFT OUTER JOIN contracts ON contracts.id = supplier_items.contract_id LEFT OUTER JOIN business_group_assignments ON (business_group_assignments.securable_id = contracts.id AND business_group_assignments.securable_type = 'Contract') STRAIGHT_JOIN items ON (items.id = supplier_items.item_id AND items.active = 1 AND (items.connect_item_id IS NULL OR items.imported_from_connect = 1)) WHERE ( suppliers.status = 'active' AND (supplier_items.catalog_id IS NULL OR ( catalogs.status = 'accepted' AND (catalogs.start_date IS NULL OR '2011-11-15 18:30:00' >= catalogs.start_date) AND (catalogs.end_date IS NULL OR '2011-11-15 18:30:00' < catalogs.end_date) )) AND (supplier_items.contract_id IS NULL OR (contracts.status = 'published' AND business_group_assignments.business_group_id in (3,2,1) AND contracts.start_date <= '2011-11-15 18:30:00' AND (contracts.end_date IS NULL OR contracts.end_date > '2011-11-15 18:30:00') ))
  • 48. SELECT distinct suppliers.id FROM suppliers sy JOIN supplier_items ON supplier_items.supplier_id = suppliers.id LEFT OUTER JOIN catalogs ON catalogs.id = supplier_items.catalog_id LEFT OUTER JOIN contracts ON contracts.id = il supplier_items.contract_id LEFT OUTER JOIN business_group_assignments ON (business_group_assignments.securable_id = contracts.id AND Ra business_group_assignments.securable_type = 'Contract') STRAIGHT_JOIN items ON (items.id = supplier_items.item_id AND items.active = 1 AND (items.connect_item_id IS NULL OR items.imported_from_connect = 1)) ry WHERE ( suppliers.status = 'active' AND (supplier_items.catalog_id IS NULL OR ( catalogs.status = 'accepted' AND (catalogs.start_date IS NULL OR '2011-11-15 18:30:00' >= ve catalogs.start_date) AND (catalogs.end_date IS NULL OR '2011-11-15 18:30:00' < catalogs.end_date) )) AND (supplier_items.contract_id IS NULL OR (contracts.status = 'published' t AND business_group_assignments.business_group_id in (3,2,1) No AND contracts.start_date <= '2011-11-15 18:30:00' AND (contracts.end_date IS NULL OR contracts.end_date > '2011-11-15 18:30:00') ))
  • 49. So let’s step back a moment and talk about a common problem...
  • 50. Displaying paginated search results
  • 51.
  • 52. What you’re querying on doesn’t always match what you’re displaying
  • 53. Users Roles Permissions Suppliers Addresses Countries Commodities Contacts And this is a simple one...
  • 54. Users Roles Permissions Online Shipping Payment Stores Terms Terms Suppliers Addresses Countries Parent Phone Suppliers Numbers Commodities Contacts And this is a simple one...
  • 55. outer join != :include
  • 56. Depends on a Ruby monkeypatch .joins(begin options[:include].deep_exec{|c| c.to_sym.send(:outer) } rescue [] end) Depends on Ernie Miller’s awesome Metawhere / Squeel
  • 57. Wow, that’s nasty. Why would you do that? –y’all, just now
  • 58.
  • 59. 30% improvement in common cases
  • 60. 30% improvement in common cases 90% improvement in some nasty cases
  • 61. 30% improvement in common cases 90% improvement in some nasty cases YMMV
  • 64. .paginate({ :select => 'SQL_CALC_FOUND_ROWS DISTINCT #{table}.id', :per_page => 20, :page => options[:page] })
  • 65. MySQL count query avoidance hack. YMMV. .paginate({ :select => 'SQL_CALC_FOUND_ROWS DISTINCT #{table}.id', :per_page => 20, :page => options[:page] })
  • 66. MySQL count query avoidance hack. YMMV. .paginate({ :select => 'SQL_CALC_FOUND_ROWS DISTINCT #{table}.id', :per_page => 20, :page => options[:page] }) [Then query just the rows you want]
  • 67. Like deep_clone? Try deep_exec. class Array def deep_exec(&blk) result = [] each do |e| if e.respond_to?(:deep_exec) result << e.deep_exec(&blk) else result << yield(e) end end result end end
  • 68. Like deep_clone? Try deep_exec. class Array class Hash def deep_exec(&blk) def deep_exec(&blk) result = {} result = [] each do |k,v| each do |e| result[yield k] = if e.respond_to?(:deep_exec) if v.respond_to?(:deep_exec) result << e.deep_exec(&blk) v.deep_exec(&blk) else else result << yield(e) yield v end end end end result result end end end end
  • 69. Totally out of time...
  • 70. We’re Hiring! (I know, total surprise.)
  • 71. Photo Credits Used under Creative Commons from typedow Used under Creative Commons from gaymerbear Used under Creative Commons from Mandy_Jansen http://popartmachine.com/blog/pop-art-based-on-hawaiian-shirt-pattern.html Used under Creative Commons from casey.marshall