Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Using POROs to test ideas

Using POROs to test ideas

Given at the July Ruby meetup in Sydney. Rails encourages bad designs. Using POROs can save you from some of the traps you fall into when using Rails.

Ryan Bigg

July 08, 2014
Tweet

More Decks by Ryan Bigg

Other Decks in Programming

Transcript

  1. Using POROs to test ideas

    View Slide

  2. Core
    Finished in 5 minutes 22 seconds
    1321 examples, 0 failures
    3.2 second startup time

    View Slide

  3. http://xkcd.com/657
    controllers
    models
    views

    View Slide

  4. Rails encourages bad ideas

    View Slide

  5. Hero worship of DHH

    View Slide

  6. Hero worship of me
    "he wrote a book!"

    View Slide

  7. Turbolinks

    View Slide

  8. Concerns*

    View Slide

  9. Model Design

    View Slide

  10. Callbacks

    View Slide

  11. - TJ Holowaychuk
    https://medium.com/code-adventures/farewell-node-js-4ba9e7f3e52b

    View Slide

  12. Spree::LineItem
    11 different callbacks

    View Slide

  13. 1) Spree::OrderContents update cart changes item quantity
    Failure/Error: subject.update_cart params
    NoMethodError:
    undefined method `should_track_inventory?' for nil:NilClass
    # ./app/models/spree/stock/quantifier.rb:12:in `total_on_hand'
    # ./app/models/spree/stock/quantifier.rb:24:in `can_supply?'
    # ./app/models/spree/stock/availability_validator.rb:15:in `validate'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:447:in `public_send'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:447:in `block in make_lambda'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:184:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:184:in `block in simple'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:185:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:185:in `block in simple'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:185:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:185:in `block in simple'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:185:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:185:in `block in simple'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:185:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:185:in `block in simple'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:185:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:185:in `block in simple'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:86:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:86:in `run_callbacks'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activemodel-4.1.1/lib/active_model/validations.rb:376:in `run_validations!'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activemodel-4.1.1/lib/active_model/validations/callbacks.rb:111:in `block in run_validations!'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:113:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:113:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:166:in `block in halting'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:166:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:166:in `block in halting'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:86:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:86:in `run_callbacks'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activemodel-4.1.1/lib/active_model/validations/callbacks.rb:111:in `run_validations!'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activemodel-4.1.1/lib/active_model/validations.rb:317:in `valid?'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/validations.rb:70:in `valid?'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/autosave_association.rb:304:in `association_valid?'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/autosave_association.rb:293:in `block in validate_collection_association'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/autosave_association.rb:293:in `each'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/autosave_association.rb:293:in `validate_collection_association'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/autosave_association.rb:207:in `block in add_autosave_association_callbacks'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/autosave_association.rb:153:in `instance_eval'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/autosave_association.rb:153:in `block in define_non_cyclic_method'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:424:in `block in make_lambda'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:184:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:184:in `block in simple'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:185:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:185:in `block in simple'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:185:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:185:in `block in simple'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:86:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:86:in `run_callbacks'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activemodel-4.1.1/lib/active_model/validations.rb:376:in `run_validations!'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activemodel-4.1.1/lib/active_model/validations/callbacks.rb:111:in `block in run_validations!'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:113:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:113:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:149:in `block in halting_and_conditional'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:149:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:149:in `block in halting_and_conditional'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:149:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:149:in `block in halting_and_conditional'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:166:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:166:in `block in halting'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:86:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:86:in `run_callbacks'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activemodel-4.1.1/lib/active_model/validations/callbacks.rb:111:in `run_validations!'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activemodel-4.1.1/lib/active_model/validations.rb:317:in `valid?'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/validations.rb:70:in `valid?'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/validations.rb:77:in `perform_validations'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/validations.rb:51:in `save'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/attribute_methods/dirty.rb:21:in `save'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/transactions.rb:268:in `block (2 levels) in save'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/transactions.rb:329:in `block in with_transaction_returning_status'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/connection_adapters/abstract/database_statements.rb:209:in `transaction'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/transactions.rb:208:in `transaction'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/transactions.rb:326:in `with_transaction_returning_status'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/transactions.rb:268:in `block in save'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/transactions.rb:283:in `rollback_active_record_state!'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/transactions.rb:267:in `save'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/persistence.rb:232:in `block in update'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/transactions.rb:329:in `block in with_transaction_returning_status'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/connection_adapters/abstract/database_statements.rb:211:in `block in transaction'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/connection_adapters/abstract/database_statements.rb:219:in `within_new_transaction'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/connection_adapters/abstract/database_statements.rb:211:in `transaction'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/transactions.rb:208:in `transaction'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/transactions.rb:326:in `with_transaction_returning_status'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/persistence.rb:230:in `update'
    # ./app/models/spree/order_contents.rb:29:in `update_cart'
    # ./spec/models/spree/order_contents_spec.rb:127:in `block (3 levels) in '
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/example.rb:114:in `instance_eval'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/example.rb:114:in `block in run'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/example.rb:179:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/example.rb:179:in `run'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/extensions/instance_eval_with_args.rb:16:in `instance_exec'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/extensions/instance_eval_with_args.rb:16:in `instance_eval_with_args'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/example.rb:247:in `instance_eval_with_args'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/hooks.rb:106:in `block (2 levels) in run'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/hooks.rb:108:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/hooks.rb:108:in `run'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/hooks.rb:446:in `run_hook'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/example_group.rb:340:in `run_around_each_hooks'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/example.rb:256:in `with_around_each_hooks'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/example.rb:111:in `run'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/example_group.rb:390:in `block in run_examples'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/example_group.rb:386:in `map'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/example_group.rb:386:in `run_examples'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/example_group.rb:371:in `run'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/example_group.rb:372:in `block in run'
    https://gist.github.com/radar/752c14db65a2cb09293a

    View Slide

  14. 1) Spree::OrderContents update cart changes item quantity
    Failure/Error: subject.update_cart params
    NoMethodError:
    undefined method `should_track_inventory?' for nil:NilClass
    # ./app/models/spree/stock/quantifier.rb:12:in `total_on_hand'
    # ./app/models/spree/stock/quantifier.rb:24:in `can_supply?'
    # ./app/models/spree/stock/availability_validator.rb:15:in `validate'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:447:in `public_send'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:447:in `block in make_lambda'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:184:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:184:in `block in simple'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:185:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:185:in `block in simple'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:185:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:185:in `block in simple'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:185:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:185:in `block in simple'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:185:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:185:in `block in simple'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:185:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:185:in `block in simple'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:86:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:86:in `run_callbacks'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activemodel-4.1.1/lib/active_model/validations.rb:376:in `run_validations!'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activemodel-4.1.1/lib/active_model/validations/callbacks.rb:111:in `block in run_validations!'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:113:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:113:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:166:in `block in halting'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:166:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:166:in `block in halting'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:86:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:86:in `run_callbacks'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activemodel-4.1.1/lib/active_model/validations/callbacks.rb:111:in `run_validations!'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activemodel-4.1.1/lib/active_model/validations.rb:317:in `valid?'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/validations.rb:70:in `valid?'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/autosave_association.rb:304:in `association_valid?'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/autosave_association.rb:293:in `block in validate_collection_association'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/autosave_association.rb:293:in `each'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/autosave_association.rb:293:in `validate_collection_association'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/autosave_association.rb:207:in `block in add_autosave_association_callbacks'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/autosave_association.rb:153:in `instance_eval'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/autosave_association.rb:153:in `block in define_non_cyclic_method'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:424:in `block in make_lambda'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:184:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:184:in `block in simple'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:185:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:185:in `block in simple'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:185:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:185:in `block in simple'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:86:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:86:in `run_callbacks'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activemodel-4.1.1/lib/active_model/validations.rb:376:in `run_validations!'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activemodel-4.1.1/lib/active_model/validations/callbacks.rb:111:in `block in run_validations!'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:113:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:113:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:149:in `block in halting_and_conditional'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:149:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:149:in `block in halting_and_conditional'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:149:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:149:in `block in halting_and_conditional'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:166:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:166:in `block in halting'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:86:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activesupport-4.1.1/lib/active_support/callbacks.rb:86:in `run_callbacks'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activemodel-4.1.1/lib/active_model/validations/callbacks.rb:111:in `run_validations!'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activemodel-4.1.1/lib/active_model/validations.rb:317:in `valid?'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/validations.rb:70:in `valid?'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/validations.rb:77:in `perform_validations'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/validations.rb:51:in `save'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/attribute_methods/dirty.rb:21:in `save'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/transactions.rb:268:in `block (2 levels) in save'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/transactions.rb:329:in `block in with_transaction_returning_status'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/connection_adapters/abstract/database_statements.rb:209:in `transaction'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/transactions.rb:208:in `transaction'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/transactions.rb:326:in `with_transaction_returning_status'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/transactions.rb:268:in `block in save'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/transactions.rb:283:in `rollback_active_record_state!'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/transactions.rb:267:in `save'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/persistence.rb:232:in `block in update'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/transactions.rb:329:in `block in with_transaction_returning_status'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/connection_adapters/abstract/database_statements.rb:211:in `block in transaction'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/connection_adapters/abstract/database_statements.rb:219:in `within_new_transaction'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/connection_adapters/abstract/database_statements.rb:211:in `transaction'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/transactions.rb:208:in `transaction'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/transactions.rb:326:in `with_transaction_returning_status'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/activerecord-4.1.1/lib/active_record/persistence.rb:230:in `update'
    # ./app/models/spree/order_contents.rb:29:in `update_cart'
    # ./spec/models/spree/order_contents_spec.rb:127:in `block (3 levels) in '
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/example.rb:114:in `instance_eval'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/example.rb:114:in `block in run'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/example.rb:179:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/example.rb:179:in `run'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/extensions/instance_eval_with_args.rb:16:in `instance_exec'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/extensions/instance_eval_with_args.rb:16:in `instance_eval_with_args'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/example.rb:247:in `instance_eval_with_args'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/hooks.rb:106:in `block (2 levels) in run'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/hooks.rb:108:in `call'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/hooks.rb:108:in `run'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/hooks.rb:446:in `run_hook'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/example_group.rb:340:in `run_around_each_hooks'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/example.rb:256:in `with_around_each_hooks'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/example.rb:111:in `run'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/example_group.rb:390:in `block in run_examples'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/example_group.rb:386:in `map'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/example_group.rb:386:in `run_examples'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/example_group.rb:371:in `run'
    # /Users/ryanbigg/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/example_group.rb:372:in `block in run'

    View Slide

  15. # ./app/models/spree/stock/quantifier.rb:12 …

    # ./app/models/spree/order_contents.rb:29 …
    # ./spec/models/spree/order_contents_spec.rb:127 …

    View Slide

  16. AddVariant.perform(order, line_item)

    View Slide

  17. You don't need Rails.

    View Slide

  18. Sketch out ideas using Ruby.

    View Slide

  19. Plain Old Ruby Object

    View Slide

  20. Lotus is doing good things.
    http://github.com/lotus
    (but isn't quite there yet)

    View Slide

  21. View Slide

  22. View Slide

  23. You don't need Active Record.

    View Slide

  24. Use Sequel:

    View Slide

  25. sequel (4.12)
    >
    activerecord (4.1)

    View Slide

  26. Spree (2.3)
    >
    Magento (1.9)

    View Slide

  27. Chrome (35)
    >
    Firefox (30)
    >
    Opera (22)
    >
    IE (11)
    >
    Safari (6)

    View Slide

  28. Use Sequel:

    View Slide

  29. Extract out to a module:

    View Slide

  30. Test using "Fakes":

    View Slide

  31. Test using "Fakes":

    View Slide

  32. Using Sequel::Model

    View Slide

  33. Using Sequel::Model

    View Slide

  34. Spree PORO
    http://github.com/radar/spree_poro
    Finished in 0.04455 seconds
    52 examples, 0 failures

    View Slide

  35. Future Spree Core?
    Finished in 1 minute 11 seconds
    1321 examples, 0 failures

    View Slide

  36. Spree PORO
    http://github.com/radar/spree_poro
    Syd PORO
    http://github.com/radar/syd-poro

    View Slide