Search code examples
ruby-on-railsdatabaseactiverecordnormalization

Rails data design for multiple date picker


I have an Appointment model, whose available_dates can include multiple dates (say, available in Jan 1, 5, 6 and 7).

My question is very basic: how should I store available dates for each event?

What I can think of is a table Avaiable_Dates with two columns: event_id and date. Each event would have multiple rows, one date per row. It seems to be cumbersome to query entire table to make sure we got all dates of an event. A Hash {event => {date1, date2, date3}} would be faster, but I don't know how to implement it using ActiveRecord.

Thank you.


Solution

  • It might not be a bad idea to just use the separate model for available times, but if you decide to go the hash route you can do so using the serialize keyword. You have to tell ActiveRecord to serialize the variable, and then it will do the serialization and deserialization automatically whenever you access the hash.

    Saving arrays, hashes, and other non-mappable objects in text columns

    Active Record can serialize any object in text columns using YAML. To do so, you must specify this with a call to the class method serialize. This makes it possible to store arrays, hashes, and other non-mappable objects without doing any additional work.

    class User < ActiveRecord::Base
      serialize :preferences
    end
    
    user = User.create(:preferences => { "background" => "black", "display" => large })
    User.find(user.id).preferences # => { "background" => "black", "display" => large }
    

    You can also specify a class option as the second parameter that’ll raise an exception if a serialized object is retrieved as a descendant of a class not in the hierarchy.

    class User < ActiveRecord::Base
      serialize :preferences, Hash
    end
    
    user = User.create(:preferences => %w( one two three ))
    User.find(user.id).preferences    # raises SerializationTypeMismatch
    

    When you specify a class option, the default value for that attribute will be a new instance of that class.

    class User < ActiveRecord::Base
      serialize :preferences, OpenStruct
    end
    
    user = User.new
    user.preferences.theme_color = "red"
    

    From rubyonrails.org

    From a design perspective, if you think you will ever add any more data to the available time object then you should make it its own model. Otherwise a serialized hash seems fine.