Slide 1

Slide 1 text

Dax Huiberts [email protected] Best practices and useful tools DRYing up your views

Slide 2

Slide 2 text

• My first big presentation • So if I screw up... please be merciful.

Slide 3

Slide 3 text

Overview • Basics • Haml • Formtastic • Advanced techniques • Block Helper • Presenters

Slide 4

Slide 4 text

Basics What you should already do with plain Rails

Slide 5

Slide 5 text

Some basics • Keep your logic out of your views • HTML-escape your user output • Don’t mix javascript inside your views • Use partials for recurring HTML structures

Slide 6

Slide 6 text

Keep your logic out of your views

Slide 7

Slide 7 text

Keep your logic out of your views Don’t do this: <% main_categories = Category.find :all, :conditions => "parent_id IS NULL" %>

Slide 8

Slide 8 text

Keep your logic out of your views Don’t do this: <% main_categories = Category.find :all, :conditions => "parent_id IS NULL" %> Better: <% main_categories = Category.main %>

Slide 9

Slide 9 text

Keep your logic out of your views Don’t do this: <% main_categories = Category.find :all, :conditions => "parent_id IS NULL" %> Better: <% main_categories = Category.main %> Best: def main_categories @main_categories ||= Category.main end

Slide 10

Slide 10 text

HTML-escape your user output

Slide 11

Slide 11 text

HTML-escape your user output Hi, my name is: window.location='http://bit.ly/4kb77v'

Slide 12

Slide 12 text

HTML-escape your user output Hi, my name is: window.location='http://bit.ly/4kb77v' <%= link_to @user.name, @user %> Results in: window.location='http://bit.ly/4kb77v'</ script></a> SHIT!!!

Slide 13

Slide 13 text

HTML-escape your user output Hi, my name is: window.location='http://bit.ly/4kb77v' <%= link_to h(@user.name), @user %> Results in: <script>window.location='http://bit.ly/4kb77v'</ script> GOTCHA!!!

Slide 14

Slide 14 text

Don’t mix javascript inside your views

Slide 15

Slide 15 text

Slide 16

Slide 16 text

Use partials for recurring HTML structures Your view:
<%= @post.body %>

Slide 17

Slide 17 text

Use partials for recurring HTML structures Your PARTIAL:
<%= data %>

Slide 18

Slide 18 text

Use partials for recurring HTML structures Your PARTIAL:
<%= data %>
Calling it with: <%= render :partial => "shared/rounded_box", :locals => {:data => @post.body} %>

Slide 19

Slide 19 text

Use partials for recurring HTML structures Your helper method: def rounded_box &block data = capture(&block) concat(render(:partial => "shared/rounded_box", :locals => {:data => concat()})) end

Slide 20

Slide 20 text

Use partials for recurring HTML structures Your helper method: def rounded_box &block data = capture(&block) concat(render(:partial => "shared/rounded_box", :locals => {:data => concat()})) end And your view: <% rounded_box do %> <%= @post.body %> <% end %>

Slide 21

Slide 21 text

Haml Beautiful HTML

Slide 22

Slide 22 text

Haml • Started using it in summer 2007 • Hate it => get used to it => loved it • Closer to the CSS domain • Markup should be beautiful • http://haml-lang.com/

Slide 23

Slide 23 text

Haml ERB:
<%= print_date %>
<%= current_user.address %>
<%= current_user.email %>
<%= current_user.bio %>
UGLY!!!

Slide 24

Slide 24 text

Haml Haml: #profile .left.column #date= print_date #address= current_user.address .right.column #email= current_user.email #bio= current_user.bio BEAUTIFUL!!!

Slide 25

Slide 25 text

Haml Haml: %strong= item.title

Slide 26

Slide 26 text

Haml Haml: %strong= item.title ERB: <%= item.title %>

Slide 27

Slide 27 text

Haml Haml: %strong{:class => "code", :id => "message"} Hello, World! ERB: Hello, World!

Slide 28

Slide 28 text

Haml Haml: %strong.code#message Hello, World! ERB: Hello, World!

Slide 29

Slide 29 text

Haml summary • Haml is awesome!!! • Everybody should use it! • O’RLY? • YEAH’RLY!

Slide 30

Slide 30 text

Sass Also take a look at Sass! Syntactically awesome stylesheets: http://sass-lang.com/

Slide 31

Slide 31 text

Formtastic Semantically rich and accessible forms

Slide 32

Slide 32 text

Formtastic • Forms are friggin’ boring to code • Semantically rich & accessible • Automatic support for: • Labeling • Error reporting • Extensive markup possibilities • http://github.com/justinfrench/formtastic

Slide 33

Slide 33 text

