SlideShare a Scribd company logo
Moving ActiveRecord
objects to the
boundaries of your
domain
@PatrickDougall
Patrick Dougall
https://github.com/pdougall1
Get in the mood
Quick Overview
How do I do this!?
What am I doing?!
Logic all over
the place!
Models
Views
Controllers
AR Models
First thing I learned
Fat Models / Skinny Controllers
AR Models
Views
Controllers
Fat Models / Skinny ControllersSo now you say Domain?
AR Models
Views
Controllers
AR Models
Views
Controllers
AR Models
Views
Controllers
Domain
Ok, so what is domain?
Ok, so what is domain?
The work that this application needs to do
for the domain you’re working with.
• Involves calculations based on input and
stored data
• Validation of any data that comes in from the
presentation layer
• figuring out what data source logic to
dispatch.
Ok, so what is domain?
We’ll practice a little
1. AR objects go into an AR directory
2. associations are ok, but only one level deep
(through only one joins table)
3. NO OTHER METHODS
But I have no self control!
we’ll have rules
Overview of data model
The work that this application needs to do
for the domain you’re working with.
• Involves calculations based on input and
stored data
• Validation of any data that comes in from the
presentation layer
• figuring out what data source logic to
dispatch.
Ok, so what is domain?
query object
@projects = Project.where(active: true)
def index
end
Active Projects
class Project < ActiveRecord::Base
has_many :project_user_roles
has_many :users, through: :project_user_roles
has_many :operations
endscope :active, -> { where(active: true) }
@projects = Project.active
def index
end
Active Projects
@projects = ActiveProjects.new
class ActiveProjects < SimpleDelegator
def initialize(project_factory: AR::Project)
super project_factory.where(active: true)
end
end
But it often things are a
little different
Need a user page
SELECT "users".*
FROM "users"
WHERE "users"."id" = 1
module AR
class User < ActiveRecord::Base
end
end
def show
@user = AR::User.find(params[:id])
end
SELECT "projects".*
FROM "projects"
INNER JOIN "project_user_roles"
ON "projects"."id" =
"project_user_roles"."project_id"
WHERE "project_user_roles"."user_id" = 1
Also a projects list
def show
@user = AR::User.find(params[:id])@projects = @user.projects
end
has_many :project_user_roles
has_many :projects, through: :project_user_roles
module AR
class User < ActiveRecord::Base
end
end
SELECT "operations".*
FROM "operations"
INNER JOIN "projects"
ON "projects"."id" = "operations"."project_id"
INNER JOIN "project_user_roles"
ON "project_user_roles"."project_id" = "projects"."id"
INNER JOIN "users"
ON "users"."id" = "project_user_roles"."user_id"
WHERE "users"."id" = 1
Also an operations list
def show
@user = AR::User.find(params[:id])
@projects = @user.projects
end @operations = @user.operations
has_many :project_user_roles
has_many :projects, through: :project_user_roles
has_many :operations, through: :projects,
source: :operations
SELECT "operations".*
FROM "operations"
INNER JOIN "projects"
ON "projects"."id" = "operations"."project_id"
INNER JOIN "project_user_roles"
ON "project_user_roles"."project_id" =
"projects"."id"
WHERE "project_user_roles"."user_id" = 1
def get_operations_scope(user)
@operation_scope
.joins(project: :project_user_roles)
.where(project_user_roles: { user_id: user.id })
end
def get_operations_scope(user)
@operation_scope
.joins(project: :project_user_roles)
.where(project_user_roles: { user_id: user.id })
end
module Query
class UserOperations < SimpleDelegator
def initialize(user, operation_scope: AR::Operation)
@operation_scope = operation_scope
super get_operations_scope(user)
end
end
end
Need an operations list
def show
@user = AR::User.find(params[:id])
@projects = @user.projects
end@operations = UserOperations.new(@user)
def show
@user = AR::User.find(params[:id])
@projects = @user.projects
end
@operations = UserOperations.new(@user)
operations listNeed an
def get_operations_scope(user)
@operation_scope
.joins(project: :project_user_roles)
.where(project_user_roles: { user_id: user.id })
end
operations listNeed an
SELECT "operations".*
FROM "operations"
INNER JOIN "projects"
ON "projects"."id" = "operations"."project_id"
INNER JOIN "project_user_roles"
ON "project_user_roles"."project_id" =
"projects"."id"
WHERE "project_user_roles"."user_id" = 1
SELECT "operations".*
FROM "operations"
INNER JOIN "projects"
ON "projects"."id" = "operations"."project_id"
INNER JOIN "project_user_roles"
ON "project_user_roles"."project_id" =
"projects"."id"
INNER JOIN "roles"
ON "roles"."id" = "project_user_roles"."role_id"
WHERE "project_user_roles"."user_id" = 1
AND "roles"."name" = "admin
operations list
def show
@user = AR::User.find(params[:id])
@projects = @user.projects
end
@operations = UserOperations.new(@user)
def get_operations_scope(user)
@operation_scope
.joins(project: :project_user_roles)
.where(project_user_roles: { user_id: user.id })
Need anactive
end .where(projects: { active: true })
.where(projects: { active: true })
.joins(project: :project_user_roles)
.where(roles: { name: “admin” })
def get_operations_scope(user)
@operation_scope
end
.joins(operation: { project: {
project_user_roles: :role
}})
.where(project_user_roles: { user_id: user.id })
SELECT "operations".*
FROM "operations"
INNER JOIN "projects"
ON "projects"."id" = "operations"."project_id"
INNER JOIN "project_user_roles"
ON "project_user_roles"."project_id" =
"projects"."id"
INNER JOIN "roles"
ON "roles"."id" = "project_user_roles"."role_id"
WHERE "project_user_roles"."user_id" = 1
AND "roles"."name" = "admin
def show
@user = AR::User.find(params[:id])
@projects = @user.projects
end
@operations = UserOperations.new(@user)
operations listNeed an active for admin
def get_operations_scope(user)
@operation_scope
.joins(project: {
project_user_roles: :role
})
.where(project_user_roles: { user_id: user.id })
.where(roles: { name: "admin" })
end
SELECT "operations".*
FROM "operations"
INNER JOIN "projects"
ON "projects"."id" = "operations"."project_id"
INNER JOIN "project_user_roles"
ON "project_user_roles"."project_id" =
"projects"."id"
INNER JOIN "roles"
ON "roles"."id" = "project_user_roles"."role_id"
WHERE "project_user_roles"."user_id" = 1
AND "roles"."name" = "admin
The work that this application needs to do
for the domain you’re working with.
• Involves calculations based on input and
stored data
• Validation of any data that comes in from the
presentation layer
• figuring out what data source logic to
dispatch.
Ok, so what is domain?
query object
form object
Need a new User
def new
@user = AR::User.new
end
class User < ActiveRecord::Base
endvalidates_presence_of :first_name,
:last_name,
:email
Need a new User
def new
end
@user = Form::User.new
class User
include ActiveModel::Model
validates_presence_of :first_name,
:last_name,
:email
end
The work that this application needs to do
for the domain you’re working with.
• Involves calculations based on input and
stored data
• Validation of any data that comes in from the
presentation layer
• figuring out what data source logic to
dispatch.
Ok, so what is domain?
query object
form object
PORO ?
• Less likely to create god object
• Naturally ends up in their own objects
• Easier to understand our objects
Why is this good?
1. OOP 2015 Keynote - Robert C. Martin ("Uncle Bob"): Agility and Architecture
• https://www.youtube.com/watch?v=0oGpWmS0aYQ
2. Martin Fowler: Patterns of Enterprise Architecture
• http://martinfowler.com/books/eaa.html
References

