Skip to content

Backend Training: Decorator

Nelson Lee edited this page Nov 30, 2017 · 3 revisions

🔖 : draper

By now we can display posts and faqs data from the database. The only issue now is that some of the contexts are not formatted correctly. For example, the date format is different from the ones showing on the mockup.

So let's add some decorators to fix the issues.

Add decorator for posts

# app/decorators/post_decorator.rb
# Decorates Post
class PostDecorator < Draper::Decorator

  delegate_all

  def published_date
    object.published_date.strftime('%B %d, %Y')
  end

  def published_date_short
    object.published_date.strftime('%b %d, %Y')
  end

  def content_short
    return if content.blank?
    truncate(strip_tags(content), length: 250)
  end

end

Call decorator from controller

# app/controllers/posts_controller.rb
class PostsController < ApplicationController

  ......

  def index
    @posts = Post.published
    filter_posts
    @posts = @posts.by_published_date.
             paginate(page: params[:page], per_page: 9).
             decorate
  end

  ......

end

Refresh the browser Command ⌘+r, and oops. Seems like will_paginate is not working well with decorators.

decorator-error

Let's fix this by adding a file app/decorators/paginating_decorator.rb

# app/decorators/paginating_decorator.rb
# Pagination Patch
class PaginatingDecorator < Draper::CollectionDecorator

  # support for will_paginate
  delegate :current_page, :per_page, :offset, :total_entries, :total_pages

end

And add another file called app/decorators/application_decorator.rb

# app/decorators/application_decorator.rb
# Dercorator Base
class ApplicationDecorator < Draper::Decorator

  include Draper::LazyHelpers
  delegate_all

  def self.collection_decorator_class
    PaginatingDecorator
  end

end

Now change app/decorators/post_decorator.rb to inherit from ApplicationDecorator

# app/decorators/post_decorator.rb
# Decorates Post
class PostDecorator < ApplicationDecorator

Refresh the browser Command ⌘+r, and the page should render now.

Apply Decorator

Let's apply decorator in the views by calling the methods we created previously

.col-sm-6.col-md-4
  .thumbnail
    = holder_tag '300x150', 'Sample Image', '', class: 'img-responsive'
    .caption
      h4= link_to post.title, post
      p.text-muted= post.category_list
      br/
      p= post.content_short
      br/
      p.text-muted= post.published_date_short

Now your post should look like

post

Fix reset of the files

Let's add decorator to show page as well.

# app/controllers/posts_controller.rb
class PostsController < ApplicationController

  .....

  def show
    @post = Post.published.
            friendly.find(params[:id]).decorate
  end

  ......

Go to show page and now the show page is working as expected.

Let's add a decorator for faq as well

# app/decorators/faq_decorator.rb
# Decorates Faq
class FaqDecorator < ApplicationDecorator
# app/controllers/faqs_controller.rb
class FaqsController < ApplicationController

  def index
    @faqs = Faq.by_position.decorate
  end

end

One last thing, remember we also have posts inside home#index so let's fix them as well.

# app/controllers/home_controller.rb
class HomeController < ApplicationController

  def index
    @posts = Post.published.by_published_date.
             limit(3).decorate
    @faqs = Faq.by_position.decorate
  end

  ......

end

Refresh the browser Command ⌘+r, and they should all be working correctly now.

Let's commit your changes before moving on to the next step.

$ git add -A
$ git commit -m 'Post & Faq Decorators'

↪️ Next Section: RSpec Tests