Formtastic form_for: <% form_for @user do |form| %>
<%= form.label :title %> <%= form.text_field :title %>
<%= form.label :body %> <%= form.text_area :body %>
<%= submit_tag "Save" %>
<% end %> EWWW!!!

Slide 34

Slide 34 text

Formtastic semantic_form_for: <% semantic_form_for @user do |form| %> <%= form.inputs :title, :body %> <%= form.buttons :commit %> <% end %> YAY!!!

Slide 35

Slide 35 text

Formtastic semantic_form_for with Haml: - semantic_form_for @user do |form| = form.inputs :title, :body = form.buttons :commit WHOOHOO!!!

Slide 36

Slide 36 text

Formtastic summary • Cleans up your code dramatically! • Best use of forms yet!

Slide 37

Slide 37 text

Advanced Techniques When your projects get bigger

Slide 38

Slide 38 text

Block helpers When DRYing up views gets in the way

Slide 39

Slide 39 text

Block helpers • When partials start to contain to much options • When partials look more like ruby than HTML • http://github.com/markevans/block_helpers

Slide 40

Slide 40 text

Block helpers Calling a partial: <%= render :partial => "videos/video", :locals => {:video => video, :hide_description => true, :style_tag => :li }%>

Slide 41

Slide 41 text

Block helpers Calling a helper method: <%= render_video video, :hide_description => true, :style_tag => :li %>

Slide 42

Slide 42 text

Block helpers Complex partial: <% hide_thumbnail ||= true hide_description ||= true header_tag ||= :h2 style_tag ||= :div css_class ||= 'video' %> <% content_tag style_tag, :class => css_class do %> <%= content_tag header_tag, video.title %> <%= image_tag(video.thumbnail_url, :class => 'thumb') unless hide_thumbnail %> <%= '

%s

' % h(video.description) unless hide_description %> <% end %> Hmmm.....

Slide 43

Slide 43 text

Block helpers Block helper (part 1 of 2): module VideosHelper class VideoBlock < BlockHelpers::Base DEFAULT_OPTIONS = {:hide_thumbnail => true, :hide_description => true, :style_tag => :div, :header_tag => :h2, :css_class => "video"} attr_accessor :video, :options def initialize(video, options = {}) @video = video @options = DEFAULT_OPTIONS.merge(options) end ...

Slide 44

Slide 44 text

Block helpers Block helper (part 2 of 2): ... def display header = content_tag(options[:header_tag], video.title) thumbnail = image_tag(video.thumbnail, :class => "thumb") unless options[:hide_thumbnail] description = content_tag(:p, video.description) unless options[:hide_description] data = header + thumbnail.to_s + description.to_s content_tag(options[:style_tag], :class => options[:css_class], data) end end end

Slide 45

Slide 45 text

Block helpers Your ERB: <%= video_block video, :hide_description => true, :style_tag => :li %> MMMMM!!!!!

Slide 46

Slide 46 text

Block helpers summary • Shift from ERB to Ruby • Don’t pretend it’s a partial anymore • More structured & more maintainable over time

Slide 47

Slide 47 text

Presenters Bridging the gap between models and controllers/views

Slide 48

Slide 48 text

Presenters • Apply the adapter (wrapper) pattern to combine controller logic with domain logic • Keep logic in it’s rightful place. • Prevent models to contain controller logic • Warning: It’s still a concept!

Slide 49

Slide 49 text

Presenters Wrong ERB: <% if current_user && (current_user.is_admin? || (@topic.creator == current_user && [email protected])) %> <%= link_to "Edit topic", @topic %> <% end %> WRONG!!!

Slide 50

Slide 50 text

Presenters Presenter file: class TopicPresenter < Presenter::Base def can_edit? is_admin? || (is_owner? && !locked) end def can_lock? is_admin? end def can_reply? current_user && !locked end ... ... def is_owner? creator == current_user end private def is_admin? current_user && current_user.is_admin? end end

Slide 51

Slide 51 text

Presenters Controller action: def show @topic = presenter(Topic.find(params[:id])) end

Slide 52

Slide 52 text

Presenters Correct ERB: <%= link_to "Edit topic", @topic if @topic.can_edit? %> DAMN RIGHT!!!

Slide 53

Slide 53 text

Presenters summary • Like I said, it’s still a concept • Can clean up complex partials a lot • Keeps models the way they should be • More info at: http://www.htmltimes.com/presenters-in- Ruby-on-Rails-applications.php or http://bit.ly/vUlv

Slide 54

Slide 54 text

Conclusion • It saved precious bits on your hard drive • Higher level of abstraction • Views get more readable, thus better maintainable • Beware: Big shift from ERB/Haml to Ruby • But, It’s a joy writing views again!

Slide 55

Slide 55 text

That’s it!

Slide 56

Slide 56 text

Questios?