More Related Content

What's hot

Spring batch
Spring batchSpring batch
Spring batch
Wayan Wira
 
Fewd week6 slides
Fewd week6 slidesFewd week6 slides
Fewd week6 slides
William Myers
 
A To-do Web App on Google App Engine
A To-do Web App on Google App EngineA To-do Web App on Google App Engine
A To-do Web App on Google App Engine
Michael Parker
 
Excellent
ExcellentExcellent
Excellent
Marco Otte-Witte
 
Rails is not just Ruby
Rails is not just RubyRails is not just Ruby
Rails is not just Ruby
Marco Otte-Witte
 
Angular Js Basics
Angular Js BasicsAngular Js Basics
Angular Js Basics
أحمد عبد الوهاب
 
Angular js
Angular jsAngular js
Angular js
Eueung Mulyana
 
The basics of Ember Objects
The basics of Ember ObjectsThe basics of Ember Objects
The basics of Ember Objects
Jason Schmidt
 
JavaScript Abstraction
JavaScript AbstractionJavaScript Abstraction
JavaScript Abstraction
☆ Milan Adamovsky ☆
 
Owl: The New Odoo UI Framework
Owl: The New Odoo UI FrameworkOwl: The New Odoo UI Framework
Owl: The New Odoo UI Framework
Odoo
 
Angular2 & ngrx/store: Game of States
Angular2 & ngrx/store: Game of StatesAngular2 & ngrx/store: Game of States
Angular2 & ngrx/store: Game of States
Oren Farhi
 
Spring boot
Spring boot Spring boot
Spring boot
Vinay Prajapati
 
Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]
Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]
Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]
Iakiv Kramarenko
 

What's hot (13)

Spring batch
Spring batchSpring batch
Spring batch
 
Fewd week6 slides
Fewd week6 slidesFewd week6 slides
Fewd week6 slides
 
A To-do Web App on Google App Engine
A To-do Web App on Google App EngineA To-do Web App on Google App Engine
A To-do Web App on Google App Engine
 
