Using cookies to store and retrieve
At it's simplest, a cookie collection object needs to do the following.Add items
Retrieve all items
In this example, I want to be able to show a list of recent restaurants on the side of the page.
Do do this, I would like an interface that allows me to add a recent restaurant.
recent_restaurants.push(@restaurant)
Or, to retrieve recent restaurants...
recent_restaurants
I'd like to avoid making direct calls using the 'cookies' hash, instead interact with the collection and hold the list between requests in the cookie.
With a CookieCollection class, we can use this to handle the common additions and deletes. We also get all the power that comes with the Array class. This class is meant to be subclassed.
class CookieCollection < Array attr_accessor :ids def initialize(cookies) super(0) @_cookies = cookies if @_cookies[cookie_name].present? self.ids = @_cookies[cookie_name].split(',') else self.ids = [] end end def push(object) super(object) update_cookie end private def update_cookie ids = map(&:id) @_cookies[cookie_name] = {:value => ids.join(','), :expires => 20.years.from_now} end def cookie_name self.class.name.parameterize end end
Note - the cookie value is only the ids of the object.
In a RecentRestaurants subclass, we can make the specific updates to our list of recent restaurants. In this case, I wanted to limit my list to the last 5 items.
class RecentRestaurants < CookieCollection def initialize(cookies) super(cookies) self.ids = ids.last(5) ids.each{ |r_id| push(Restaurant.find(r_id)) } end def push(restaurant) delete(restaurant) while length > 4 delete_at(0) end super(restaurant) end end
In the application controller, I exposed a helper method to allow access to recent_restaurants
def recent_restaurants @_recent_restaurants ||= RecentRestaurants.new(cookies) end helper_method :recent_restaurants
And then, in a view or controller, you can easily do things like
class RestaurantsController < ApplicationController def show @restaurant = Restaurant.find(params[:id]) # Add a restaurant recent_restaurants.push(@restaurant) # Access all recent restaurants easily recent_restaurants end end
This cleans things up quite a bit and makes it easier to work with in a consistent way. It could easily be extended to be used with Sessions, as well.