Development | Dmytro Shteflyuk's Home https://kpumuk.info In my blog I'll try to describe about interesting technologies, my discovery in IT and some useful things about programming. Mon, 07 Sep 2015 23:10:49 +0000 en-US hourly 1 https://wordpress.org/?v=6.7.1 Simplifying your Ruby on Rails code: Presenter pattern, cells plugin https://kpumuk.info/ruby-on-rails/simplifying-your-ruby-on-rails-code/ https://kpumuk.info/ruby-on-rails/simplifying-your-ruby-on-rails-code/#comments Wed, 09 Sep 2009 05:41:14 +0000 http://kpumuk.info/?p=937 Today we will talk about code organization in Ruby on Rails projects. As everybody knows, Ruby on Rails is a conventional framework, which means you should follow framework architects’ decisions (put your controllers inside app/controllers, move all your logic into models, etc.) But there are many open questions around those conventions. In this write-up I […]

The post Simplifying your Ruby on Rails code: Presenter pattern, cells plugin first appeared on Dmytro Shteflyuk's Home.]]>
Today we will talk about code organization in Ruby on Rails projects. As everybody knows, Ruby on Rails is a conventional framework, which means you should follow framework architects’ decisions (put your controllers inside app/controllers, move all your logic into models, etc.) But there are many open questions around those conventions. In this write-up I will try to summarize my personal experience and show how I usually solve these problems.

Here is the list of questions we will talk about:

  1. You have some logic in your view, which uses your models extensively. There are no places in other views with such logic. The classic recommendation is to move this code into a model, but after a short time your models become bloated with stupid one-off helper methods. The solution: pattern Presenter.

  2. Your constructor contains a lot of code to retrieve some values for your views from the database or another storage. You have a lot of fragment_exist? calls to ensure no of your data is loaded when corresponding fragment is already in cache. It’s really hard to test a particular action because of it’s size. The solution: pattern Presenter.

  3. You have a partial, used everywhere on the site. It accepts a lot of parameters to configure how rendered code should look like. The header of this partial, which initializes default values of parameters, becomes larger and larger. The solution: cells plugin.

Please note: sample application is available on GitHub.

Presenter Pattern

Okay, you have an idea when to use this patterns. Let’s look at the example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class HomeController < ApplicationController
  def show
    unless fragment_exist?('home/top_videos')
      @top_videos = Video.top.all(:limit => 10)
    end
   
    unless fragment_exist?('home/categories')
      @categories = Category.all(:order => 'name DESC')
    end
   
    unless fragment_exist?('home/featured_videos')
      @featured_videos = Video.featured.all(:limit => 5)
    end

    unless fragment_exist?('home/latest_videos')
      @latest_videos = Video.latest.all(:limit => 5)
    end
  end
end

And the view:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<h1>Home page</h1>

<div id="top_videos">
    <h2>Top videos</h2>
    <% cache('home/top_videos') do %>
        <%= render 'videos', :videos => @top_videos, :hide_description => true %>
    <% end %>
</div>

<div class="tabs">
    <ul id="taxonomy">
        <li><a href="#" id="categories" class="current">Categories</a></li>
    </ul>
    <div class="categories_panel">
        <h2>Categories</h2>
        <% cache('home/categories') do %>
            <%= render 'categories' %>
        <% end %>
    </div>
</div>

<div class="box">
    <div id="latest">
        <h2>Latest videos</h2>
        <% cache('home/latest_videos') do %>
            <%= render 'videos', :videos => @latest_videos, :hide_thumbnail => true %>
        <% end %>
    </div>
    <div id="featured">
        <h2>Featured videos</h2>
        <% cache('home/featured_videos') do %>
            <%= render 'videos', :videos => @featured_videos, :hide_thumbnail => true %>
        <% end %>
    </div>
</div>

Note: this code is available in the first commit of my presenter example project.

Scary code, isn’t it? So let’s refactor it using Presenter pattern. I prefer to put presenters into a separate folder app/presenters, so first we should add it to Rails load path. Add this line to your config/environment.rb:

1
2
3
config.load_paths += %W(
  #{Rails.root}/app/presenters
)

Now we are ready to write our presenter (app/presenters/home_presenters/show_presenter.rb):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
module HomePresenters
  class ShowPresenter
    def top_videos
      @top_videos ||= Video.top.all(:limit => 10)
    end

    def categories
      @categories ||= Category.all(:order => 'name DESC')
    end
   
    def featured_videos
      @featured_videos ||= Video.featured.all(:limit => 5)
    end

    def latest_videos
      @latest_videos ||= Video.latest.all(:limit => 5)
    end
  end