Excellent
ExcellentExcellent
Excellent
 
Rails is not just Ruby
Rails is not just RubyRails is not just Ruby
Rails is not just Ruby
 
Angular Js Basics
Angular Js BasicsAngular Js Basics
Angular Js Basics
 
Angular js
Angular jsAngular js
Angular js
 
The basics of Ember Objects
The basics of Ember ObjectsThe basics of Ember Objects
The basics of Ember Objects
 
JavaScript Abstraction
JavaScript AbstractionJavaScript Abstraction
JavaScript Abstraction
 
Owl: The New Odoo UI Framework
Owl: The New Odoo UI FrameworkOwl: The New Odoo UI Framework
Owl: The New Odoo UI Framework
 
Angular2 & ngrx/store: Game of States
Angular2 & ngrx/store: Game of StatesAngular2 & ngrx/store: Game of States
Angular2 & ngrx/store: Game of States
 
Spring boot
Spring boot Spring boot
Spring boot
 
Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]
Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]
Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]
 

Viewers also liked

Tentang ruju
Tentang rujuTentang ruju
Tentang ruju
Septian Muna Barakati
 
Lakey | Hogelin
Lakey | HogelinLakey | Hogelin
Lakey | Hogelin
benjamin4312
 
Maciej Szymanowicz, European Commission @ Frankfurt Book Fair 2015, TISP work...
Maciej Szymanowicz, European Commission @ Frankfurt Book Fair 2015, TISP work...Maciej Szymanowicz, European Commission @ Frankfurt Book Fair 2015, TISP work...
Maciej Szymanowicz, European Commission @ Frankfurt Book Fair 2015, TISP work...
TISP Project
 
Kitab ilmu
Kitab ilmuKitab ilmu
Proposal wisataaa
Proposal wisataaaProposal wisataaa
Proposal wisataaa
Septian Muna Barakati
 
Prezentare Generala SkiBus 2015
Prezentare Generala SkiBus 2015Prezentare Generala SkiBus 2015
Prezentare Generala SkiBus 2015
Florian Coman
 
Lucie McLean — Come Together: Building Product Culture in Non-Digital Organis...
Lucie McLean — Come Together: Building Product Culture in Non-Digital Organis...Lucie McLean — Come Together: Building Product Culture in Non-Digital Organis...
Lucie McLean — Come Together: Building Product Culture in Non-Digital Organis...
Turing Fest
 

Viewers also liked (7)

Tentang ruju
Tentang rujuTentang ruju
Tentang ruju
 
Lakey | Hogelin
Lakey | HogelinLakey | Hogelin
Lakey | Hogelin
 
Maciej Szymanowicz, European Commission @ Frankfurt Book Fair 2015, TISP work...
Maciej Szymanowicz, European Commission @ Frankfurt Book Fair 2015, TISP work...Maciej Szymanowicz, European Commission @ Frankfurt Book Fair 2015, TISP work...
Maciej Szymanowicz, European Commission @ Frankfurt Book Fair 2015, TISP work...
 
Kitab ilmu
Kitab ilmuKitab ilmu
Kitab ilmu
 
Proposal wisataaa
Proposal wisataaaProposal wisataaa
Proposal wisataaa
 
Prezentare Generala SkiBus 2015
Prezentare Generala SkiBus 2015Prezentare Generala SkiBus 2015
Prezentare Generala SkiBus 2015
 
Lucie McLean — Come Together: Building Product Culture in Non-Digital Organis...
Lucie McLean — Come Together: Building Product Culture in Non-Digital Organis...Lucie McLean — Come Together: Building Product Culture in Non-Digital Organis...
Lucie McLean — Come Together: Building Product Culture in Non-Digital Organis...
 

Similar to Moving ActiveRecord objects to the boundaries of your domain

Little Opinions, Big Possibilities: The Tools and Patterns for Building Larg...
 Little Opinions, Big Possibilities: The Tools and Patterns for Building Larg... Little Opinions, Big Possibilities: The Tools and Patterns for Building Larg...
Little Opinions, Big Possibilities: The Tools and Patterns for Building Larg...
Brian Mann
 
Ember.js - A JavaScript framework for creating ambitious web applications
Ember.js - A JavaScript framework for creating ambitious web applications  Ember.js - A JavaScript framework for creating ambitious web applications
Ember.js - A JavaScript framework for creating ambitious web applications
Juliana Lucena
 
Controller in AngularJS
Controller in AngularJSController in AngularJS
Controller in AngularJS
Brajesh Yadav
 
Ruby/Rails
Ruby/RailsRuby/Rails
Ruby/Rails
rstankov
 
From Legacy to Hexagonal (An Unexpected Android Journey)
From Legacy to Hexagonal (An Unexpected Android Journey)From Legacy to Hexagonal (An Unexpected Android Journey)
From Legacy to Hexagonal (An Unexpected Android Journey)
Jose Manuel Pereira Garcia
 
