Наряжаем рельсу

Using decorators in Ruby on Rails

Николай Кугаевский /@kugaevsky

Data in view layer

  • Ruby object
  • Rails helpers
  • Custom helpers
  • Embed ruby code

Смесь французского с нижегородским

Ruby is about objects, not procedures

article
  h3
    = link_to post.title, post
    small< = post.user
  p = post.body

  - if user_signed_in? && current_user == post.user
    ul.button-group
      li = link_to_show(post)
      li = link_to 'Edit', edit_post_path(post), class: 'button alert tiny'
      li = link_to 'Destroy', post, data: {:confirm => 'Are you sure?'}, :method => :delete, class: 'button alert tiny'

Helpers smells like

PHP

Decorator to the rescue

Что такое? Кто такой

Декоратор (англ. Decorator) — структурный шаблон проектирования, предназначенный для динамического подключения дополнительного поведения к объекту. Шаблон Декоратор предоставляет гибкую альтернативу практике создания подклассов с целью расширения функциональности.

русская Wikipedia

А по-русски?

Decorator pattern — in object-oriented programming, the decorator pattern (also known as Wrapper, an alternative naming shared with the Adapter pattern) is a design pattern that allows behavior to be added to an individual object, either statically or dynamically, without affecting the behavior of other objects from the same class.

понятная Wikipedia

Singleton method

[1] pry(main)> question = "Where I am?"
=> "Where I am?"
[2] pry(main)> question.define_singleton_method(:answer) { "GRRUG meetup!" }
=> :answer
[3] pry(main)> question.answer
=> "GRRUG meetup!"

Decorator class

class StringDecorator
  def initialize(string = "")
    @string = string
  end

  def answer
    "I dunno!"
  end

  def size
    @string.size > 10 ? %(It's sooooo long) : 'It is short'
  end

  def method_missing(method, *args, &block)
    @string.send(method, *args, &block)
  end
end

Decorated object

# Initialize
decorated_string = StringDecorator.new("Where I am?")

# Decorator method
decorated_string.answer => "I dunno!"

# String method
decorated_string.downcase => "where i am?"

# Overridden method
decorated_string.size => "It's sooooo long"`

Draper

Draper adds an object-oriented layer of presentation logic to your Rails application.

Without Draper, this functionality might have been tangled up in procedural helpers or adding bulk to your models. With Draper decorators, you can wrap your models with presentation-related logic to organise - and test - this layer of your app much more effectively.

— gem Draper on Github

Draper install

# Gemfile
gem 'draper'

# app/controllers/posts_controller.rb
def show
  @post = Post.find(params[:id]).decorate
end

# app/decorators/posts_decorator.rb
class PostDecorator < Draper::Decorator
  delegate_all

  def created_at
    helpers.l(object.created_at)
  end
end

Alternatives

Reading and watching