将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}
答案 0 :(得分:5)
当您提交带有checkbox
的表单时,如果您未指定value
表单,则默认为字符串on
。此外,如果未选中该复选框,则根本不会提交。结果是,在您的处理程序中,params[:test]
(假设checkbox
被命名为test
)如果未选中则为nil
,或者为on
字符串如果是的话。
Datamapper中的布尔属性期望被分配布尔值(true
或false
)或small set of values that it will implicitly convert之一。 on
和nil
不属于这些值,因此当您尝试将值分配给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]