OData Introduction and Impact on API Design (Webcast)
OData Introduction and Impact on API Design (Webcast)OData Introduction and Impact on API Design (Webcast)
OData Introduction and Impact on API Design (Webcast)
Apigee | Google Cloud
 
Crossing the Bridge: Connecting Rails and your Front-end Framework
Crossing the Bridge: Connecting Rails and your Front-end FrameworkCrossing the Bridge: Connecting Rails and your Front-end Framework
Crossing the Bridge: Connecting Rails and your Front-end Framework
Daniel Spector
 
What's New in Jira Cloud for Developers
What's New in Jira Cloud for DevelopersWhat's New in Jira Cloud for Developers
What's New in Jira Cloud for Developers
Atlassian
 
Building Large Web Applications That Are Easy to Maintain
Building Large Web Applications That Are Easy to MaintainBuilding Large Web Applications That Are Easy to Maintain
Building Large Web Applications That Are Easy to Maintain
MarsBased
 
Introduction to Django
Introduction to DjangoIntroduction to Django
Introduction to Django
Joaquim Rocha
 
How to disassemble one monster app into an ecosystem of 30
How to disassemble one monster app into an ecosystem of 30How to disassemble one monster app into an ecosystem of 30
How to disassemble one monster app into an ecosystem of 30
fiyuer
 
How to become an Android dev starting from iOS (and vice versa)
How to become an Android dev starting from iOS (and vice versa)How to become an Android dev starting from iOS (and vice versa)
How to become an Android dev starting from iOS (and vice versa)
Giuseppe Filograno
 
Intro to Rails ActiveRecord
Intro to Rails ActiveRecordIntro to Rails ActiveRecord
Intro to Rails ActiveRecord
Mark Menard
 
Leture5 exercise onactivities
Leture5 exercise onactivitiesLeture5 exercise onactivities
Leture5 exercise onactivities
maamir farooq
 
Lecture exercise on activities
Lecture exercise on activitiesLecture exercise on activities
Lecture exercise on activities
maamir farooq
 
The Best (and Worst) of Django
The Best (and Worst) of DjangoThe Best (and Worst) of Django
The Best (and Worst) of Django
Jacob Kaplan-Moss
 
RUNDECK PRO - example acl policy convention
RUNDECK PRO -  example acl policy conventionRUNDECK PRO -  example acl policy convention
RUNDECK PRO - example acl policy convention
simplifyops
 
Building Modern Apps using Android Architecture Components
Building Modern Apps using Android Architecture ComponentsBuilding Modern Apps using Android Architecture Components
Building Modern Apps using Android Architecture Components
Hassan Abid
 
Android best practices
Android best practicesAndroid best practices
Android best practices
Jose Manuel Ortega Candel
 
Design Patterns for Tablets and Smartphones
Design Patterns for Tablets and SmartphonesDesign Patterns for Tablets and Smartphones
Design Patterns for Tablets and Smartphones
Michael Galpin
 

Similar to Moving ActiveRecord objects to the boundaries of your domain (20)

Little Opinions, Big Possibilities: The Tools and Patterns for Building Larg...
 Little Opinions, Big Possibilities: The Tools and Patterns for Building Larg... Little Opinions, Big Possibilities: The Tools and Patterns for Building Larg...
Little Opinions, Big Possibilities: The Tools and Patterns for Building Larg...
 
Ember.js - A JavaScript framework for creating ambitious web applications
Ember.js - A JavaScript framework for creating ambitious web applications  Ember.js - A JavaScript framework for creating ambitious web applications
Ember.js - A JavaScript framework for creating ambitious web applications
 
Controller in AngularJS
Controller in AngularJSController in AngularJS
Controller in AngularJS
 
Ruby/Rails
Ruby/RailsRuby/Rails
Ruby/Rails
 
From Legacy to Hexagonal (An Unexpected Android Journey)
From Legacy to Hexagonal (An Unexpected Android Journey)From Legacy to Hexagonal (An Unexpected Android Journey)
From Legacy to Hexagonal (An Unexpected Android Journey)
 
OData Introduction and Impact on API Design (Webcast)
OData Introduction and Impact on API Design (Webcast)OData Introduction and Impact on API Design (Webcast)
OData Introduction and Impact on API Design (Webcast)
 
Crossing the Bridge: Connecting Rails and your Front-end Framework
Crossing the Bridge: Connecting Rails and your Front-end FrameworkCrossing the Bridge: Connecting Rails and your Front-end Framework
Crossing the Bridge: Connecting Rails and your Front-end Framework
 
What's New in Jira Cloud for Developers
What's New in Jira Cloud for DevelopersWhat's New in Jira Cloud for Developers
What's New in Jira Cloud for Developers
 
