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

Objects on Rails

Objects on Rails

Lailson Bandeira

July 26, 2014
Tweet

More Decks by Lailson Bandeira

Other Decks in Technology

Transcript

  1. WHOAMI Lailson Bandeira Co-founder of Guava Software Co-founder Frevo on

    Rails MS.c. in Machine Learning at CIn/UFPE Member of the VIISAR Research Group Sun Certified Java Programmer (SCJP)
  2. PRESENTER DEFINITION Presenters objects are a type of decorator specialized

    for presenting models to an end user. — Avdi Grimm M C V
  3. PRESENTER LONG DEFINITION If the Model is concerned with storing

    and manipulating business data, and the View is concerned with displaying it, you can think of the Exhibit as standing between them deciding which data to show, and in what order. It may also provide some extra presentation-specific information (such as the specific URLs for related re- sources) which the business model has no knowledge of by itself. — Avdi Grimm
  4. PRESENTER WHEN TO USE IT Use it when you have

    complex presentation rules.
  5. PRESENTER WHEN TO USE IT Presenters are the ideal place

    to: • format complex data for user display • define commonly-used representations of an object • mark up attributes with a little semantic HTML — Draper
  6. PRESENTER # app/decorators/article_decorator.rb class ArticleDecorator < Draper::Decorator delegate_all ! def

    publication_status if published? "Published at #{published_at}" else "Unpublished" end end ! def published_at object.published_at.strftime("%A, %B %e") end end EXAMPLE
  7. FORM OBJECT DEFINITION Form objects decouple your models from forms.

    They usually perform validations, setup of nested models, rendering of form helpers and coordination of object relations. — Nick Sutterer M C V
  8. FORM OBJECT WHEN TO USE IT Use it when when

    you have a form which doesn’t match your models.
  9. FORM OBJECT EXAMPLE # models ! class User < ActiveRecord::Base

    has_one :profile end ! class Profile < ActiveRecord::Base belongs_to :user end
  10. FORM OBJECT EXAMPLE # form class UserForm < Reform::Form include

    DSL include Reform::Form::ActiveModel ! properties [:first_name, :last_name], on: :user properties [:email, :locale, :age], on: :profile ! model :user, on: :user ! validates :first_name, :last_name, :email, presence: true end
  11. FORM OBJECT EXAMPLE class UsersController < ApplicationController def new @form

    = Forms::UserForm.new(user: User.new, profile: Profile.new) end ! def create if form.validate(params) form.save do |data, map| user = User.create(map[:user]) map[:user_id] = user.id Profile.create(map[:profile]) end else render action: :new end end end
  12. WHEN TO USE IT Use it when you have complex

    validation rules, possible spanning multiple objects or when you have contextual validation. VALIDATOR
  13. EXAMPLE class Edit < Scrivener attr_accessor :title attr_accessor :body !

    def validate assert_present :title assert_present :body end end ! edit = Edit.new(title: title, body: body) edit.valid? #=> true ! article = Article.new(edit.attributes) article.save VALIDATOR
  14. EXAMPLE class Publish < Scrivener attr_accessor :status ! def validate

    assert_format :status, /^(published|draft)$/ end end ! publish = Publish.new(status: "published") publish.valid? #=> true ! article.update_attributes(publish.attributes) VALIDATOR
  15. POLICY WHEN TO USE IT Use it when your application

    has complex domain/business rules.
  16. POLICY EXAMPLE class InvestmentPromotionPolicy attr_reader :investment ! def initialize(investment) @investment

    = investment end ! def promoted? valid_promotion_date? and owner_promotable? end ! def owner_promotable? investment.owner.active_for_promotion? end ! def promotion_status case when promoted? :promoted when valid_promotion_date? and !owner_promotable? :pending_for_promotion else :not_promoted end end ! def valid_promotion_date? (investment.promotion_starts_at..investment.promotion_ends_at).cover? Time.now end end
  17. POLICY EXAMPLE class Investment < ActiveRecord::Base delegate :promoted?, :owner_promotable?, :promotion_status

    to: :promotion_policy ! # some methods ! private ! def promotion_policy @promotion_policy ||= InvestmentPromotionPolicy.new(self) end end
  18. POLICY EXAMPLE 2 class PostPolicy attr_reader :user, :post ! def

    initialize(user, post) @user = user @post = post end ! def update? user.admin? or not post.published? end end
  19. POLICY EXAMPLE 2 # controller def update @post = Post.find(params[:id])

    authorize @post if @post.update(post_params) redirect_to @post else render :edit end end
  20. INTERACTOR DEFINITION An interactor is an object with a simple

    interface and a singular purpose. It provides a common interface for performing complex interactions in a single request and usually represents a business process. — Collective Idea M C V
  21. INTERACTOR EXAMPLE class AuthenticateUser include Interactor ! def perform if

    user = User.authenticate(context[:email], context[:password]) context[:user] = user else context.fail! end end end
  22. INTERACTOR EXAMPLE class SessionsController < ApplicationController def create result =

    AuthenticateUser.perform(session_params) ! if result.success? redirect_to result.user else render :new end end ! private def session_params params.require(:session).permit(:email, :password) end end
  23. INTERACTOR EXAMPLE class PlaceOrder include Interactor::Organizer ! organize [ CheckInventory,

    CalculateTax, ChargeCard, CreateOrder, DeliverThankYou, DeliverOrderNotification, ScheduleFollowUp ] end
  24. QUERY DEFINITION Query is an object that implements an interface

    for querying the database. — Luca Guidi M C V
  25. QUERY WHEN TO USE IT Use it when your application

    business rules requires complex queries.
  26. QUERY class MediaQuery attr_reader :start_date, :end_date, :term, :location_name ! def

    initialize(params={}) @start_date = params[:start_date] @end_date = params[:end_date] @term = params[:term] @location_name = params[:location_name] end ! def generate query = Medium.scoped query = query.gte(created_at: start_date) if start_date query = query.lte(created_at: end_date) if end_date query = query.where(location: location_name) if location_name.present? query = query.text(term) if term.present? query end ! end EXAMPLE
  27. REFERENCES • 7 Ways to Decompose Fat ActiveRecord Models http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/

    ! • Structuring Rails Applications http://karolgalanciak.com/blog/2013/10/06/structuring-rails-applications/ ! • Concerns, Decorators, Presenters, Service Objects, Helpers, Help Me Decide! http://confreaks.com/videos/3329-railsconf-concerns-decorators-presenters-service-objects-helpers-help-me-decide ! • Catalog of Patterns of Enterprise Application Architecture http://martinfowler.com/eaaCatalog/
  28. That’s all, folks! XXI FREVO ON RAILS MEETUP Slides presented

    by Lailson Bandeira on July 26, 2014 as part of the 21st Frevo on Rails Meetup, available at https://speakerdeck.com/lailsonbm. Slides created with Keynote with the fonts Monserrat, Source Sans Pro and Inconsolata. LAILSON BANDEIRA http://lailson.me/ http://github.com/lailsonbm http://facebook.com/guavasoftware