class Widget < ApplicationRecord
belongs_to :manufacturer
validates :price,
numericality: { greater_than: 0 }
end
class WidgetsController < ApplicationController
def create
@widget = Widget.new(widget_params)
if @widget.save
redirect_to widgets_path
else
render :new
end
end
end
class WidgetsController < ApplicationController
def create
@widget = Widget.new(widget_params)
if @widget.save
PreOrderJob.perform_later(@widget.id)
redirect_to widgets_path
else
render :new
end
end
end
class WidgetsController < ApplicationController
def create
@widget = Widget.new(widget_params)
if @widget.save
if @widget.price > 1_000
AdminMailer.new_widget(@widget)
else
PreOrderJob.perform_later(@widget.id)
end
redirect_to widgets_path
else
render :new
end
end
end
class WidgetsController < ApplicationController
def create
@widget = Widget.new(widget_params)
if @widget.save
if @widget.manufacturer.legacy?
SalesNotification.create!(widget: @widget)
elsif @widget.price > 1_000
AdminMailer.new_widget(@widget)
else
PreOrderJob.perform_later(@widget.id)
end
redirect_to widgets_path
else
render :new
end
end
end
class Widget < ActiveRecord::Base
after_create do
if self.manufacturer.legacy?
SalesNotification.create!(widget: self)
elsif self.price > 1_000
AdminMailer.new_widget(self)
else
PreOrderJob.perform_later(self.id)
end
end
end
WIDGETS
table” are different things.
class Widget < ActiveRecord::Base
after_create do
if self.manufacturer.legacy?
SalesNotification.create!(widget: self)
elsif self.price > 1_000
AdminMailer.new_widget(self)
else
PreOrderJob.perform_later(self.id)
end
end
end
after_create
> ls app
assets/ # Assets like CSS or Images
channels/ # Channels for Action Cable
controllers/ # HTTP
helpers/ # View helpers
jobs/ # Background jobs
mailers/ # Sending email
models/ # Database Access
views/ # HTML views
> ls app
assets/ # Assets like CSS or Images and business logic
channels/ # Channels for Action Cable and business logic
controllers/ # HTTP and business logic
helpers/ # View helpers and business logic
jobs/ # Background jobs and business logic
mailers/ # Sending email and business logic
models/ # Database Access and business logic
views/ # HTML views and business logic
> ls app
assets/ # Assets like CSS or Images and business logic
channels/ # Channels for Action Cable and business logic
controllers/ # HTTP and business logic
helpers/ # View helpers and business logic
jobs/ # Background jobs and business logic
mailers/ # Sending email and business logic
models/ # Database Access and business logic
views/ # HTML views and business logic
> ls app
assets/ # Assets like CSS or Images
channels/ # Channels for Action Cable
controllers/ # HTTP
helpers/ # View helpers
jobs/ # Background jobs
mailers/ # Sending email
models/ # Database Access and business logic
views/ # HTML views
Active Record is the M in MVC - the model - which is the layer of the system responsible for representing business data and logic. Active Record facilitates the creation and use of business objects whose data requires persistent storage to a database.
app/models
bin/rails g model
class WidgetsController < ApplicationController
def create
@widget = Widget.new(widget_params)
if @widget.save
if @widget.manufacturer.legacy?
SalesNotification.create!(widget: @widget)
elsif @widget.price > 1_000
AdminMailer.new_widget(@widget)
else
PreOrderJob.perform_later(@widget.id)
end
redirect_to widgets_path
else
render :new
end
end
end
class
def
class
def
#
#
#
#
#
#
#
#
#
#
#
end
end
class
def (widget_params)
widget = Widget.new(widget_params)
if widget.save
if widget.manufacturer.legacy?
SalesNotification.create!(widget: widget)
elsif widget.price > 1_000
AdminMailer.new_widget(widget)
else
PreOrderJob.perform_later(widget.id)
end
end
widget
end
end
class WidgetCreation
def create_widget(widget_params)
widget = Widget.new(widget_params)
if widget.save
if widget.manufacturer.legacy?
SalesNotification.create!(widget: widget)
elsif widget.price > 1_000
AdminMailer.new_widget(widget)
else
PreOrderJob.perform_later(widget.id)
end
end
widget
end
end
mkdir
> mkdir app/services
> ls app
assets/ # Assets like CSS or Images
channels/ # Channels for Action Cable
controllers/ # HTTP
helpers/ # View helpers
jobs/ # Background jobs
mailers/ # Sending email
models/ # Database Access
services/ # Business Logic
views/ # HTML views
> ls app
assets/ # Assets like CSS or Images and nothing else
channels/ # Channels for Action Cable and nothing else
controllers/ # HTTP and nothing else
helpers/ # View helpers and nothing else
jobs/ # Background jobs and nothing else
mailers/ # Sending email and nothing else
models/ # Database Access and nothing else
services/ # Business Logic and nothing else
views/ # HTML views and nothing else
class WidgetsController < ApplicationController
def create
@widget = WidgetCreation.new.create_widget(widget_params)
if @widget.valid?
redirect_to widgets_path
else
render :new
end
end
end
WidgetsController
is stable.Widget
is also stable.WIDGETS
are stable.Widget
or its instances are stable.Changes to Widget Creation Are Now Well-Isolated
ActiveModel::Validations
is extremely well designed. We should not abandon it
ActiveModel::Validations
exists)Widget.create
inserts rows into the WIDGETS
database tableWidgetsTable.insert_new_row
class SalesTeamNotifier
def send_daily_notifications
end
end
class WidgetCreation
def create_widget(…)
end
def import_widget_from_csv(…)
end
end
class WidgetCreation
def create_widget(…)
notify_admins(…)
end
def import_widget_from_csv(…)
notify_admins(…)
end
private
def notify_admins(…)
# code to share
end
end
class WidgetCreation
private
def notify_admins(…)
AdminNotifier.notify_on_new_widget(…)
end
end
class Widgets::Creation
# …
end
class Widgets::Archival
# …
end
class Widgets::Reporting
# …
end
sustainable-rails.com
50% off with code SERVICELAYER
Are you from India, 日本, Mexico, 香港, Україна, or any African nation? Use one of these codes intead:
https://bit.ly/davetron5000-ppp