Building Large Web Applications That Are Easy to Maintain
Building Large Web Applications That Are Easy to MaintainBuilding Large Web Applications That Are Easy to Maintain
Building Large Web Applications That Are Easy to Maintain
 
Introduction to Django
Introduction to DjangoIntroduction to Django
Introduction to Django
 
How to disassemble one monster app into an ecosystem of 30
How to disassemble one monster app into an ecosystem of 30How to disassemble one monster app into an ecosystem of 30
How to disassemble one monster app into an ecosystem of 30
 
How to become an Android dev starting from iOS (and vice versa)
How to become an Android dev starting from iOS (and vice versa)How to become an Android dev starting from iOS (and vice versa)
How to become an Android dev starting from iOS (and vice versa)
 
Intro to Rails ActiveRecord
Intro to Rails ActiveRecordIntro to Rails ActiveRecord
Intro to Rails ActiveRecord
 
Leture5 exercise onactivities
Leture5 exercise onactivitiesLeture5 exercise onactivities
Leture5 exercise onactivities
 
Lecture exercise on activities
Lecture exercise on activitiesLecture exercise on activities
Lecture exercise on activities
 
The Best (and Worst) of Django
The Best (and Worst) of DjangoThe Best (and Worst) of Django
The Best (and Worst) of Django
 
RUNDECK PRO - example acl policy convention
RUNDECK PRO -  example acl policy conventionRUNDECK PRO -  example acl policy convention
RUNDECK PRO - example acl policy convention
 
Building Modern Apps using Android Architecture Components
Building Modern Apps using Android Architecture ComponentsBuilding Modern Apps using Android Architecture Components
Building Modern Apps using Android Architecture Components
 
Android best practices
Android best practicesAndroid best practices
Android best practices
 
Design Patterns for Tablets and Smartphones
Design Patterns for Tablets and SmartphonesDesign Patterns for Tablets and Smartphones
Design Patterns for Tablets and Smartphones
 

Recently uploaded

Fueling AI with Great Data with Airbyte Webinar
Fueling AI with Great Data with Airbyte WebinarFueling AI with Great Data with Airbyte Webinar
Fueling AI with Great Data with Airbyte Webinar
Zilliz
 
GenAI Pilot Implementation in the organizations
GenAI Pilot Implementation in the organizationsGenAI Pilot Implementation in the organizations
GenAI Pilot Implementation in the organizations
kumardaparthi1024
 
Taking AI to the Next Level in Manufacturing.pdf
Taking AI to the Next Level in Manufacturing.pdfTaking AI to the Next Level in Manufacturing.pdf
Taking AI to the Next Level in Manufacturing.pdf
ssuserfac0301
 
Building Production Ready Search Pipelines with Spark and Milvus
Building Production Ready Search Pipelines with Spark and MilvusBuilding Production Ready Search Pipelines with Spark and Milvus
Building Production Ready Search Pipelines with Spark and Milvus
Zilliz
 
Finale of the Year: Apply for Next One!
Finale of the Year: Apply for Next One!Finale of the Year: Apply for Next One!
Finale of the Year: Apply for Next One!
GDSC PJATK
 
Introduction of Cybersecurity with OSS at Code Europe 2024
Introduction of Cybersecurity with OSS  at Code Europe 2024Introduction of Cybersecurity with OSS  at Code Europe 2024
Introduction of Cybersecurity with OSS at Code Europe 2024
Hiroshi SHIBATA
 
Choosing The Best AWS Service For Your Website + API.pptx
Choosing The Best AWS Service For Your Website + API.pptxChoosing The Best AWS Service For Your Website + API.pptx
Choosing The Best AWS Service For Your Website + API.pptx
Brandon Minnick, MBA
 
Generating privacy-protected synthetic data using Secludy and Milvus
Generating privacy-protected synthetic data using Secludy and MilvusGenerating privacy-protected synthetic data using Secludy and Milvus
Generating privacy-protected synthetic data using Secludy and Milvus
Zilliz
 
HCL Notes and Domino License Cost Reduction in the World of DLAU
HCL Notes and Domino License Cost Reduction in the World of DLAUHCL Notes and Domino License Cost Reduction in the World of DLAU
HCL Notes and Domino License Cost Reduction in the World of DLAU
panagenda
 
Energy Efficient Video Encoding for Cloud and Edge Computing Instances
Energy Efficient Video Encoding for Cloud and Edge Computing InstancesEnergy Efficient Video Encoding for Cloud and Edge Computing Instances
Energy Efficient Video Encoding for Cloud and Edge Computing Instances
Alpen-Adria-Universität
 
leewayhertz.com-AI in predictive maintenance Use cases technologies benefits ...
leewayhertz.com-AI in predictive maintenance Use cases technologies benefits ...leewayhertz.com-AI in predictive maintenance Use cases technologies benefits ...
leewayhertz.com-AI in predictive maintenance Use cases technologies benefits ...
alexjohnson7307
 
