2

I need to add status for an object, and need a hint about the Rails way to do this. Somewhere I've seen status was added into the model, but already lost where it was.

By status, I mean something that tracks about the item state. Like {0: :ORDERED, 1: :CHANGED, 2: :SHIPPED, 3: :ARCHIVED} for order in store. Looks like it needs id that stored in DB, constant or symbol that I could use in code instead of integer id, and one or two human readable messages for UI

Emily
  • 17,813
  • 3
  • 43
  • 47
lifecoder
  • 1,424
  • 1
  • 14
  • 29
  • Something that say about the item state. Like {0: :ORDERED, 1: :CHANGED, 2: :SHIPPED, 3: :ARCHIVED} for order in store. Looks like it needs id that stored in DB, constant or symbol that I could use in code instead of integer id, and one or two human readable messages for UI. – lifecoder May 24 '12 at 19:47
  • Thanks for @Samy, found what I'm looking for: [simple status realisation in RoR][1] [1]: http://stackoverflow.com/questions/2650897/in-rails-how-should-i-implement-a-status-field-for-a-tasks-app-integer-or-enu – lifecoder May 24 '12 at 21:02

3 Answers3

6

There's a couple simple ways to do this. If the names of the statuses are short, I'd do basically what Samy suggested and store them directly in the model. So, in your migration, you'd do

add_column :orders, :status, :string

Then, in your model, you can use the status method to retrieve the status. You'll want to make sure you only store valid statuses, so you the :inclusion validator something like this:

class Order
  validates :status, inclusion: { in: %w(ordered changed shipped archived) },
                     presence: true
end

If the statuses are longer, you can do something very much like the above with a short name for each status, then add an additional method to give you the full status message

class Order

  STATUSES = { 'ordered' => 'Order placed',
               'changed' => 'A change has been made to the order',
               'shipped' => 'The order has been shipped',
               'archived' => 'The order has been archived' }

  def self.valid_statuses
    STATUSES.keys
  end

  validates :status, inclusion: { in: valid_statuses },
                     presence: true

  def extended_status
    STATUSES[status]
  end
end
Emily
  • 17,813
  • 3
  • 43
  • 47
  • Thank you< nearly exactly what I want to find. In the comment for the question link for a bit better solution (string status in the DB obviously isn't a good practice). – lifecoder May 24 '12 at 21:06
1

MagicFieldNames might be what you are looking for, it has a discriminator type column that you can use for Single Table Inheritance.

If you want simpler, you can use a status column which value can equal ordered, changed, or shipped. You don't even need to create constants in Rails or such a thing.

Samy Dindane
  • 17,900
  • 3
  • 40
  • 50
  • Thank you for the comment. I'm pretty new wit Ruby and Rails- maybe so I counldn't find any useful under your links :( – lifecoder May 24 '12 at 20:13
  • I'm not totally sure, but this seems the only *native* way to do what you want. I updated my answer with a more simpler solution. – Samy Dindane May 24 '12 at 20:35
  • Still couldn't find information about this magic fields, I'm sure it's my fault and find this when the time is come. But googling around "status column" give me exactly what I'm looking for. – lifecoder May 24 '12 at 21:01
1

If the problem has some complexity (f.e: lots of states, the object changes its behavior when changing its state...), you could use the gem StateMachine.

Gawyn
  • 1,156
  • 1
  • 10
  • 21
  • It looks like some overkill, I just need 4 or 5 states and extremly simple logic backing them, and also wan't to know how to do this type of things in the right way by myself. Anyway, thank you for your suggestion, I'll give it a shot. – lifecoder May 24 '12 at 20:19
  • There is another, more simple way to do it. Create a "state" column and a global variable called STATES, which lists all the possible states. You can put the global variable just under the start of the item class declaration. Also add a validates_inclusion_of :state, :in => STATES. I would say this is the most Rubyist way to do it. – Gawyn May 24 '12 at 21:00