We have been having some projects lately that needed a lot of admin CRUDs and pages showing a list of attributes, and we were getting bored of copy and paste code like this in our show pages, for every single attribute:
Name
<% @person.name %>
%>
We had already created some helper to do the work for us, but having this helper being copied from one project to another wasn’t that DRY. That’s when we decided to create ShowFor.
ShowFor is a DSL to help you showing a list of attributes, with I18n, perfect for show pages in CRUD interfaces. It allows you to replace code/html duplication in your views using a nice syntax. Let’s see what we can do.
Attributes
Let’s imagine we have a Person model, which has first_name, last_name, age, photo, and confirmed attributes. The following lines show a list of values for a specific person:
<% show_for @person do |p| %>
<% p.attribute :first_name %>
<% p.attribute :last_name %>
<% p.attribute :confirmed %>
<% p.attribute :created_at :format=""> :short %>
<% p.attribute :age :if_blank=""> "No age" %>
<% p.attribute :photo do %>
<% image_tag %>
<% end %>
<% end %>
%>%>%>%>%>%>%>%>%>%>
Here is an example output you will get:
First name
Carlos
Last name
Antonio
Confirmed?
Yes
Created at
08 Mar 11:30
Age
24
Photo
As you can see, you are going to get a default html markup, with classes and ids to help you design with CSS. And if you noticed, we are using extra options in some attributes, lets take a look at some of them:
-
:format
lets you pass any format that will be used together with i18n, for date/time attributes only, as you would use with thel
helper. -
:if_blank
specifies what to show if the attribute is blank. It may have a default value from i18n. -
do...end
: using blocks you can handle the content for that specific attribute by yourself, as we have done in this example for thephoto
attribute.
Boolean attributes, as our :confirmed
, also have a default for true
and false
values, and can be configured through i18n. If you want to say “Yup” and “Nope” instead of “Yes” and “No” respectively, just change your i18n file. You can also pass a :escape
option to not escape the value (true
by default).
Associations
ShowFor also works with associations. For instance, we can easily add that a Person belongs to a City with a name attribute and that it has and belongs to many Tags. To handle the former, we can do:
<% p.association :city %>
%>
ShowFor will guess the right attribute to show by looking into all possibilities configured in ShowFor.association_methods
and in this case choosing :name. But of course, you can change it as you need, on-the-fly:
<% p.association :city :using=""> :full_name %>
<% p.attribute :full_name :in=""> :city %>
%>%>
Both calls above will have the same output, just choose the one which suits you better.
Handling collections is easy as belongs_to associations. You can just pass the association to ShowFor and it will know whether it’s a collection or not, generating a list of elements using ul
and li
tags.
<% p.association :tags %>
%>
However, if you want to render the collection inline, you can use :to_sentence or :join as options:
<% p.association :tags :to_sentence=""> true %>
<% p.association :tags :join=""> ',' %>
%>%>
It’s also possible to pass a block to the collection. ShowFor will create the wrapper tag (ul
by default in this case) and will yield
each element in the collection for you to handle it:
<% a.association :tags do |tag| %>
Labels
You may have noticed ShowFor has a default label using the strong
html tag. It also exposes you this as a helper, so you can use it whenever you wish:
<% p.label :first_name %>
<% p.label :age :id=""> 'person_age' %>
First name
Age
%>%>
Installation
ShowFor is already compatible with Rails 3, at the time of this writing in version 0.2.0. You can just follow the instructions in the README to get it installed.
If you are using Rails 2.3.x, take a look at the 0.1 branch, and follow the installations in the README for this branch to get it up and running.
Please don’t forget to run the generator and take a look at the initializer, it will allows you configure several parts of ShowFor.
script/generate show_for_install
Closing
ShowFor helps you to show your objects easily with a default html markup, and can be totally configured to suit your needs. It has been helping us in every project, and we hope it may help you too. If you have any doubt, please take a look at the README, there are a lot of examples and documentation there.
And what about you? Do you have any helper you use every single day that might be transformed in a plugin/gem? Do not hesitate on doing this, we would be glad to see your work.
Enjoy!
Hi guys,
That’s a nice DSL, but I was wondering: is it correct to use instead of something like ? I’m not sure, but the strong means “important text” while the label tag means “this is the name/title of the thing ahead” which is appropriate usability wise and compatible with screen readers and stuff like that. I would rather do something like:
‘something’%>
to generate
First nameCarlos
Besides, I’d add a :break option to enable/disable the . Hope this helps.
Regards
Hi guys,
That’s a nice DSL, but I was wondering: is it correct to use instead of something like ? I’m not sure, but the strong means “important text” while the label tag means “this is the name/title of the thing ahead” which is appropriate usability wise and compatible with screen readers and stuff like that. I would rather do something like:
‘something’%>
to generate
First nameCarlos
Besides, I’d add a :break option to enable/disable the . Hope this helps.
Regards
It seems the comments are not escaping the markup, sorry 🙁
It seems the comments are not escaping the markup, sorry 🙁
I’d agree with Rafael’s comment. Why use strong instead of the proper (and dare I say, semantic) “label” tag?.
Besides that, I like a lot. Feels “formtasticly” in spirit. Great work!
What about adding a attributes method? So your first example would become something like (using HAML to try to evade that markup eating of wordpress :P):
show_for @person do |p|
= p.attributes :first_name, :last_name, :confirmed?
= p.attribute :created_at, :format => :short
= p.attribute :age, :if_blank => “No age”
I’d agree with Rafael’s comment. Why use strong instead of the proper (and dare I say, semantic) “label” tag?.
Besides that, I like a lot. Feels “formtasticly” in spirit. Great work!
What about adding a attributes method? So your first example would become something like (using HAML to try to evade that markup eating of wordpress :P):
show_for @person do |p|
= p.attributes :first_name, :last_name, :confirmed?
= p.attribute :created_at, :format => :short
= p.attribute :age, :if_blank => “No age”
@Rafael really thanks for the tips. And we are going to take a look at the markup inside the comments :)..
@Rafael and @Alvaro, the initializer ShowFor installs inside your config/initializers has some configurations that allows you to change each piece of code it uses, for instance the label_tag, wrapper_tag, and default separator (ie br tag). Perhaps I missed explaining a bit about it in the post.
I think it should do the trick of overriding the :strong tag for :label for instance. Anyway, I agree label is “the name/title of the thing ahead” (I liked it =D).
@Alvaro a patch to add :attributes would be appreciated =). Thanks.
@Rafael really thanks for the tips. And we are going to take a look at the markup inside the comments :)..
@Rafael and @Alvaro, the initializer ShowFor installs inside your config/initializers has some configurations that allows you to change each piece of code it uses, for instance the label_tag, wrapper_tag, and default separator (ie br tag). Perhaps I missed explaining a bit about it in the post.
I think it should do the trick of overriding the :strong tag for :label for instance. Anyway, I agree label is “the name/title of the thing ahead” (I liked it =D).
@Alvaro a patch to add :attributes would be appreciated =). Thanks.
I’m getting a generator not found (using latest Rails 3):
wgd1 root# gem install show_for
Successfully installed show_for-0.2.0
1 gem installed
Installing ri documentation for show_for-0.2.0…
Updating class cache with 4063 classes…
Installing RDoc documentation for show_for-0.2.0…
wgd1$ rails generate show_for_install
Could not find generator show_for_install.
wgd1$ rails g
Please choose a generator below.
Rails:
… as expected
ActiveRecord:
… as expected
Erb:
… as expected
Rspec:
… as expected
TestUnit:
… as expected
I’m getting a generator not found (using latest Rails 3):
wgd1 root# gem install show_for
Successfully installed show_for-0.2.0
1 gem installed
Installing ri documentation for show_for-0.2.0…
Updating class cache with 4063 classes…
Installing RDoc documentation for show_for-0.2.0…
wgd1$ rails generate show_for_install
Could not find generator show_for_install.
wgd1$ rails g
Please choose a generator below.
Rails:
… as expected
ActiveRecord:
… as expected
Erb:
… as expected
Rspec:
… as expected
TestUnit:
… as expected
@Rafael and @Alvaro: even the label tag isn’t the recommend one. The label is meant to be associated with a form element.
I think DL can be used, but is not that easy to style it. I’d probably go with p > strong + text.
@Rafael and @Alvaro: even the label tag isn’t the recommend one. The label is meant to be associated with a form element.
I think DL can be used, but is not that easy to style it. I’d probably go with p > strong + text.
Agreed, label is def. not the recommended one. First show_for versions used b tags instead of strong. And then I got a few pull requests asking to change to strong. Good news is, it’s easy to customize in your app. 🙂
@BillSaysThis I’m investigating. 🙂
Agreed, label is def. not the recommended one. First show_for versions used b tags instead of strong. And then I got a few pull requests asking to change to strong. Good news is, it’s easy to customize in your app. 🙂
@BillSaysThis I’m investigating. 🙂
Hi,
@Nando is right, the DL, DT and DD tags are the recommended ones for this job, label is exclusive for form. My bad 🙂
http://www.w3.org/TR/html5/semantics.html#the-dl-element
The styling may be a little trick, but perhaps it worth the trouble to define a correct default.
Regards
Hi,
@Nando is right, the DL, DT and DD tags are the recommended ones for this job, label is exclusive for form. My bad 🙂
http://www.w3.org/TR/html5/semantics.html#the-dl-element
The styling may be a little trick, but perhaps it worth the trouble to define a correct default.
Regards
Cool. I’ve been wanting to do this myself for quite some time. Especially since Streamlined is no longer maintained. Now all we is ListFor.
One suggestion — it’d be better if we didn’t have to put each line in a separate ERB tag. Even if the entire file was all Ruby, it’d be OK by me.
Cool. I’ve been wanting to do this myself for quite some time. Especially since Streamlined is no longer maintained. Now all we is ListFor.
One suggestion — it’d be better if we didn’t have to put each line in a separate ERB tag. Even if the entire file was all Ruby, it’d be OK by me.
How do I change the label printed above an association list for individual fields?
How do I change the label printed above an association list for individual fields?
@BillSaysThis I didn’t understand what you want to achieve. More info please? 🙂
@BillSaysThis I didn’t understand what you want to achieve. More info please? 🙂
@Craig Thanks.. By “put each line in a separate ERB tag” you mean what @Alvaro said, using :attributes? If so, a patch would be really cool =).
@Craig Thanks.. By “put each line in a separate ERB tag” you mean what @Alvaro said, using :attributes? If so, a patch would be really cool =).
[…] ShowFor […]
@Carlos Antonio: I bit the bullet and tried to make it work. Just sent you an email with the patch for an idea of how to implement it. It’s quite basic, but it works 🙂
@Carlos Antonio: I bit the bullet and tried to make it work. Just sent you an email with the patch for an idea of how to implement it. It’s quite basic, but it works 🙂
BTW, I just realized I had the “label” thing totally wrong, as you’ve said before. For a moment, I though we were talking about form fields. Duh!.
I agree that DL would be the best way to work it. Maybe I’ll try to play with it this noon. Shouldn’t be that hard to accomplish.
BTW, I just realized I had the “label” thing totally wrong, as you’ve said before. For a moment, I though we were talking about form fields. Duh!.
I agree that DL would be the best way to work it. Maybe I’ll try to play with it this noon. Shouldn’t be that hard to accomplish.
@Alvaro Hey, I’m going to take a look at it ok, thanks :).
@Alvaro Hey, I’m going to take a look at it ok, thanks :).
@josevalim I mean if I code, say, :full_name %> I get a paragraph above the list of people with the word People in bold. I would like a different text to appear in place of People.
Similarly, for specific fields I would like to use a label other than the human version of the field name.
@josevalim I mean if I code, say, :full_name %> I get a paragraph above the list of people with the word People in bold. I would like a different text to appear in place of People.
Similarly, for specific fields I would like to use a label other than the human version of the field name.
Sorry, code block above didn’t come out correctly, should be:
:full_name %>
Sorry, code block above didn’t come out correctly, should be:
:full_name %>
Ugg, still no good. Here’s without the angle bracket:
Sorry, code block above didn’t come out correctly, should be:
% = d.association :people, :using => :full_name %
Ugg, still no good. Here’s without the angle bracket:
Sorry, code block above didn’t come out correctly, should be:
% = d.association :people, :using => :full_name %
Bill, I’m almost sure that you can given the :label option:
<%= d.association :people, :using => :full_name, :label => “OMG People” %>
Bill, I’m almost sure that you can given the :label option:
<%= d.association :people, :using => :full_name, :label => “OMG People” %>
Thanks, the label option wasn’t clear to me.
Thanks, the label option wasn’t clear to me.
Next issue, again I’m sure I just haven’t read the docs closely enough 😉
I want to use a block with the association so I can print something a bit more sophisticated for each item. If I use a helper nothing shows up, even in a very simple case as below nothing shows up (< removed to hopefully print code properly).
% d.association :people, :label => ‘Staffers’, :label_tag => ‘h2’ do |person| %>
li> %= person.full_name %> /li>
% end %>
Next issue, again I’m sure I just haven’t read the docs closely enough 😉
I want to use a block with the association so I can print something a bit more sophisticated for each item. If I use a helper nothing shows up, even in a very simple case as below nothing shows up (< removed to hopefully print code properly).
% d.association :people, :label => ‘Staffers’, :label_tag => ‘h2’ do |person| %>
li> %= person.full_name %> /li>
% end %>
It would be neat if one could just pass in the record and then it would output all attributes listed in attr_accessible
It would be neat if one could just pass in the record and then it would output all attributes listed in attr_accessible
Does this work with MongoMapper?
Does this work with MongoMapper?
@Vineyard yes, it should work normally.. There is nothing in ShowFor talking about your database, it’s only a better way of showing data.
@Vineyard yes, it should work normally.. There is nothing in ShowFor talking about your database, it’s only a better way of showing data.