Sinatra没有从params解析数组

时间:2013-02-25 14:41:50

标签: sinatra params padrino

我有一个像这样的隐藏表格:

= form_for movie, 'create', method: 'POST' do |f|
  - Movie.attribute_names.each do |attr|
   = f.hidden_field attr.to_sym, value: movie.send(attr)
  = f.submit 'Save this Movie', class: 'button'

这些属性中的一些是序列化数组,但是padrino似乎不是从字符串解析数组,所以当我尝试从存储在params中的这个attr哈希中保存记录时,db会引发序列化错误:

{"title"=>"Iron Man 2",
 "directors"=>"[\"Jon Favreau\"]",
 "cast_members"=>"[\"Robert Downey Jr.\", \"Gwyneth Paltrow\", \"Don Cheadle\", \"Scarlett Johansson\", \"Sam Rockwell\"]",
 "genres"=>"[\"Action\", \"Adventure\", \"Sci-Fi\"]",
 "length"=>"124",
 "trailer_url"=>"http://imdb.com/video/screenplay/vi1172179225/",
 "year"=>"2010",
 "languages"=>"[\"English\", \"French\", \"Russian\"]"}

我可以用这个丑陋的代码块解析数组字符串:

Movie.serialized_attributes.keys.each do |k|
  movie[k] = movie[k].gsub(/\"|\[|\]/, '').split(', ') if movie[k]
end

但这似乎只是愚蠢,sinatra应该自动解析它(或不?),或者我可能正在以错误的方式生成表单。 如何解决此问题?

注意:刚尝试生成这样的表单:

- Movie.attribute_names.each do |attr|
   - if Movie.serialized_attributes.keys.include? attr
     = f.hidden_field attr.to_sym, value: movie.send(attr), multiple: true
   - else
     = f.hidden_field attr.to_sym, value: movie.send(attr)

2 个答案:

答案 0 :(得分:1)

我的建议是避免以数组和散列的形式发送数据。您尝试发送的数据可以很容易地作为一个字符串发送,然后在另一侧进行拆分。例如,为什么不将演员发送为逗号分隔的字符串,然后在收到时发送param["cast_members"].split(/\s*,\s*/)?某种自动提示是谨慎的,或者你最终会有很多拼写错误的名字。这将通过在发送数据之前用slugs 替换条目来帮助您进一步分隔数据。看看StackOverflow处理标记字段的方式。

如果你真的需要作为数组发送,可以考虑将其转换为JSON,然后在另一端发送和反序列化,而不是自己动手。

答案 1 :(得分:0)

我希望尽可能保持LOC和可读性,因此使用AJAX解决了这个问题:

= link_to 'Save this movie', class: 'button', id: "create_movie_#{movie_id}"
- content_for :scripts do
  :javascript
    $(function(){
      $('#create_movie_#{movie_id}').on('click', function(){
        $.post("/movies/create.json",
        {movie: #{movie.to_json}},
        function(r){
          console.log('Response arrived:')
          console.log(r)
        })
      })
    })

# controller.rb
post :create, provides: [:html, :json] do
  case content_type
  when :json
    Movie.create(params[:movie]).to_json
  when :html
    if @movie = Movie.create(params[:movie])
      render 'movies/show'
    else
      redirect 'movies/fetch', error: 'Something went wrong'
    end
  end
end