Main news related to the CCS TSI 2023 (2023/1695)
Main news related to the CCS TSI 2023 (2023/1695)Main news related to the CCS TSI 2023 (2023/1695)
Main news related to the CCS TSI 2023 (2023/1695)
Jakub Marek
 
Programming Foundation Models with DSPy - Meetup Slides
Programming Foundation Models with DSPy - Meetup SlidesProgramming Foundation Models with DSPy - Meetup Slides
Programming Foundation Models with DSPy - Meetup Slides
Zilliz
 
Presentation of the OECD Artificial Intelligence Review of Germany
Presentation of the OECD Artificial Intelligence Review of GermanyPresentation of the OECD Artificial Intelligence Review of Germany
Presentation of the OECD Artificial Intelligence Review of Germany
innovationoecd
 
Letter and Document Automation for Bonterra Impact Management (fka Social Sol...
Letter and Document Automation for Bonterra Impact Management (fka Social Sol...Letter and Document Automation for Bonterra Impact Management (fka Social Sol...
Letter and Document Automation for Bonterra Impact Management (fka Social Sol...
Jeffrey Haguewood
 
Artificial Intelligence for XMLDevelopment
Artificial Intelligence for XMLDevelopmentArtificial Intelligence for XMLDevelopment
Artificial Intelligence for XMLDevelopment
Octavian Nadolu
 
Digital Marketing Trends in 2024 | Guide for Staying Ahead
Digital Marketing Trends in 2024 | Guide for Staying AheadDigital Marketing Trends in 2024 | Guide for Staying Ahead
Digital Marketing Trends in 2024 | Guide for Staying Ahead
Wask
 
Skybuffer SAM4U tool for SAP license adoption
Skybuffer SAM4U tool for SAP license adoptionSkybuffer SAM4U tool for SAP license adoption
Skybuffer SAM4U tool for SAP license adoption
Tatiana Kojar
 
5th LF Energy Power Grid Model Meet-up Slides
5th LF Energy Power Grid Model Meet-up Slides5th LF Energy Power Grid Model Meet-up Slides
5th LF Energy Power Grid Model Meet-up Slides
DanBrown980551
 
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdfUnlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
Malak Abu Hammad
 

Recently uploaded (20)

Fueling AI with Great Data with Airbyte Webinar
Fueling AI with Great Data with Airbyte WebinarFueling AI with Great Data with Airbyte Webinar
Fueling AI with Great Data with Airbyte Webinar
 
GenAI Pilot Implementation in the organizations
GenAI Pilot Implementation in the organizationsGenAI Pilot Implementation in the organizations
GenAI Pilot Implementation in the organizations
 
Taking AI to the Next Level in Manufacturing.pdf
Taking AI to the Next Level in Manufacturing.pdfTaking AI to the Next Level in Manufacturing.pdf
Taking AI to the Next Level in Manufacturing.pdf
 
Building Production Ready Search Pipelines with Spark and Milvus
Building Production Ready Search Pipelines with Spark and MilvusBuilding Production Ready Search Pipelines with Spark and Milvus
Building Production Ready Search Pipelines with Spark and Milvus
 
Finale of the Year: Apply for Next One!
Finale of the Year: Apply for Next One!Finale of the Year: Apply for Next One!
Finale of the Year: Apply for Next One!
 
Introduction of Cybersecurity with OSS at Code Europe 2024
Introduction of Cybersecurity with OSS  at Code Europe 2024Introduction of Cybersecurity with OSS  at Code Europe 2024
Introduction of Cybersecurity with OSS at Code Europe 2024
 
Choosing The Best AWS Service For Your Website + API.pptx
Choosing The Best AWS Service For Your Website + API.pptxChoosing The Best AWS Service For Your Website + API.pptx
Choosing The Best AWS Service For Your Website + API.pptx
 
Generating privacy-protected synthetic data using Secludy and Milvus
Generating privacy-protected synthetic data using Secludy and MilvusGenerating privacy-protected synthetic data using Secludy and Milvus
Generating privacy-protected synthetic data using Secludy and Milvus
 
HCL Notes and Domino License Cost Reduction in the World of DLAU
HCL Notes and Domino License Cost Reduction in the World of DLAUHCL Notes and Domino License Cost Reduction in the World of DLAU
HCL Notes and Domino License Cost Reduction in the World of DLAU
 
Energy Efficient Video Encoding for Cloud and Edge Computing Instances
Energy Efficient Video Encoding for Cloud and Edge Computing InstancesEnergy Efficient Video Encoding for Cloud and Edge Computing Instances
Energy Efficient Video Encoding for Cloud and Edge Computing Instances
 
leewayhertz.com-AI in predictive maintenance Use cases technologies benefits ...
leewayhertz.com-AI in predictive maintenance Use cases technologies benefits ...leewayhertz.com-AI in predictive maintenance Use cases technologies benefits ...
leewayhertz.com-AI in predictive maintenance Use cases technologies benefits ...
 
Main news related to the CCS TSI 2023 (2023/1695)
Main news related to the CCS TSI 2023 (2023/1695)Main news related to the CCS TSI 2023 (2023/1695)
Main news related to the CCS TSI 2023 (2023/1695)
 
Programming Foundation Models with DSPy - Meetup Slides
Programming Foundation Models with DSPy - Meetup SlidesProgramming Foundation Models with DSPy - Meetup Slides
Programming Foundation Models with DSPy - Meetup Slides
 
Presentation of the OECD Artificial Intelligence Review of Germany
Presentation of the OECD Artificial Intelligence Review of GermanyPresentation of the OECD Artificial Intelligence Review of Germany
Presentation of the OECD Artificial Intelligence Review of Germany
 
Letter and Document Automation for Bonterra Impact Management (fka Social Sol...
Letter and Document Automation for Bonterra Impact Management (fka Social Sol...Letter and Document Automation for Bonterra Impact Management (fka Social Sol...
Letter and Document Automation for Bonterra Impact Management (fka Social Sol...
 
Artificial Intelligence for XMLDevelopment
Artificial Intelligence for XMLDevelopmentArtificial Intelligence for XMLDevelopment
Artificial Intelligence for XMLDevelopment
 
Digital Marketing Trends in 2024 | Guide for Staying Ahead
Digital Marketing Trends in 2024 | Guide for Staying AheadDigital Marketing Trends in 2024 | Guide for Staying Ahead
Digital Marketing Trends in 2024 | Guide for Staying Ahead
 
Skybuffer SAM4U tool for SAP license adoption
Skybuffer SAM4U tool for SAP license adoptionSkybuffer SAM4U tool for SAP license adoption
Skybuffer SAM4U tool for SAP license adoption
 
5th LF Energy Power Grid Model Meet-up Slides
5th LF Energy Power Grid Model Meet-up Slides5th LF Energy Power Grid Model Meet-up Slides
5th LF Energy Power Grid Model Meet-up Slides
 
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdfUnlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
 

Moving ActiveRecord objects to the boundaries of your domain

  • 1. Moving ActiveRecord objects to the boundaries of your domain @PatrickDougall Patrick Dougall https://github.com/pdougall1
  • 2.
  • 3. Get in the mood
  • 4. Quick Overview How do I do this!? What am I doing?!
  • 5. Logic all over the place! Models Views Controllers AR Models First thing I learned
  • 6. Fat Models / Skinny Controllers AR Models Views Controllers
  • 7. Fat Models / Skinny ControllersSo now you say Domain? AR Models Views Controllers AR Models Views Controllers AR Models Views Controllers Domain
  • 8. Ok, so what is domain?
  • 9. Ok, so what is domain?
  • 10. The work that this application needs to do for the domain you’re working with. • Involves calculations based on input and stored data • Validation of any data that comes in from the presentation layer • figuring out what data source logic to dispatch. Ok, so what is domain?
  • 11. We’ll practice a little 1. AR objects go into an AR directory 2. associations are ok, but only one level deep (through only one joins table) 3. NO OTHER METHODS But I have no self control! we’ll have rules
  • 13. The work that this application needs to do for the domain you’re working with. • Involves calculations based on input and stored data • Validation of any data that comes in from the presentation layer • figuring out what data source logic to dispatch. Ok, so what is domain? query object
  • 14. @projects = Project.where(active: true) def index end Active Projects class Project < ActiveRecord::Base has_many :project_user_roles has_many :users, through: :project_user_roles has_many :operations endscope :active, -> { where(active: true) } @projects = Project.active
  • 15. def index end Active Projects @projects = ActiveProjects.new class ActiveProjects < SimpleDelegator def initialize(project_factory: AR::Project) super project_factory.where(active: true) end end
  • 16. But it often things are a little different
  • 17. Need a user page SELECT "users".* FROM "users" WHERE "users"."id" = 1 module AR class User < ActiveRecord::Base end end def show @user = AR::User.find(params[:id]) end
  • 18. SELECT "projects".* FROM "projects" INNER JOIN "project_user_roles" ON "projects"."id" = "project_user_roles"."project_id" WHERE "project_user_roles"."user_id" = 1 Also a projects list def show @user = AR::User.find(params[:id])@projects = @user.projects end has_many :project_user_roles has_many :projects, through: :project_user_roles module AR class User < ActiveRecord::Base end end
  • 19. SELECT "operations".* FROM "operations" INNER JOIN "projects" ON "projects"."id" = "operations"."project_id" INNER JOIN "project_user_roles" ON "project_user_roles"."project_id" = "projects"."id" INNER JOIN "users" ON "users"."id" = "project_user_roles"."user_id" WHERE "users"."id" = 1 Also an operations list def show @user = AR::User.find(params[:id]) @projects = @user.projects end @operations = @user.operations has_many :project_user_roles has_many :projects, through: :project_user_roles has_many :operations, through: :projects, source: :operations
  • 20. SELECT "operations".* FROM "operations" INNER JOIN "projects" ON "projects"."id" = "operations"."project_id" INNER JOIN "project_user_roles" ON "project_user_roles"."project_id" = "projects"."id" WHERE "project_user_roles"."user_id" = 1 def get_operations_scope(user) @operation_scope .joins(project: :project_user_roles) .where(project_user_roles: { user_id: user.id }) end def get_operations_scope(user) @operation_scope .joins(project: :project_user_roles) .where(project_user_roles: { user_id: user.id }) end module Query class UserOperations < SimpleDelegator def initialize(user, operation_scope: AR::Operation) @operation_scope = operation_scope super get_operations_scope(user) end end end Need an operations list def show @user = AR::User.find(params[:id]) @projects = @user.projects end@operations = UserOperations.new(@user)
  • 21. def show @user = AR::User.find(params[:id]) @projects = @user.projects end @operations = UserOperations.new(@user) operations listNeed an def get_operations_scope(user) @operation_scope .joins(project: :project_user_roles) .where(project_user_roles: { user_id: user.id }) end
  • 22. operations listNeed an SELECT "operations".* FROM "operations" INNER JOIN "projects" ON "projects"."id" = "operations"."project_id" INNER JOIN "project_user_roles" ON "project_user_roles"."project_id" = "projects"."id" WHERE "project_user_roles"."user_id" = 1 SELECT "operations".* FROM "operations" INNER JOIN "projects" ON "projects"."id" = "operations"."project_id" INNER JOIN "project_user_roles" ON "project_user_roles"."project_id" = "projects"."id" INNER JOIN "roles" ON "roles"."id" = "project_user_roles"."role_id" WHERE "project_user_roles"."user_id" = 1 AND "roles"."name" = "admin
  • 23. operations list def show @user = AR::User.find(params[:id]) @projects = @user.projects end @operations = UserOperations.new(@user) def get_operations_scope(user) @operation_scope .joins(project: :project_user_roles) .where(project_user_roles: { user_id: user.id }) Need anactive end .where(projects: { active: true })
  • 24. .where(projects: { active: true }) .joins(project: :project_user_roles) .where(roles: { name: “admin” }) def get_operations_scope(user) @operation_scope end .joins(operation: { project: { project_user_roles: :role }}) .where(project_user_roles: { user_id: user.id }) SELECT "operations".* FROM "operations" INNER JOIN "projects" ON "projects"."id" = "operations"."project_id" INNER JOIN "project_user_roles" ON "project_user_roles"."project_id" = "projects"."id" INNER JOIN "roles" ON "roles"."id" = "project_user_roles"."role_id" WHERE "project_user_roles"."user_id" = 1 AND "roles"."name" = "admin def show @user = AR::User.find(params[:id]) @projects = @user.projects end @operations = UserOperations.new(@user) operations listNeed an active for admin
  • 25. def get_operations_scope(user) @operation_scope .joins(project: { project_user_roles: :role }) .where(project_user_roles: { user_id: user.id }) .where(roles: { name: "admin" }) end SELECT "operations".* FROM "operations" INNER JOIN "projects" ON "projects"."id" = "operations"."project_id" INNER JOIN "project_user_roles" ON "project_user_roles"."project_id" = "projects"."id" INNER JOIN "roles" ON "roles"."id" = "project_user_roles"."role_id" WHERE "project_user_roles"."user_id" = 1 AND "roles"."name" = "admin
  • 26. The work that this application needs to do for the domain you’re working with. • Involves calculations based on input and stored data • Validation of any data that comes in from the presentation layer • figuring out what data source logic to dispatch. Ok, so what is domain? query object form object
  • 27. Need a new User def new @user = AR::User.new end class User < ActiveRecord::Base endvalidates_presence_of :first_name, :last_name, :email
  • 28. Need a new User def new end @user = Form::User.new class User include ActiveModel::Model validates_presence_of :first_name, :last_name, :email end
  • 29. The work that this application needs to do for the domain you’re working with. • Involves calculations based on input and stored data • Validation of any data that comes in from the presentation layer • figuring out what data source logic to dispatch. Ok, so what is domain? query object form object PORO ?
  • 30. • Less likely to create god object • Naturally ends up in their own objects • Easier to understand our objects Why is this good?
  • 31. 1. OOP 2015 Keynote - Robert C. Martin ("Uncle Bob"): Agility and Architecture • https://www.youtube.com/watch?v=0oGpWmS0aYQ 2. Martin Fowler: Patterns of Enterprise Architecture • http://martinfowler.com/books/eaa.html References