使用Datamapper在Sinatra中选择,复选框和单选按钮元素

时间:2012-11-30 03:57:15

标签: ruby sinatra haml

将Datamapper与Sinatra一起使用,保存文本属性非常简单:

DataMapper::setup(:default, "sqlite3://#{Dir.pwd}/tailor.db")  
class Person  
  include DataMapper::Resource  
  property :id, Serial  
  property :name, String, :required => true
  property :height, String, :required => false
end  
DataMapper.finalize.auto_upgrade!

...

put '/:id/edit' do
  p = Person.get params[:id]
  p.name = params[:name]
  p.height = params[:height]
  p.save
end

观点:

%form
  %input{:type => 'text', :name => 'name'}
  %input{:type => 'text', :name => 'height'}
  %input{:type => 'submit', :value => 'Save'}

使用:type => 'text'这是一件轻而易举的事。但是,我在尝试使用复选框设置布尔值(property :test, Boolean, :required => false)时遇到了麻烦。 This question类似,但没有解决如何做一个简单的布尔值。

此外,设置不接受任何字符串的值的最简单方法是什么,而只是一组预定义的选项 - 作为允许一个选择的选择,或者允许多个选项的一组单选按钮?

修改

我想出了复选框:

p.bool = !params[:bool].nil?

并在视图中:

  %input{:type => 'checkbox', :name => 'bool', :value => "#{@bool}", :checked => @p.bool}

1 个答案:

答案 0 :(得分:5)

当您提交带有checkbox的表单时,如果您未指定value表单,则默认为字符串on。此外,如果未选中该复选框,则根本不会提交。结果是,在您的处理程序中,params[:test](假设checkbox被命名为test)如果未选中则为nil,或者为on字符串如果是的话。

Datamapper中的布尔属性期望被分配布尔值(truefalse)或small set of values that it will implicitly convert之一。 onnil不属于这些值,因此当您尝试将值分配给Datamapper时,它将无法通过验证而无法保存:

...
p.test = 'on'
if !p.save
  p p.errors[:test]
end

产生

["Test must be of type TrueClass"]

解决此问题的一种方法是检入处理程序并在分配给属性时将值显式转换为布尔值:

p.test = params[:test] == 'on' ? true : false

另一种方法是将HTML复选框中的value设置为Datamapper将转换的值之一,以便您可以直接传递它。您可以在表单中使用多个具有相同名称的控件,它们将按照它们在页面中显示的顺序提交。 Sinatra将仅在创建params哈希时使用最后一个,因此如果您添加hidden输入与复选框之前的复选框相同的名称,那么如果是未检查该值将是隐藏输入的值。如果选中它,它的值将覆盖隐藏输入的值。

%input{:type => 'hidden', :name => 'foo', :value => 'f'}
%input{:type => 'checkbox', :name => 'foo', :value => 't'}

现在params[:test]将是'f''t',这两个Datamapper都会为您转换,因此您只需执行

p.test = params[:test]