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

Trailblazer: One Year After 1.0 Release

Trailblazer: One Year After 1.0 Release

Would like to be up to date what happened last year on Trailblazer ecosystem? This is your chance to get all the fresh news in 45 minutes!

After the v1.0 release on Sep 25th, 2015 a lot of things has changed, if you have evaluated the framework and aren't using on a daily basis, now is the time to reevaluate as the framework (and all the gems that support it) matured.

Still not sure about it? Don't worry, I'm gonna show some patterns we have been using in our +30.000 LOC and 2 yo rails app.

78c0efd97053da279c3133324ebb9a3c?s=128

Celso Fernandes

September 23, 2016
Tweet

Transcript

  1. 1 Year After Release 1.0 Celso Fernandes

  2. Is Trailblazer for you? Celso Fernandes

  3. How it solved my problems! Celso Fernandes

  4. Agenda • Introduction • Quick Example • New Releases •

    Non Crud Example (Patterns)
  5. Introduction first some questions!

  6. QA ! QA Section

  7. QA ! Do you know (or have used), Trailblazer?

  8. QA ! In production?

  9. QA ! How many people don’t speak Portuguese?

  10. Introduction where everything begins…

  11. None
  12. None
  13. None
  14. None
  15. None
  16. None
  17. None
  18. 2015 25th Sept -> Release v1.0 2016 5th Apr ->

    First API change (deprecation, not yet removed)
  19. Rails • Productivity! • Happiness! • Stability!

  20. Rails • Productivity! • Happiness! • Stability! • …

  21. Rails • Productivity! • Happiness! • Stability! • ActiveRecord •

    Migrations • Query Interface
  22. Rails • Productivity! • Happiness! • Stability! • ActiveRecord •

    Migrations • Query Interface • ActiveSupport (Timezones)
  23. Rails • Productivity! • Happiness! • Stability! • ActiveRecord •

    Migrations • Query Interface • ActiveSupport (Timezones) • ActionCable
  24. Rails • Productivity! • Happiness! • Stability! • ActiveRecord •

    Migrations • Query Interface • ActiveSupport (Timezones) • ActionCable (!Scale)
  25. Rails • Productivity! • Happiness! • Stability! • ActiveRecord •

    Migrations • Query Interface • ActiveSupport (Timezones) • ActionCable • ActionView
  26. Rails • Productivity! • Happiness! • Stability! • ActiveRecord •

    Migrations • Query Interface • ActiveSupport (Timezones) • ActionCable • ActionView
  27. Rails Giant Shoulder!

  28. Rails Rails 5!

  29. None
  30. Routes resources  :sensors # config/routes.rb

  31. CRUD " Index

  32. Controller class  SensorsController  <  ApplicationController      def  index  

           present  Sensors::Index          render  html:  concept('sensors/cell',  @model).(:index)      end   end # app/controllers/sensors_controller.rb
  33. Operation class  Sensors::Index  <  Trailblazer::Operation      def  model!(params)  

           Sensor.all.includes(:measurable)              .page(params[:page]).per(params[:per])      end   end # app/concepts/sensors/index.rb
  34. Cell class  Sensors::Cell  <  Cell::Concept      include  Kaminari::Cells  

       #  Property      property  :name      property  :kind      def  index          render      end      #  Colection      def  row          render      end      private          def  blank?              model.empty?          end   end # app/concepts/sensors/cell.rb
  35. View <div  class="row">      <table>        

     <thead>              <tr>                  <th><%=  t(".name")  %></th>                  <th><%=  t(".kind")  %></th>                  <th></th>              </tr>          </thead>          <tbody>              <%  unless  blank?  %>              <%=  concept("sensors/cell",  collection:  model).(:row)  %>              <%  else  %>              <tr  class="warning"><td  colspan="8"  class="text-­‐center"><%=   t(".no_sensors_yet")  %></td></tr>              <%=  model.count  %>              <%  end  %>          </tbody>      </table>   </div>   <%=  paginate  view.sensors  %> # app/concepts/sensors/views/index.erb
  36. View <div    <        <    

           <                <                <                <            </        </        <            <%              <%=  concept(            <%              < t(".no_sensors_yet"            <%=  model.count  %>              <%          </    </ </div <%= # app/concepts/sensors/views/index.erb            <%=  concept("sensors/cell",  collection:  model).(:row)  %>  
  37. View <tr>      <td><%=  name  %></td>      <td><%=

     kind  %></td>      <td>          <%=  link_to  "Edit",  edit_sensor_path(locale:   params[:locale],  id:  id)          <%=  link_to  "Destroy",  sensor_path(locale:   params[:locale],  id:  id),   data:  {  confirm:  'Are  you  sure?'  },   method:  :delete,   remote:  true      </td>   </tr> # app/concepts/sensors/views/row.erb
  38. CRUD + Create

  39. Controller class  SensorsController  <  ApplicationController      def  new  

           form  Sensors::Create          render  html:  concept('sensors/cell',  @form).(:new)      end      def  create          run  Sensors::Create  do  |op|              return  respond_to  do  |format|                  format.js  {  redirect_to  sensors_url  }                  format.html  {  redirect_to  sensors_url  }              end          end          respond_to  do  |format|              format.js  {  render  html:  concept('sensors/cell',  @form).(:new),  status:  422  }              format.html  {  render  html:  concept('sensors/cell',  @form).(:new),  status:  422  }          end      end   end # app/controllers/sensors_controller.rb
  40. Turbolinks makes navigating your web application faster.

  41. View <%  @form_path  =  sensors_path(locale:  params[:locale])  %>   <%=  render

     'form'  %>   # app/concepts/sensors/new.erb
  42. View <div  class="row">      <%=  trailblazer_form_for  model,  url:  @form_path

     do  |f|  %>          <%=  f.text_field  :name  %>          <%=  f.select  :kind,  model.kind_options  %>          <%=  f.submit  %>      <%  end  %>   </div> # app/concepts/sensors/form.erb
  43. Operation class  Sensors::Create  <  Trailblazer::Operation      class  Contract  <

     Reform::Form          property  :name          property  :kind          validates  :name,  presence:  true          def  kind_options              Sensor::KONSTANT.map  {  |value|  [value.humanize,   value]}          end      end   end # app/concepts/sensors/contract/create.erb
  44. Operation require_dependency  'sensors/contract/create'   class  Sensors::Create  <  Trailblazer::Operation    

     include  Model      model  Sensor      contract  Contract      def  process(params)          validate(params[:sensor])  do  |contract|              contract.save          end      end   end # app/concepts/sensors/operation/create.erb
  45. Model class  Sensor  <  ApplicationRecord      KONSTANT  =  %w(abc

     def)   end # app/models/sensor.rb
  46. QA ! Where put validations?

  47. QA Where put validations?

  48. None
  49. Formular

  50. Formular =  form(model.contract,  url)  do  |f|      =  f.input

     :title,  placeholder:  "Title"      =  f.input  :url_slug,  placeholder:  "URL  slug" inputs
  51. Formular =  form(model.contract,  url)  do  |f|      .form-­‐group  

           =  f.checkbox  :is_public,  label:  “Public?”          =  f.checkbox  :roles,  collection:  [["Admin",   1],  ["Owner",  2],  ["Maintainer",  3]],  checked:   model.contract.roles,  label:  "Roles" checkbox
  52. Formular =  form(model.contract,  url)  do  |f|    .form-­‐group    

         =  f.radio  :owner,  label:  "Flori",  value:  1          =  f.radio  :owner,  label:  "Konsti",  value:  2      .row          .col-­‐md-­‐2              =  f.radio  :owner,  collection:  [["Flori",   1],  ["Konsti",  2]],  label:  "Owners"          .col-­‐md-­‐3              =  f.radio  :owner,  collection:  [["Flori",   1],  ["Konsti",  2]],  label:  "Owners,  inline",   inline:  true radio
  53. Formular =  form(model.contract,  url)  do  |f|      =  f.select

     :select_roles,            collection:  [["Admin",  1],  ["Owner",  2],   ["Maintainer",  3]],            selected:  model.contract.select_roles,            label:  "Selectable  Roles"   select
  54. Formular =  form(model.contract,  url)  do  |f|      .form-­‐group  

           =  f.textarea  :content,              placeholder:  "And  your  story...",  rows:  9   textarea
  55. Formular =  form(model.contract,  url)  do  |f|      .form-­‐group  

           =  f.button  type:  :submit,   value:  “Submit!”,   class:  [:btn,  :'btn-­‐lg',  :'btn-­‐default'] submit
  56. Tyrant

  57. Tyrant

  58. class  SessionController  <  AppController      def  sign_in    

         run  Tyrant::SignIn      end   end Tyrant
  59. Improvements • trailblazer-loader • Dry Validations on Reform • Dropped

    AV from Cells • Created http://trailblazer.to/ • Operation++
  60. Improvements • trailblazer-loader • Dry Validations on Reform • Dropped

    AV from Cells • Created http://trailblazer.to/ • Operation++
  61. trailblazer loader app   ├──  concepts   │    

     ├──  comment   │      │      ├──  callback.rb   │      │      ├──  cell.rb   │      │      ├──  contract.rb   │      │      ├──  operation.rb   │      │      ├──  policy.rb   │      │      └──  views   │      │              ├──  grid.haml   │      │              └──  show.haml Compound-Singular
  62. trailblazer loader app   ├──  concepts   │    

     ├──  comment   │      │      ├──  contract.rb   │      │      ├──  operation.rb   │      │      ├──  admin   │      │              ├──  contract.rb   │      │              └──  operation.rb Compound-Singular (Nested Concepts)
  63. trailblazer loader app   ├──  concepts   │    

     ├──  comment   │      │      ├──  contract   │      │      │      ├──  create.rb   │      │      │      └──  update.rb   │      │      ├──  cell   │      │      │      └──  form.rb   │      │      ├──  operation   │      │      │      ├──  create.rb   │      │      │      └──  update.rb   │      │      └──  views   │      │              ├──  grid.haml   │      │              └──  show.haml Explicit-Singular
  64. trailblazer loader app   ├──  concepts   │    

     ├──  comment   │      │      ├──  contract   │      │      │      ├──  create.rb   │      │      │      └──  update.rb   │      │      ├──  operation   │      │      │      ├──  create.rb   │      │      │      └──  update.rb   │      │      ├──  admin   │      │      │      └──  contract   │      │      │              ├──  create.rb   │      │      │              └──  update.rb Explicit-Singular (Nested)
  65. trailblazer loader app   ├──  concepts   │    

     ├──  comment   │      │      ├──  contracts   │      │      │      ├──  create.rb   │      │      │      └──  update.rb   │      │      ├──  cells   │      │      │      └──  form.rb   │      │      ├──  operations   │      │      │      ├──  create.rb   │      │      │      └──  update.rb   │      │      └──  views   │      │              ├──  grid.haml   │      │              └──  show.haml Explicit-Plural
  66. trailblazer loader app   ├──  concepts   │    

     ├──  comment   │      │      ├──  contracts   │      │      │      ├──  create.rb   │      │      │      └──  update.rb   │      │      ├──  operations   │      │      │      ├──  create.rb   │      │      │      └──  update.rb   │      │      ├──  admin   │      │      │      └──  contracts   │      │      │              ├──  create.rb   │      │      │              └──  update.rb Explicit-Plural (Nested)
  67. trailblazer loader gem  ‘trailblazer-­‐loader'   • trailblazer-rails • trailblazer-grape •

    trailblazer-roda • trailblazer-lotus
  68. Improvements • trailblazer-loader • Dry Validations on Reform • Dropped

    AV from Cells • Created http://trailblazer.to/ • Operation++
  69. Dry Validations require  "reform/form/dry"   Reform::Form.class_eval  do      feature

     Reform::Form::Dry   end
  70. Dry Validations • Validations Groups • Got rid of ActiveModel

  71. Improvements • trailblazer-loader • Dry Validations on Reform • Dropped

    AV from Cells • Created http://trailblazer.to/ • Operation++
  72. Dropped AV from Cells • https://apotonick.wordpress.com/ 2015/06/08/cells-4-0-goodbye-rails- hello-ruby/

  73. – Nick “We also got rid of ActionView. Replacing this

    jurassic gem with our own 30 lines rendering code has sped up rendering about 25%.”
  74. Improvements • trailblazer-loader • Dry Validations on Reform • Dropped

    AV from Cells • Created http://trailblazer.to/
  75. Improvements • trailblazer-loader • Dry Validations on Reform • Dropped

    AV from Cells • Created http://trailblazer.to/ • Operation++
  76. Operation++ • Added Operation::Callbacks • Added Operation::Policy • Added Operation::Resolver

    • Added Collections
  77. Operation++ • Added Operation::Callbacks • Added Operation::Policy • Added Operation::Resolver

    • Added Collections
  78. Operation++ class  Comment::Create  <  Trailblazer::Operation      callback  :after_save  do

             on_change  :notify!      end      callback  :after_save  do          on_change  :cleanup!      end   end  
  79. Operation++ • Added Operation::Callbacks • Added Operation::Policy • Added Operation::Resolver

    • Added Collections
  80. Operation++ class  Thing::Policy      def  initialize(user,  thing)    

         @user,  @thing  =  user,  thing      end      def  create?          admin?      end      def  admin?          @user.admin  ==  true      end      #  ..   end  
  81. Operation++ class  Thing::Create  <  Trailblazer::Operation      include  Trailblazer::Operation::Policy  

       policy  Thing::Policy,  :create?   end  
  82. Operation++ • Added Operation::Callbacks • Added Operation::Policy • Added Operation::Resolver

    • Added Collections
  83. Operation++ class  Thing::Create  <  Trailblazer::Operation      include  Resolver  

       policy  Thing::Policy,  :create?      model  Thing,  :create      builds  -­‐>  (model,  policy,  params)          return  Admin  if  policy.admin?          return  SignedIn  if  params[:current_user]      end   end  
  84. Operation++ • Added Operation::Callbacks • Added Operation::Policy • Added Operation::Resolver

    • Added Collections
  85. Operation++ class  Comment::Index  <  Trailblazer::Operation      include  Collection  

       def  model!(params)          Comment.all      end   end
  86. Frameworks Trailblazer with Rails Book | Repository Trailblazer with Sinatra

    Guide | Repository Trailblazer with Hanami - coming soon! Trailblazer with Roda - coming soon! Trailblazer with Grape - coming very soon!
  87. Frameworks Trailblazer with Rails Book | gemgem-trbrb Trailblazer with Sinatra

    Guide | gemgem-sinatra Trailblazer with Hanami - gemgem-hanami Trailblazer with Roda - coming soon! Trailblazer with Grape - coming very soon!
  88. Dreamstack

  89. Frameworks # Gems gem 'cells-erb', '~> 0.0' gem 'cells-rails', '~>

    0.0' gem 'kaminari-cells' gem 'reform', '~> 2.2' gem 'reform-rails', '~> 0.1' gem 'trailblazer', '~> 1.1' gem 'trailblazer-cells', '~> 0.0' gem 'trailblazer-rails', '~> 0.2'
  90. Frameworks All Rails-relevant files are now in the trailblazer-rails gem.

    You have to include it should you be in a Rails environment. roar-rails # Dec 29, 2011 reform-rails # Aug 15, 2015 trailblazer-rails # Sep 4, 2015 cells-rails # Feb 17, 2016
  91. Other Languages

  92. Patterns

  93. None
  94. ◦ be rake stats +----------------------+-------+-------+---------+---------+-----+-------+ | Name | Lines |

    LOC | Classes | Methods | M/C | LOC/M | +----------------------+-------+-------+---------+---------+-----+-------+ | Controllers | 1711 | 1439 | 102 | 148 | 1 | 7 | | Helpers | 248 | 216 | 1 | 31 | 31 | 4 | | Jobs | 31 | 28 | 1 | 2 | 2 | 12 | | Models | 7050 | 3560 | 125 | 461 | 3 | 5 | | Mailers | 0 | 0 | 0 | 0 | 0 | 0 | | Javascripts | 1232 | 968 | 0 | 157 | 0 | 4 | | Libraries | 2607 | 2600 | 3 | 8 | 2 | 323 | | Controller tests | 3313 | 2890 | 52 | 35 | 0 | 80 | | Helper tests | 267 | 219 | 7 | 13 | 1 | 14 | | Model tests | 7516 | 4294 | 83 | 60 | 0 | 69 | | Mailer tests | 0 | 0 | 0 | 0 | 0 | 0 | | Job tests | 47 | 41 | 1 | 1 | 1 | 39 | | Integration tests | 1143 | 950 | 8 | 4 | 0 | 235 | | Cucumber features | 338 | 248 | 0 | 2 | 0 | 122 | | Concepts | 4645 | 3866 | 245 | 608 | 2 | 4 | | Concepts Tests | 4136 | 3420 | 139 | 21 | 0 | 160 | +----------------------+-------+-------+---------+---------+-----+-------+ | Total | 34284 | 24739 | 767 | 1551 | 2 | 13 | +----------------------+-------+-------+---------+---------+-----+-------+ Code LOC: 12677 Test LOC: 12062 Code to Test Ratio: 1:1.0
  95. ◦ be rake stats +----------------------+-------+-------+---------+---------+-----+-------+ | Name | Lines |

    LOC | Classes | Methods | M/C | LOC/M | +----------------------+-------+-------+---------+---------+-----+-------+ | Controllers | 1711 | 1439 | 102 | 148 | 1 | 7 | | Helpers | 248 | 216 | 1 | 31 | 31 | 4 | | Jobs | 31 | 28 | 1 | 2 | 2 | 12 | | Models | 7050 | 3560 | 125 | 461 | 3 | 5 | | Mailers | 0 | 0 | 0 | 0 | 0 | 0 | | Javascripts | 1232 | 968 | 0 | 157 | 0 | 4 | | Libraries | 2607 | 2600 | 3 | 8 | 2 | 323 | | Controller tests | 3313 | 2890 | 52 | 35 | 0 | 80 | | Helper tests | 267 | 219 | 7 | 13 | 1 | 14 | | Model tests | 7516 | 4294 | 83 | 60 | 0 | 69 | | Mailer tests | 0 | 0 | 0 | 0 | 0 | 0 | | Job tests | 47 | 41 | 1 | 1 | 1 | 39 | | Integration tests | 1143 | 950 | 8 | 4 | 0 | 235 | | Cucumber features | 338 | 248 | 0 | 2 | 0 | 122 | | Concepts | 4645 | 3866 | 245 | 608 | 2 | 4 | | Concepts Tests | 4136 | 3420 | 139 | 21 | 0 | 160 | +----------------------+-------+-------+---------+---------+-----+-------+ | Total | 34284 | 24739 | 767 | 1551 | 2 | 13 | +----------------------+-------+-------+---------+---------+-----+-------+ Code LOC: 12677 Test LOC: 12062 Code to Test Ratio: 1:1.0
  96. ◦ be rake stats +----------------------+-------+-------+---------+---------+-----+-------+ | Name | Lines |

    LOC | Classes | Methods | M/C | LOC/M | +----------------------+-------+-------+---------+---------+-----+-------+ | Controllers | 1711 | 1439 | 102 | 148 | 1 | 7 | | Helpers | 248 | 216 | 1 | 31 | 31 | 4 | | Jobs | 31 | 28 | 1 | 2 | 2 | 12 | | Models | 7050 | 3560 | 125 | 461 | 3 | 5 | | Mailers | 0 | 0 | 0 | 0 | 0 | 0 | | Javascripts | 1232 | 968 | 0 | 157 | 0 | 4 | | Libraries | 2607 | 2600 | 3 | 8 | 2 | 323 | | Controller tests | 3313 | 2890 | 52 | 35 | 0 | 80 | | Helper tests | 267 | 219 | 7 | 13 | 1 | 14 | | Model tests | 7516 | 4294 | 83 | 60 | 0 | 69 | | Mailer tests | 0 | 0 | 0 | 0 | 0 | 0 | | Job tests | 47 | 41 | 1 | 1 | 1 | 39 | | Integration tests | 1143 | 950 | 8 | 4 | 0 | 235 | | Cucumber features | 338 | 248 | 0 | 2 | 0 | 122 | | Concepts | 4645 | 3866 | 245 | 608 | 2 | 4 | | Concepts Tests | 4136 | 3420 | 139 | 21 | 0 | 160 | +----------------------+-------+-------+---------+---------+-----+-------+ | Total | 34284 | 24739 | 767 | 1551 | 2 | 13 | +----------------------+-------+-------+---------+---------+-----+-------+ Code LOC: 12677 Test LOC: 12062 Code to Test Ratio: 1:1.0
  97. ◦ be rake stats +----------------------+-------+-------+---------+---------+-----+-------+ | Name | Lines |

    LOC | Classes | Methods | M/C | LOC/M | +----------------------+-------+-------+---------+---------+-----+-------+ | Controllers | 1711 | 1439 | 102 | 148 | 1 | 7 | | Helpers | 248 | 216 | 1 | 31 | 31 | 4 | | Jobs | 31 | 28 | 1 | 2 | 2 | 12 | | Models | 7050 | 3560 | 125 | 461 | 3 | 5 | | Mailers | 0 | 0 | 0 | 0 | 0 | 0 | | Javascripts | 1232 | 968 | 0 | 157 | 0 | 4 | | Libraries | 2607 | 2600 | 3 | 8 | 2 | 323 | | Controller tests | 3313 | 2890 | 52 | 35 | 0 | 80 | | Helper tests | 267 | 219 | 7 | 13 | 1 | 14 | | Model tests | 7516 | 4294 | 83 | 60 | 0 | 69 | | Mailer tests | 0 | 0 | 0 | 0 | 0 | 0 | | Job tests | 47 | 41 | 1 | 1 | 1 | 39 | | Integration tests | 1143 | 950 | 8 | 4 | 0 | 235 | | Cucumber features | 338 | 248 | 0 | 2 | 0 | 122 | | Concepts | 4645 | 3866 | 245 | 608 | 2 | 4 | | Concepts Tests | 4136 | 3420 | 139 | 21 | 0 | 160 | +----------------------+-------+-------+---------+---------+-----+-------+ | Total | 34284 | 24739 | 767 | 1551 | 2 | 13 | +----------------------+-------+-------+---------+---------+-----+-------+ Code LOC: 12677 Test LOC: 12062 Code to Test Ratio: 1:1.0
  98. ◦ be rake stats +----------------------+-------+-------+---------+---------+-----+-------+ | Name | Lines |

    LOC | Classes | Methods | M/C | LOC/M | +----------------------+-------+-------+---------+---------+-----+-------+ | Controllers | 1711 | 1439 | 102 | 148 | 1 | 7 | | Helpers | 248 | 216 | 1 | 31 | 31 | 4 | | Jobs | 31 | 28 | 1 | 2 | 2 | 12 | | Models | 7050 | 3560 | 125 | 461 | 3 | 5 | | Mailers | 0 | 0 | 0 | 0 | 0 | 0 | | Javascripts | 1232 | 968 | 0 | 157 | 0 | 4 | | Libraries | 2607 | 2600 | 3 | 8 | 2 | 323 | | Controller tests | 3313 | 2890 | 52 | 35 | 0 | 80 | | Helper tests | 267 | 219 | 7 | 13 | 1 | 14 | | Model tests | 7516 | 4294 | 83 | 60 | 0 | 69 | | Mailer tests | 0 | 0 | 0 | 0 | 0 | 0 | | Job tests | 47 | 41 | 1 | 1 | 1 | 39 | | Integration tests | 1143 | 950 | 8 | 4 | 0 | 235 | | Cucumber features | 338 | 248 | 0 | 2 | 0 | 122 | | Concepts | 4645 | 3866 | 245 | 608 | 2 | 4 | | Concepts Tests | 4136 | 3420 | 139 | 21 | 0 | 160 | +----------------------+-------+-------+---------+---------+-----+-------+ | Total | 34284 | 24739 | 767 | 1551 | 2 | 13 | +----------------------+-------+-------+---------+---------+-----+-------+ Code LOC: 12677 Test LOC: 12062 Code to Test Ratio: 1:1.0
  99. Gemfile # Gems gem 'cells-erb', '~> 0.0' gem 'cells-rails', '~>

    0.0' gem 'kaminari-cells' gem 'reform', '~> 2.2' gem 'reform-rails', '~> 0.1' gem 'trailblazer', '~> 1.1' gem 'trailblazer-cells', '~> 0.0' gem 'trailblazer-rails', '~> 0.2'
  100. Case

  101. Case

  102. Case

  103. Case

  104. Case

  105. Case

  106. Case

  107. Cells!

  108. Web Concept!

  109. Form!

  110. Web Concept!

  111. Link (remote: true)

  112. File Structure app/concepts/home.rb (namespace) app/concepts/home/cell.rb app/concepts/home/views/show.erb app/concepts/home/views/locales/{en,pt-BR}.yml app/concepts/home/cell/new_tweets.rb app/concepts/home/cell/new_tweets/views/show.erb app/concepts/home/cell/profile.rb

    app/concepts/home/cell/profile/views/show.erb app/concepts/home/cell/trends.rb app/concepts/home/cell/trends/views/show.erb app/concepts/home/cell/tweets.rb app/concepts/home/cell/tweets/views/show.erb app/concepts/home/cell/who_follow.rb app/concepts/home/cell/who_follow/views/show.erb
  113. Cells!

  114. File Structure app/concepts/home/operation/show.rb app/concepts/home/operation/create.rb app/concepts/home/contract/create.rb app/concepts/home/operation/refresh.rb

  115. File Structure app/controllers/home_controller.rb app/model/person.rb app/model/person/create.rb app/model/tweet.rb app/model/tweet/create.rb app/model/trend.rb app/model/trend/create.rb

  116. File Structure Inside app/models Model::(Substantive || Verb) Substantive is a

    model Verb is an operation
  117. config/routes.rb post  "/tweet",  controller:  "home",  action:  "create"   get  "/refresh",

     controller:  "home",  action:  "refresh"   root  to:  "home#show"
  118. HomeController class  HomeController  <  ApplicationController      def  show  

           present  Home::Show          render_cell      end      def  create          run  Home::Create  do  |op|              return  respond_to  do  |format|                  format.js  {  redirect_to  root_path  }                  format.html  {  redirect_to  root_path  }              end          end          respond_to  do  |format|              format.js  {  render_cell("home/tweet/cell",  @form)  }              format.html  {  render_cell("home/tweet/cell",  @form)  }          end      end      def  refresh          present  Home::Refresh          respond_to  do  |format|              format.js  {  render_cell("home/cell",  @model,  action_name:  "show")  }              format.html  {  render_cell("home/cell",  @model,  action_name:  "show")  }          end      end   end
  119. HomeController class    def        present    

         render_cell      end    def        run                              format.js  {  redirect_to  root_path  }                  format.html  {  redirect_to  root_path  }                      end        respond_to              format.js  {  render_cell(            format.html  {  render_cell(        end    end    def        present          respond_to              format.js  {  render_cell(            format.html  {  render_cell(        end    end   end    def  show          present  Home::Show          render_cell      end  
  120. HomeController class    def        present    

         render_cell      end    def        run                              format.js  {  redirect_to  root_path  }                  format.html  {  redirect_to  root_path  }                      end        respond_to              format.js  {  render_cell(            format.html  {  render_cell(        end    end    def        present          respond_to              format.js  {  render_cell(            format.html  {  render_cell(        end    end   end        render_cell  
  121. HomeController class    def        present    

         render_cell      end    def        run                              format.js  {  redirect_to  root_path  }                  format.html  {  redirect_to  root_path  }                      end        respond_to              format.js  {  render_cell(            format.html  {  render_cell(        end    end    def        present          respond_to              format.js  {  render_cell(            format.html  {  render_cell(        end    end   end    def  create          run  Home::Create  do  |op|              return  respond_to  do  |format|                  format.js  {  redirect_to  root_path  }                  format.html  {  redirect_to  root_path  }              end          end          respond_to  do  |format|              format.js  {  render_cell("home/tweet/cell",  @form)  }              format.html  {  render_cell("home/tweet/cell",  @form)  }          end      end  
  122. HomeController class    def        present    

         render_cell      end    def        run                              format.js  {  redirect_to  root_path  }                  format.html  {  redirect_to  root_path  }                      end        respond_to              format.js  {  render_cell(            format.html  {  render_cell(        end    end    def        present          respond_to              format.js  {  render_cell(            format.html  {  render_cell(        end    end   end                format.js  {  redirect_to  root_path  }              format.js  {  render_cell("home/tweet/cell",  @form)  }  
  123. HomeController class    def        present    

         render_cell      end    def        run                              format.js  {  redirect_to  root_path  }                  format.html  {  redirect_to  root_path  }                      end        respond_to              format.js  {  render_cell(            format.html  {  render_cell(        end    end    def        present          respond_to              format.js  {  render_cell(            format.html  {  render_cell(        end    end   end    def  refresh          present  Home::Refresh          respond_to  do  |format|              format.js  {  render_cell("home/cell",  @model,  action_name:  "show")  }              format.html  {  render_cell("home/cell",  @model,  action_name:  "show")  }          end      end  
  124. HomeController class    def        present    

         render_cell      end    def        run                              format.js  {  redirect_to  root_path  }                  format.html  {  redirect_to  root_path  }                      end        respond_to              format.js  {  render_cell(            format.html  {  render_cell(        end    end    def        present          respond_to              format.js  {  render_cell(            format.html  {  render_cell(        end    end   end        present  Home::Refresh              format.js  {  render_cell("home/cell",  @model,  action_name:  "show")  }  
  125. ApplicationController class  ApplicationController  <  ActionController::Base      before_filter  :set_current_user  

       def  render_cell(name  =  nil,  model=nil,  options={},  &block)          name  =  cell_name(name)          model  =  cell_model(model)          action_name  =  cell_action(options)          render  html:  concept(name,  model,  options).(action_name),  layout:  options.fetch(:layout,  current_layout),  status:  options.fetch(:status,  200)      end      private          def  cell_name(name)              self.class.to_s.underscore.gsub(/_controller\z/,  '')  +  "/cell"  if  name.nil?          end          def  cell_model(model)              model  =  @model  if  model.nil?              model  =  @collection  if  model.nil?          end          def  cell_action(options)              action_name  =  options.delete(:action_name)  if  options.has_key?(:action_name)              action_name  =  @_action_name.to_sym  if  action_name.nil?          end          def  current_layout              current_layout_set  =  self.send(:_layout,  [:html])              return  current_layout_set  if  current_layout_set.is_a?(String)              return  current_layout_set.virtual_path  if  current_layout_set.is_a?(ActionView::Template)              (self.send(:_layout,  [:html])).identifier.split("/").last.gsub(/.html.erb/,"")          end          def  set_current_user              params[:current_user]  =  (current_user.nil?  ?  nil  :  current_user)          end   end
  126. class  ApplicationController  <  ActionController::Base    before_filter      def  render_cell

           name  =        model          action_name          render      end      private          def  cell_name            self        end          def  cell_model            model              model          end          def  cell_action            action_name              action_name          end          def  current_layout              current_layout_set              return            return            (self        end          def  set_current_user              params[        end   end    before_filter  :set_current_user          def  set_current_user              params[:current_user]  =  (current_user.nil?  ?  nil  :  current_user)          end   ApplicationController
  127. class  ApplicationController  <  ActionController::Base    before_filter      def  render_cell

           name  =        model          action_name          render      end      private          def  cell_name            self        end          def  cell_model            model              model          end          def  cell_action            action_name              action_name          end          def  current_layout              current_layout_set              return            return            (self        end          def  set_current_user              params[        end   end    def  render_cell(name  =  nil,  model=nil,  options={},  &block)          name  =  cell_name(name)          model  =  cell_model(model)          action_name  =  cell_action(options)          render  html:  concept(name,  model,  options).(action_name),  layout:  options.fetch(:layout,  current_layout),  status:  options.fetch(:status,  200)      end   ApplicationController
  128. class  ApplicationController  <  ActionController::Base    before_filter      def  render_cell

           name  =        model          action_name          render      end      private          def  cell_name            self        end          def  cell_model            model              model          end          def  cell_action            action_name              action_name          end          def  current_layout              current_layout_set              return            return            (self        end          def  set_current_user              params[        end   end        name  =  cell_name(name)          model  =  cell_model(model)          action_name  =  cell_action(options)                                                                                                                                                                                            current_layout                  cell_name(name)                  cell_model(model)                  cell_action(options)                  current_layout   ApplicationController
  129. class  ApplicationController  <  ActionController::Base    before_filter      def  render_cell

           name  =        model          action_name          render      end      private          def  cell_name            self        end          def  cell_model            model              model          end          def  cell_action            action_name              action_name          end          def  current_layout              current_layout_set              return            return            (self        end          def  set_current_user              params[        end   end        render  html:  concept(name,  model,  options).(action_name),  layout:  options.fetch(:layout,  current_layout),  status:  options.fetch(:status,  200)   ApplicationController
  130. Home::Show Operation class  Home::Show  <  Trailblazer::Operation      def  model!(params)

             view_store(:new_tweets,  new_tweets)          view_store(:profile,  profile)          view_store(:trends,  trends)          view_store(:tweets,  tweets)          view_store(:who_follow,  who_follow)      end      def  trends      end      ...   end  
  131. Operation Monkey Patch ( :P ) require  'trailblazer/operation'   class

     Trailblazer::Operation      attr_reader  :view      def  view_store(key,  object)          @view  =  OpenStruct.new  if  @view.nil?          @view.send("#{key}=",  object)      end   end
  132. Operation View class  Trailblazer::Operation::View      attr_reader  :view    

     def  view_store(key,  object)          @view  =  OpenStruct.new  if  @view.nil?          @view.send("#{key}=",  object)      end   end
  133. Inside Home::Show Cell concept("home/cell/new_tweets",  view.new_tweets)   concept("home/cell/profile",  view.profile)   concept("home/cell/trends",

     view.trends)   concept("home/cell/tweets",  view.tweets)   concept("home/cell/who_follow",  view.who_follow)
  134. Cell Monkey Patch! require  'cell/concept'   module  Cell    

     class  Concept  <  Cell::ViewModel          def  self.locale_file!              cell_name  =  self.to_s.underscore.gsub(/\/cell/,  '')              ::Rails.application.config.i18n.load_path  +=                  Dir[::Rails.root.join(                      'app',  'concepts',  cell_name,  'views',  'locales',   ‘*.{rb,yml}'                  )]          end      end   end
  135. Application Cell module  Cell::App      def  self.included(subclass)    

         subclass.include  ApplicationHelper          subclass.include  Cell::Translation          translation_path  =  define_translation_path          subclass.locale_file!      end      def  view          operation.try(:view)      end      private          def  operation              controller.instance_variable_get(:@operation)          end          def  contract              controller.instance_variable_get(:@operation).try(:contract)          end   end
  136. Case

  137. Obrigado!