Search code examples
ruby-on-railsassociationshas-manybelongs-tohas-one

Rails Active Record Associations


I've been reading and re-reading the Rails associations guide:

http://guides.rubyonrails.org/association_basics.html

This were close but not quite the same:

Ruby on rails active record associations

I'm not sure how to setup the following scenario.

Events has a status of either pending, open, or close.

I thought this would be simple enough to just have:

event has_one status
status belongs_to event

But this really isn't a one-to-one relationship since a status can belong to many events.

So then I thought I would do something like:

status has_many events
event belongs_to status

But this seems funny, because a status doesn't own an event. An event owns a status, right?

I had tried using enumerations and not have a status model. But that got tricky since it seems like ActiveRecord doesn't really support enumerations. I also figured that having a separate model might be good in case someone wants to expand on the number of options for status, like adding 'awaiting approval' or something.

This post suggests that my latter setup is okay, even though it reads funny:

Really easy Rails Active-Record Associations question

But I'm just wondering if I'm not aware of a better Ruby/Rails way of handling this simple scenario.

Thanks in advance!


Solution

  • Ignore that voice in your head: you're doing it fine. The real important of which model has belongs_to is where the foreign key is stored. It's clear in this example that the foreign key should be stored in the Event model, which means it should belongs_to :status.

    I also agree with the other posts, though - if you have got a small and fixed number of potential Status records, consider creating an constant hash to store them instead of creating a whole database table for them.

    Why not add a status column to Event (as an integer), and have something like this:

    class Event < ActiveRecord::Base
      STATUS_TYPES = {1 => "active", 2 => "inactive", 3 => "closed"}
    
      def status
        STATUS_TYPES[self[:status]]
      end
    
      def status=(new_status)
        new_status = STATUS_TYPES.invert[new_status] if new_status.class == "String"
        self[:status] = new_status
      end
    end