2

In my rails application I have a model called JobPosting. A job posting has a status, it can be either:

  1. Waiting Approval
  2. Draft
  3. Open
  4. Interviews Scheduled
  5. Closed

I implemented these statuses using ActiveRecord::Enum like so:

class JobPosting < ApplicationRecord
   enum status: [:waiting_approval, :draft, :open, :interviews_scheduled, :closed]
end

Now I would like to display a different user interface element that is dependant on the status of the job posting. i.e.

For the waiting approval status I want:

<div class="label label-warning">pending approval</div>

And for the open status I want:

<div class="label label-success">open</div>

Note that there is different text and the class is different as the element is styled differently for the different cases. In my index.html.erb, where this styling needs to happen, I could just do a bunch of embedded ruby if statements and check the status of the posting and display the desired element, like so:

<% if posting.waiting_approval? %>
      <div class="label label-warning">pending approval</div>
<% elsif posting.open? %>
      <div class="label label-success">open</div>
<% elsif posting.closed> %>
      etc...
 <% end %>

I feel as if that is not very DRY, is there a better way?

Alternatively, I could create partial and have the logic stored in that and just render the partial, but again is that how it is done?

Robert Saunders
  • 403
  • 8
  • 22
  • you could write a function which generates content based on the enum value – ashkhn Jan 04 '17 at 13:54
  • What I typically do with this is make the status part of the class and then write css to attach to the class. So, label-draft, would be a class with the styles you want on it and then in the view just one line, "label-<%= posting.status %>" will apply the class and styles you want. – Rockwell Rice Jan 04 '17 at 13:55
  • @RockwellRice that is a good idea, I really like that implementation, although, the only thing I don't like is that I would have to compromise my status names for CSS class names that used more widely throughout my application it doesn't justify changing them. As a result for clarity I would prefer to keep the status names as they are and not change the CSS classes as well. – Robert Saunders Jan 04 '17 at 13:58
  • 1
    http://stackoverflow.com/questions/22827270/how-to-use-i18n-with-rails-4-enums – max Jan 04 '17 at 14:06

2 Answers2

3

I would do something like this:

class JobPosting < ApplicationRecord
   enum status: [:waiting_approval, :draft, :open, :interviews_scheduled, :closed]

   def status_label
     {
       'waiting_approval' => 'pending approval',
       'open' => 'open',
       'interviews_scheduled' => 'interview is scheduled',
       'closed' => 'closed',
       'draft' => 'draft'
     }[self.status]
   end
end

then in view:

<div class="label <%= posting.status %>"><%= posting.status_label %></div>

Since in Rails we've sass you can inherit properties of other css classes:

.waiting_approval{
  @extend .label-warning;
  // customize this css class if needed.
}

// and so on..
Surya
  • 15,703
  • 3
  • 51
  • 74
  • This is a great solution, the only thing I am weary of is putting this kind of logic in the model class, I prefer all of the business kind of logic to be in the controller, this is why I am going with the other answer, although both work fine! Thanks for the help! – Robert Saunders Jan 04 '17 at 14:43
2

Unless you have decorators, I would've just created a simple helper

def status_label(posting)
  case posting.status
  when :waiting_approval
    content_tag(:div, 'pending approval', class: 'label label-warning')
  when :draft
    ...
end
Rustam Gasanov
  • 15,290
  • 8
  • 59
  • 72
  • I would change it so that you can pass a block for the text or use the I18n module. – max Jan 04 '17 at 14:03