views:

179

answers:

5

I have a simple model called Party with a corresponding table called parties. There's also a controller with all the usual CRUD actions and so on. This model is used in a website and only one admin user is allowed to edit the parties - everyone else is allowed to call GET actions (index, show). Nothing special so far.

Now I need to do the following: The admin would like to choose a single Party at a time for special presentation (the selected Party is showing up on the start page of the application). The most important thing is, that there's only ONE party at time selected.

How would you solve this problem? Boolean Flag in Party model? Save the selection (id of the party) somewhere outside the database? Implement a new model with a has_one relation to Party (seems like overkill to me)?

I hope my explanation is good enough to understand the issue.

+2  A: 

I would go for the boolean flag and create nested singleton resource (promoted), which I would implement in PartiesController itself (set_promoted_party and get_promoted_party actions). For these I would create two new routes:

PUT /parties/promoted/:party_id # to set the promoted party
GET /parties/promoted/:party_id # to get the promoted_party
Milan Novota
A: 

Personally I'm very strong on data integrity being enforced by my database so would probably add that extra table and enforce it as a foreign key constraint there. It can seem like overkill, but is the only* solution that prevents data integrity issues.

Could you maybe add it as a field to the admin table/model - which would be an enforced foreign key to the party table?

*Another solution would be a database trigger that checks no other rows are the selected party but I tend to shy away from such solutions.

Darren Greaves
I always enforce my domain rules in the database (e.g. the party must have a location and a date), but feel application specific logic can happily live in the model. In future they may promote more than 1 party or promote different parties to different users. Business rule = model for me.
RichH
+3  A: 

A simple "front_page" attribute would suffice or another model like you mentioned, using the has_one relationship would be fine as well.

Using another model would allow you to maintain some more information, like how long should it remain on the front page (expiration date?) or how many times it was featured (assuming a party can be featured twice). It really depends on other requirements for your system.

You also might be able to get away with a simple implementation of the Singleton pattern as well. There's a quick description on the Rails Wiki of making an ActiveRecord object a Singleton (see below): http://wiki.rubyonrails.org/rails/pages/TipsAndTricks

Making a singleton ActiveRecord object

If you have a table with just one entry, useful for keeping track of a number sequence for databases without sequences, you can use the singleton module included with ruby like so:

require 'singleton'

class Master < ActiveRecord::Base
  include Singleton
  def initialize(args=nil) super(args) if record = Master.find(:first)    
    self.attributes = record.attributes end end def next_tracking_number increment!
    (:current_tracking_number) current_tracking_number end def 
    self.next_tracking_number instance.next_tracking_number 
  end
end

Update:

This is a very poor code example (was copied and pasted from the Rails Wiki, which had no formatting). I would highly recommend the [Ruby Design Patterns] book which tackles many of the GoF design patterns in greater detail (while making them applicable to Ruby applications). But Google should return you some good resources for using the Singleton pattern in Ruby.[2]

mwilliams
+1  A: 

I would add a second model that had a has_one relationship in order to keep the app RESTful and simple. Also, this way, you can keep a history of special Parties, and track other meaningful information related to the special parties.

The model has nothing to do with the application being RESTful - thats all about the controllers. Two controllers -> 1 model is fine.That said, I'd add the second model too!
RichH
A: 

Keep it simple. Put a promoted_party.yml file in your config directory that the controllers write to and read from. The contents can be as simple as this:

--- 
party_id: 123

Done. If you need more integrity or fancier relationships later, implement that later, not now.

For deployments, just make sure the file is symlinked to a shared directory to survive application upgrades.

Ryan McGeary