views:

95

answers:

1

I'm trying to make a simple room management service. The rooms have these properties:

class Room
  include DataMapper::Resource
  validates_is_unique :number

  property :id, Serial
  property :number, Integer
  property :guest, String
  property :status, Enum[ :free, :occupied ], :default => :free
end

Then I create a new room like this

post '/new' do
  content_type :json
  @room = Room.new :guest => params[:guest],
                   :number => params[:number],
                   :status => params[:status]
  if @room.save
    { :number => @room.number, :guest => @room.guest, :status => @room.status }.to_json
  end
end

through this haml form

%form#new_message{:action => '/new', :method => 'post'}
        %p
          %input{:type => "text",      :id => "number", :name => "number"}
          %input{:type => "text",      :id => "guest",  :name => "guest"}
          %input{:type => "checkbox",  :id => "status", :name => "status", :value => "occupied"}
          %input{:type => "submit", :value => "post"}

When the box is checked the :status is "occupied" but when I leave it unchecked the object won't save. I thought it would work since it is defaulted to "free" but no...

A: 

For whatever stupid reason, checkboxes do not get submitted if they are not clicked. This means they are not in the hash that hits your app. When you say :status => params[:status] you are really saying :status => nil. Since you have set a value, it checks that against your enum, and nil is not in your enum, so it fails validations. (based on how you are using this, doesn't it seem like it should be a boolean called either "occupied" or "available" ?)

Anyway, you could either explicitly set it to free, or not set it at all, and let the default take care of it. That is what I opted for when checking it, by moving it into a mass assignment. The code I used is below.

require 'rubygems'
require 'sinatra'
require 'haml'
require 'dm-core'
require 'dm-validations'
require 'dm-types'
require 'dm-migrations'
require 'sqlite3'


configure do
  class Room
    include DataMapper::Resource
    validates_uniqueness_of :number
    property :id, Serial
    property :number, Integer
    property :guest, String
    property :status, Enum[ :free, :occupied ], :default => :free
  end
  set :sessions , true
  DataMapper::Logger.new($stdout, :debug)
  DataMapper.setup( :default , "sqlite3://#{Dir.pwd}/development.sqlite3" )  
  DataMapper.finalize
  DataMapper.auto_upgrade!
end


get '/' do
  @rooms = Room.all
  haml :index
end

post '/new' do
  p params
  @room = Room.new params[:room]
  if @room.save
    session[:flash] = "room reserved"
    redirect '/'
  else
    session[:flash] = @room.errors.to_a
    redirect '/new'
  end
end

get '/new' do
  haml :new
end

__END__
@@layout
!!!
%html
  #flash
    = session[:flash].inspect
  = yield

@@new
%form#new_message{:action => '/new', :method => 'post' , :name => 'room' }
  %p
    %input{:type => "text",      :id => "number", :name => "room[number]"}
    %input{:type => "text",      :id => "guest",  :name => "room[guest]"}
    %input{:type => "checkbox",  :id => "status", :name => "room[status]", :value => "occupied"}
    %input{:type => "submit", :value => "post"}

@@index
%table
  - @rooms.each do |room|
    %tr
      %td= room.number
      %td= room.guest
      %td= room.status
Joshua Cheek
Oh that's why...well this works. Cool. Thank you. I was thinking about making it a boolean but I would rather call room.status (available/occupied) than room.free (true/false).
theory