end

Sometimes presenters depend on parameters, so feel free to add an initialize method. It could accept particular params or whole params collection:

1
2
3
def initialize(video_id)
  @video_id = video_id
end

Now let’s refactor our controller:

1
2
3
4
5
class HomeController < ApplicationController
  def show
    @presenter = HomePresenters::ShowPresenter.new
  end
end

Whoa, that’s nice! View now is little different:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<h1>Home page</h1>

<div id="top_videos">
    <h2>Top videos</h2>
    <% cache('home/top_videos') do %>
        <%= render 'videos', :videos => @presenter.top_videos, :hide_description => true %>
    <% end %>
</div>

<div class="tabs">
    <ul id="taxonomy">
        <li><a href="#" id="categories" class="current">Categories</a></li>
    </ul>
    <div class="categories_panel">
        <h2>Categories</h2>
        <% cache('home/categories') do %>
            <%= render 'categories' %>
        <% end %>
    </div>
</div>

<div class="box">
    <div id="latest">
        <h2>Latest videos</h2>
        <% cache('home/latest_videos') do %>
            <%= render 'videos', :videos => @presenter.latest_videos, :hide_thumbnail => true %>
        <% end %>
    </div>
    <div id="featured">
        <h2>Featured videos</h2>
        <% cache('home/featured_videos') do %>
            <%= render 'videos', :videos => @presenter.featured_videos, :hide_thumbnail => true %>
        <% end %>
    </div>
</div>

Presenters testing is much easier than testing of bloated controllers:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
describe HomePresenters::ShowPresenter do
  before :each do
    @presenter = HomePresenters::ShowPresenter.new
  end
 
  it 'should respond to :top_videos' do
    expect { @presenter.top_videos }.to_not raise_error
  end

  it 'should respond to :categories' do
    expect { @presenter.categories }.to_not raise_error
  end

  it 'should respond to :featured_videos' do
    expect { @presenter.featured_videos }.to_not raise_error
  end

  it 'should respond to :latest_videos' do
    expect { @presenter.latest_videos }.to_not raise_error
  end
end

Please note: this code is available in the second commit of my presenter example project.

Please note: you should not do any manipulations on models in presenters. They only decorate models with helper methods to be used inside controllers or views, nothing else. There are several articles describing a Conductor pattern as a presenter, do not repeat their mistakes. See the first link in the list below to get an idea about the differences.

Related links:

Cells Plugin

Okay, now we have a clean controller. But what about views? Let’s take a look at the videos partial:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<%
 hide_thumbnail   = hide_thumbnail === true;
 hide_description = hide_description === true;
 css_class      ||= 'videos'
 style          ||= :div
 case style.to_sym
   when :section
     parent_tag = 'section'
     child_tag = 'div'
   when :list
     parent_tag = 'ul'
     child_tag = 'li'
   else
     parent_tag = 'div'
     child_tag = 'div'
 end
%>

<% content_tag parent_tag, :class => css_class do %>
  <% videos.each do |video| %>
    <% content_tag child_tag do %>
      <h3><%= h video.title %></h3>
      <%= image_tag(video.thumbnail_url, :class => 'thumb') unless hide_thumbnail %>
      <%= '<p>%s</p>' % h(video.description) unless hide_description %>
    <% end %>
  <% end %>
<% end %>

So, what the heck? Is this a view or a controller? Remember old PHP days, with all this spaghetti code? That is it. It’s hard to test, it looks scary, it bad. So here cells plugin comes to the stage.

First, we need to install the plugin:

1
script/plugin install git://github.com/apotonick/cells.git

Now let’s generate a cell:

1
script/generate cell Video videos

And write some code (app/cells/video.rb):

1
2
3
4
5
6
7
8
9
10
11
12
13
class VideoCell < Cell::Base
  def videos
    @videos = @opts[:videos]
    @hide_thumbnail = @opts[:hide_thumbnail] === true;
    @hide_description = @opts[:hide_description] === true;
    @css_class = @opts[:css_class] || 'videos'
   
    view = (@opts[:style] || :div).to_sym
    view = :div unless [:section, :list].include?(view)

    render :view => "videos_#{view}"
  end
end

app/cells/video/videos_section.html.erb:

1
2
3
4
5
6
7
<section class="<%= @css_class %>">
  <% @videos.each do |video| %>
    <div>
      <%= render :partial => 'video', :locals => { :video => video } %>
    </div>
  <% end %>
</section>

app/cells/video/videos_list.html.erb:

1
2
3
4
5
6
7
<ul class="<%= @css_class %>">
  <% @videos.each do |video| %>
    <li>
      <%= render :partial => 'video', :locals => { :video => video } %>
    </li>
  <% end %>
</ul>

app/cells/video/videos_div.html.erb:

1
2
3
4
5
6
7
<div class="<%= @css_class %>">
  <% @videos.each do |video| %>
    <div>
      <%= render :partial => 'video', :locals => { :video => video } %>
    </div>
  <% end %>
</div>

app/cells/video/_video.html.erb:

1
2
3
<h3><%= h video.title %></h3>
<%= image_tag(video.thumbnail_url, :class => 'thumb') unless @hide_thumbnail %>
<%= '<p>%s</p>' % h(video.description) unless @hide_description %>

And the view:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<h1>Home page</h1>

<div id="top_videos">
    <h2>Top videos</h2>
    <% cache('home/top_videos') do %>
        <%= render_cell :video, :videos, :videos => @presenter.top_videos, :hide_description => true %>
    <% end %>
</div>

<div class="tabs">
    <ul id="taxonomy">
        <li><a href="#" id="categories" class="current">Categories</a></li>
    </ul>
    <div class="categories_panel">
        <h2>Categories</h2>
        <% cache('home/categories') do %>
            <%= render 'categories' %>
        <% end %>
    </div>
</div>

<div class="box">
    <div id="latest">
        <h2>Latest videos</h2>
        <% cache('home/latest_videos') do %>
            <%= render_cell :video, :videos, :videos => @presenter.latest_videos, :hide_thumbnail => true %>
        <% end %>
    </div>
    <div id="featured">
        <h2>Featured videos</h2>
        <% cache('home/featured_videos') do %>
            <%= render_cell :video, :videos, :videos => @presenter.featured_videos, :hide_thumbnail => true %>
        <% end %>
    </div>
</div>

Wow! That’s pretty easy to read and modify. All the logic is in the code now, all the views are easy to read, and moreover: it’s more than easy to test now! I have a little plugin called rspec-cells, and I have committed a patch yesterday to get it working with the latest RSpec. Here is how you spec could look like:

1
2
3
4
5
6
7
8
9
describe VideoCell do
  context '.videos' do
    it 'should initialize :videos variable' do
      videos = mock('Videos')
      render_cell :videos, :videos => videos
      assigns[:videos].should be(videos)
    end
  end
end

So it looks almost like a classic Ruby on Rails controller spec. I hope to review the code in nearest feature and will send a pull request to the cells plugin author. Of course, if you
found a bug, feel free to contact me.

Please note: this code is available in the third commit of my presenter example project.

Related links:

That’s all I wanted to show you today. I think a Presenter Example project will be updated periodically, so follow it on GitHub, follow me in Twitter or on GitHub to get instant updates. Also take a look at the rspec-cells plugin, maybe you will have some time to make it better.

The post Simplifying your Ruby on Rails code: Presenter pattern, cells plugin first appeared on Dmytro Shteflyuk's Home.]]>
https://kpumuk.info/ruby-on-rails/simplifying-your-ruby-on-rails-code/feed/ 25
10 recommendations on using HTML5 today (aka Homo-Adminus Blog 2.0 HTML5ified) https://kpumuk.info/development/10-recommendations-on-using-html5-today/ https://kpumuk.info/development/10-recommendations-on-using-html5-today/#comments Mon, 20 Jul 2009 14:00:14 +0000 http://kpumuk.info/?p=751 There was a lot of articles about HTML5 last days, so when Alexey Kovyrin asked me to help him with his new blog design I saw no other choice but using HTML5. There are a lot of new features added since HTML4, and some of them could be used today, like new elements <header>, <footer>, […]

The post 10 recommendations on using HTML5 today (aka Homo-Adminus Blog 2.0 HTML5ified) first appeared on Dmytro Shteflyuk's Home.]]>
There was a lot of articles about HTML5 last days, so when Alexey Kovyrin asked me to help him with his new blog design I saw no other choice but using HTML5. There are a lot of new features added since HTML4, and some of them could be used today, like new elements <header>, <footer>, <nav>, <article>, <section>, etc. I think this is a nice addition to the HTML, because these elements add more sense to an unstructured markup. There is a buzzword “semantic” exists to describe this, but I don’t like buzzwords, so I would call it “sense”. So what features we could get from HTML5, that are supported by all modern browsers?

