alt
alt

Reputation: 13907

Access model-specific constants in a Rails view

I'm running Rails 4.

I have a model called Challenge, and in my database I'm storing the status of each challenge in terms of 0-4.

But 0-4 isn't very semantic so I want to define a few variables (I'm assuming a constants) so that in any controller or view I can access the number by calling the constant:

# Challenge.rb
class Challenge < ActiveRecord::Base
  SUGGESTED = 0
  APPROVED = 1
  OPEN = 2
  VOTING = 3
  CLOSED = 4
end

I want to access these in my view:

# challenge/_details.html.erb
<% if @challenge.status == CLOSED %>
  Challenge is closed, broheim!
<% end %>

But my view doesn't want to render.

uninitialized constant ActionView::CompiledTemplates::CLOSED

What's the best way to set my status variables so that they may be accessed everywhere I need them? (i.e, anywhere the @challenge variable is present)

Upvotes: 30

Views: 24273

Answers (3)

Emrecan Şuşter
Emrecan Şuşter

Reputation: 23

I highly recommend you to using enums, which introduced in Rails 4.1 if you're asking for enumeration of specific values.

class Challenge < ActiveRecord
  enum status: {
    suggested: 0
    approved: 1
    open: 2
    voting: 3
    closed: 4
  }
end

After that, you can use these methods:

Challenge.first.suggested? # For checking
Challange.first.open! # For change the status
Challange.open # Get all challanges with "open" status

For using enums, you have to declare an integer column with enum name (i.e: “status”) in your "challenges" (or which table related with model) table.

For more information about enums

Upvotes: 0

apneadiving
apneadiving

Reputation: 115521

It's a really bad idea to code this kind of statements: your object must handle it's own logic. Imagine if someday you decide to merge status, would you change every conditional in your codebase? No, you should use one method which handles the logic.

I'd do the following:

class Challenge < ActiveRecord::Base
  SUGGESTED = 0
  APPROVED = 1
  OPEN = 2
  VOTING = 3
  CLOSED = 4

  #defines:
  # - suggested?
  # - approved?
  # - ...
  %w(suggested approved open voting closed).each do |state|
    define_method "#{state}?" do
      status == self.class.const_get(state.upcase)
    end
  end

  #if you prefer clarity, define each method:

  def suggested?
    status == SUGGESTED
  end

  #etc...
end

Then in your view:

<% if @challenge.closed? %>

Upvotes: 9

vee
vee

Reputation: 38645

You should access them as following:

Challenge::CLOSED

Since your CLOSED constant is defined within a class, you need to access the constant using the scope resolution operator. So if your view you would check it like:

# challenge/_details.html.erb
<% if @challenge.status == Challenge::CLOSED %>
  Challenge is closed, broheim!
<% end %>

Upvotes: 59

Related Questions