2

I have a very basic form, with some very basic validations (though I need to create a custom validation later... you'll probably see a question on that tomorrow. =P ), but I'm having trouble showing the user the validation errors.

Here's my main Sinatra file:

$LOAD_PATH.unshift(File.dirname(__FILE__))
require 'sinatra'
require 'rubygems'
require 'datamapper'
require 'dm-core'
require 'dm-validations'
require 'lib/authorization'

DataMapper::setup(:default, "sqlite3://#{Dir.pwd}/entries.db")

class Entry
include DataMapper::Resource

property :id,           Serial
property :first_name,   String, :required => true
property :last_name,    String, :required => true
property :email,        String, :required => true, :unique => true,
                        :format => :email_address, :messages => { 
                            :presence => "You have to   enter your email address", 
                            :is_unique => "You've     already entered", 
                            :format => "That isn't a     valid email address" }
property :created_at,   DateTime    

end
configure :development do
# create, upgrade, or migrate tables automatically
DataMapper.auto_upgrade!
end

helpers do
include Sinatra::Authorization
end

# Set UTF-8 for outgoing
before do
headers "Content-Type" => "text/html; charset=utf-8"
end


get '/' do
@title = "Enter to win a rad Timbuk2 bag!"
erb :welcome
end

post '/' do
@entry = Entry.new(:first_name => params[:first_name], :last_name => params[:last_name], :email => params[:email])

if @entry.save
    redirect("/thanks")
else
    @entry.errors.each do |e|
        puts e
    end
    redirect('/')
end
end


get '/list' do
require_admin
@title = "List of Entries"
@entries = Entry.all(:order => [:created_at.desc])
erb :list
end

get '/thanks' do
erb :thanks
end

get '/delete/:id' do
require_admin
entry = Entry.get(params[:id])
unless entry.nil?
    entry.destroy
end
redirect('/list')
end

So, if a user tries to submit an entry with only a first name, or only a last name, or nothing at all, I can see the errors in my console, but I can't figure out how to get them in the page displayed by my main handler.

I've tried adding a div:

<% unless @entry.errors.empty? %>
<div id="errors">
    <% @entry.errors.each do |e| %>
       <p><%= e %></p>
    <% end %>
</div>
<% end %>

but I get: undefined method `errors' for nil:NilClass

user229044
  • 232,980
  • 40
  • 330
  • 338
YuKagi
  • 2,451
  • 3
  • 21
  • 26

2 Answers2

2

What happens in your case is that the redirect will clear the errors again internally. You need to store them temporarily to have them available after the redirect. From Sinatra documentation on how to pass data on through redirects:

Or use a session:

  enable :session

  get '/foo' do
    session[:secret] = 'foo'
    redirect to('/bar')
  end

  get '/bar' do
    session[:secret]
  end

So in your case this would be

get '/' do
    @title = "Enter to win a rad Timbuk2 bag!"
    @errors = session[:errors]
    erb :welcome
end

and

if @entry.save
    redirect("/thanks")
else
    session[:errors] = @entry.errors.values.map{|e| e.to_s}
    redirect('/')
end

for your Sinatra file.

Your erb file would become

<% if @errors %>
<div id="errors">
    <% @errors.each do |e| %>
       <p><%= e %></p>
    <% end %>
</div>
<% end %>
emboss
  • 38,880
  • 7
  • 101
  • 108
  • Thank you. I added the sessions code (both the enable, and the session[:errors] = @entry.errors line, but I am still getting the same NoMethod error. If my erb code for adding the div wrong? – YuKagi Jul 07 '11 at 11:56
  • That all makes total sense. Thank you, again. I am getting "TypeError at / can't dump hash with default proc" now. 0.o... – YuKagi Jul 07 '11 at 12:42
  • Hmm, did you put "enable :session" somewhere near the very top of your file? It needs to be added before the methods that use it... – emboss Jul 07 '11 at 13:33
  • in the erb file or the Sinatra file? – emboss Jul 07 '11 at 13:40
  • The session needs to be marshalled. You'll find instructions [here](http://stackoverflow.com/questions/2552363/how-can-i-marshal-a-hash-with-arrays). – emboss Jul 07 '11 at 14:30
  • I'm not sure I follow. Marshalling is totally new to me. In my main sinatra file, I'm guessing I use: @errors = Marshall.dump(session[:errors]) Is that right? – YuKagi Jul 07 '11 at 14:52
  • @emboss let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/1219/discussion-between-yukagi-and-emboss) – YuKagi Jul 07 '11 at 14:52
  • @meager It should be plural: `enable :sessions` instead of singular `enable :session` [docs](http://www.sinatrarb.com/intro.html#Using%20Sessions) – Tim Inman Jan 08 '13 at 13:39
0

Can you try this :

post '/' do
  @entry = Entry.new(:first_name => params[:first_name], :last_name => params[:last_name], :email => params[:email])

  if @entry.save
    redirect("/thanks")
  else
    @title = "Enter to win a rad Timbuk2 bag!"
    erb: welcome
  end
end
Michel
  • 706
  • 3
  • 6