Ok, there is not so much of a difference between HTML4 and HTML5 from web-developer standpoint, just some <div> elements are replaced with more meaningful ones (I’m talking about markup now, not about new APIs. Here is what I mean:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Homo-Adminus Blog</title>
    <link rel="stylesheet" href="style.css" type="text/css" media="screen" />
    <!--[if IE]>
    <script src=" http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
    <![endif]-->
  </head>
  <body>
    <div id="container">
      <header id="page-header">
        <nav id="menu">
          <ul>
            <li><a href="#">Home</a></li>
            <li><a href="#">Resume/CV</a></li>
            <li><a href="#">Projects</a></li>
            <li><a href="#">Photos</a></li>
            <li><a href="#">Contact</a></li>
          </ul>
        </nav>
      </header>
      <div id="page-content">
        <section id="content">
          <article>
            <header>
              <h2><a href="#">Loops plugin for rails and merb released</a></h2>
              <p class="meta">
                Posted by Scoundrel under
                <a href="#">Development</a>,
                <a href="#">My Projects</a>,
                <a href="#">Networks</a>
              </p>
            </header>
            <aside>
              <time datetime="2008-08-20">Sun 20<br />Aug<br />2008</time>
            </aside>
            <section class="text">
              Article content goes here.
            </section>
            <footer>
              <p>
                Tags:
                <a href="#" rel="tag">github</a>,
                <a href="#" rel="tag">plugin</a>
              </p>
              <p>
                <a href="#comments">1 Comment</a> |
                <a href="#">Bookmark on del.icio.us</a>
              </p>
            </footer>
          </article>
        </section>
       
        <footer id="page-footer">
          Copyright &#169; 2009 <a href="#">Alexey Kovyrin</a> |
          Designed by <a href="#">Tatiana Kovyrina</a>
        </footer>
      </div>
      <nav id="sidebar">
        <section id="categories" class="left">
          <header><h3>Categories</h3></header>
          <ul>
            <li><a href="#">Admin-tips</a> (26)</li>
            <li><a href="#">Blog</a> (2)</li>
            <li><a href="#">Databases</a> (33)</li>
          </ul>
        </section>
      </nav>
    </div>
  </body>
</html>

In a few words: the only difference is that we use new HTML elements instead of descriptive CSS class names and IDs. I’m not going to describe all new features of HTML5 here, the good introduction could be found here or here.

Here are my recommendations on using HTML5 today:

  1. To enable new HTML5 elements in IE you should use document.createElement — see lines 6-8, explanation is here.

  2. Ensure that new HTML5 elements are block level:

    1
    2
    3
    4
    5
    header, footer, section, nav, article, aside {
        margin: 0px;
        padding: 0px;
        display: block;
    }
  3. Use <section> element if you need to add a block of specific content, like categories list (lines 54-61). Use good old <div> to add a markup element with no specific sense (for example, <div id="container"> on line 11).

  4. Use <nav> element to create any sort of navigation panes (top-level menu, sidebar, footer links). Do not use <aside> to create sidebars — this is wrong!

  5. <header> and <footer> elements are good candidates to wrap any heading (logo, top level navigation, and almost everything that visually is under the main content) and bottom (article metadata, page footer, bottom links, and almost everything that visually is below the main content) information. You can use these elements inside other elements like <nav>, <article>, or <section>, so use them.

  6. New element <article> contains a block of information inside the main content area. It could be an article or blog post, a comment, a particular book description in bookstore, etc. Be creative and use this exciting element to fill your pages with a sense.

  7. The most controversial element is <aside>. Lots of articles about HTML5 in the Internet suggest to use it for the sidebar navigation, but that is absolutely wrong. Use this tag to take some information out of primary content. Good candidates are footnotes or side notes, quotes, comment author’s avatar, etc. Yes, I’ll repeat: be creative.

  8. Almost everything you do in HTML4 is valid for HTML5: use unordered lists <ul> of list items where order does not matter, use ordered lists <ol> otherwise. Use tables (yes, <table>) for tabular data structures (and not for layout). Paragraphs, emphasizes, quotes, and much more elements should take their own place in your markup.

  9. Use validator to ensure you are doing it right.

  10. Read the code. The good place to start from is HTML5 Gallery.

You can start using HTML5 right now. It’s our future, and we need to know, how would it look like.

PS. Did you notice the nice code syntax highlighting in this blog? I’m using CodeColorer — the best syntax highlighting plugin for WordPress. Try it and you will stay with it forever!

The post 10 recommendations on using HTML5 today (aka Homo-Adminus Blog 2.0 HTML5ified) first appeared on Dmytro Shteflyuk's Home.]]>
https://kpumuk.info/development/10-recommendations-on-using-html5-today/feed/ 12