OK you decided that you care enough about your views to read on. Stick with it, its worth the ride.
Let's get started by using the default scaffolding to generate a customer model. Run the following:
script/generate scaffold
customer first_name:string, last_name:string, company:string, phone:string, email:string
Then run the migration and test the pages.
rake db:migrate
Now lets turn these views into erector views. Erector comes with a tool that will turn your erb's into erector classes. Run the following from your application root directory:
erector
app/views/customers/**
If you look in your views/customers directory you will now see .rb files. Let's compare the code. Here is our show.html.erb:
<p>
<b>First name:</b>
<%=h @customer.first_name %>
</p>
<p>
<b>Last name:</b>
<%=h @customer.last_name %>
</p>
<p>
<b>Company:</b>
<%=h
@customer.company %>
</p>
<p>
<b>Phone:</b>
<%=h @customer.phone %>
</p>
<p>
<b>Email:</b>
<%=h
@customer.email %>
</p>
<%= link_to
'Edit', edit_customer_path(@customer) %> |
<%= link_to 'Back', customers_path %>
Now here is the erector equivalent:
class Views::Customers::Show < Erector::Widget
def
content
p do
b do
text 'First name:'
end
text
@customer.first_name
end
p do
b do
text 'Last name:'
end
text @customer.last_name
end
p do
b do
text
'Company:'
end
text @customer.company
end
p do
b do
text 'Phone:'
end
text @customer.phone
end
p do
b do
text 'Email:'
end
text @customer.email
end
rawtext link_to('Edit', edit_customer_path(@customer))
text '|'
rawtext link_to('Back',
customers_path)
end
end
It is pretty straight forward. One gotcha is that the base class is the
Erector::Widget class. The problem is that we are using rails helper and these are exposed using the Erector::RailsWidget base class. You can either change the base class to Erector::RailsWidget or you can introduce an erector layout that derives from Erector::RailsWidget and then you would derive from your layout class. (See my last post for more info on this.) The other thing you need to do is to move or destroy the erb files. If you don't move or delete them then your new erector view classes will not be found. Now you have erector views for your scaffolded customer. Take it for a spin.
I personally think the syntax is cleaner if we use the {} block syntax instead of do end. Here is the same view re-written to use {}:
class Views::Customers::Show < Erector::Widget
def content
p {
b
{text 'First name:'}
text @customer.first_name
}
p {
b {text 'Last
name:'}
text @customer.last_name
}
p {
b {text 'Company:'}
text @customer.company
}
p {
b {text 'Phone:'}
text
@customer.phone
}
p {
b {text 'Email:'}
text @customer.email
}
rawtext link_to('Edit', edit_customer_path(@customer))
text '|'
rawtext link_to('Back', customers_path)
end
end
Now you have a feel for what it looks like. How about a quick refactor of this code. I personally don't like the hard coded labels, so let's remove that:
class Views::Customers::Show < Erector::Widget
def show_column(col)
p {
b {text col.to_s.titleize }
text @customer[col]
}
end
def content
show_column :first_name
show_column :last_name
show_column :company
show_column :phone
show_column :email
rawtext link_to('Edit', edit_customer_path(@customer))
text '|'
rawtext link_to('Back',
customers_path)
end
end
Now that's what I'm talking about. Now gee, if i do that in all my show views, I can easily refactor that method and make it available in either a base class or a module mix-in. What I like is how easy the refactoring is. It feels as it should easy.
Rawtext and text
You'll notice that we output using either text or rawtext. The difference is text is escaped and rawtext is not.