Ruby on Rails:以表单提交数组


75

我有一个模型,其属性为数组。我从表单提交中填充该属性的正确方法是什么?

我知道有一个带有字段名称(包括方括号)的表单输入会从输入中创建一个哈希。我是否应该仅接受它并逐步进入控制器以将其按摩成阵列?

使其抽象程度降低的示例:

class Article
  serialize :links, Array
end

links变量采用URL数组的形式,即 [["http://www.google.com"], ["http://stackoverflow.com"]]

当我在表单中使用类似以下内容的内容时,它会创建一个哈希:

<%= hidden_field_tag "article[links][#{url}]", :track, :value => nil %>

产生的哈希看起来像这样:

"links" => {"http://www.google.com" => "", "http://stackoverflow.com" => ""}

如果我未在链接名称中包含url,则其他值会相互干扰:

<%= hidden_field_tag "article[links]", :track, :value => url %>

结果看起来像这样: "links" => "http://stackoverflow.com"

Answers:


94

如果您的html表单的输入字段带有空方括号,则它们将被转换为控制器中params内的数组。

# Eg multiple input fields all with the same name:
<input type="textbox" name="course[track_codes][]" ...>

# will become the Array 
   params["course"]["track_codes"]
# with an element for each of the input fields with the same name

添加:

需要注意的是导轨佣工都没有设置做阵列伎俩自动神奇。因此,您可能必须手动创建名称属性。此外,如果使用rails助手,则复选框也有其自身的问题,因为复选框助手会创建其他隐藏字段来处理未选中的情况。


1
如果你关心数组元素的顺序将保留,并希望成为真正挑剔的标准,它可能是值得一读的这个问题。听起来好像HTML规范所暗示的,但并不是100%清楚,应该保留顺序,但是所有浏览器似乎都这样做。
antinome

HTML一样<input name="course[track_codes][][field1]" multiple /><input name="course[track_codes][][field2]" multiple />会产生PARAMS{course: {track_codes: [{field1: "yourvalue", field2: "yourvalue"},{field1: "yourvalue", field2: "yourvalue"}]}}
法布里奇奥Bertoglio

56
= simple_form_for @article do |f|
  = f.input_field :name, multiple: true
  = f.input_field :name, multiple: true
  = f.submit

这就是我想要的!
emptywalls 2014年

14
请添加说明此代码的作用。这样的答案不是很有帮助。
idmean 2015年

1
接受的答案应进行更新以包括此multiple: true更新,这显然是可行的方法。
DannyB '16

4
f.input :name, input_html: { multiple: true }可以用于输入
Canbey Bilgili,

1
f.input: name, multiple: true, value: ...还与Rails的母语form_for @article do |f|
亚历克西斯德拉哈耶

48

TL; DR版本的HTML[]约定:

数组:

<input type="textbox" name="course[track_codes][]", value="a">
<input type="textbox" name="course[track_codes][]", value="b">
<input type="textbox" name="course[track_codes][]", value="c">

收到的参数:

{ course: { track_codes: ['a', 'b', 'c'] } }

杂凑

<input type="textbox" name="course[track_codes][x]", value="a">
<input type="textbox" name="course[track_codes][y]", value="b">
<input type="textbox" name="course[track_codes][z]", value="c">

收到的参数:

{ course: { track_codes: { x: 'a', y: 'b', z: 'c' } }

有没有一种方法可以使用simple_form生成那些?
Filipe Esperandio

2
@FilipeEsperandiof.input "course[track_codes][x]"
bjacobs

8

我还发现,如果像这样通过您的输入助手,您将获得一系列课程,每个课程都有其自己的属性。

# Eg multiple input fields all with the same name:
<input type="textbox" name="course[][track_codes]" ...>

# will become the Array 
   params["course"]

# where you can get the values of all your attributes like this:
   params["course"].each do |course|
       course["track_codes"]
   end    

7

我只是使用jquery taginput设置了一个解决方案:

http://xoxco.com/projects/code/tagsinput/

我写了一个自定义的simple_form扩展名

# for use with: http://xoxco.com/projects/code/tagsinput/

class TagInput < SimpleForm::Inputs::Base

  def input
    @builder.text_field(attribute_name, input_html_options.merge(value: object.value.join(',')))
  end

end

coffeescrpt代码段:

$('input.tag').tagsInput()

和我的控制器的调整,可悲的是必须稍微具体一点:

@user = User.find(params[:id])
attrs = params[:user]

if @user.some_field.is_a? Array
  attrs[:some_field] = attrs[:some_field].split(',')
end

1

我有一个类似的问题,但想让用户输入一系列用逗号分隔的元素作为数组的值。我的迁移使用Rails新功能(还是postrges的新功能?)将数组作为列类型

add_column :articles, :links, :string, array: true, default: []

然后表格可以接受此输入

<%= text_field_tag "article[links][]", @article.links %>

这意味着控制器可以如下平稳运行

def create
  split_links
  Article.create(article_params)
end

private
def split_links
  params[:article][:links] = params[:article][:links].first.split(",").map(&:strip)
end


params.require(:article).permit(links: [])

现在,用户可以输入任意数量的链接,并且表单在创建和更新时都可以正常运行。而且我仍然可以使用强大的参数。


0

对于使用简单表格的用户,您可以考虑使用此解决方案。基本上需要设置您自己的输入并将其用作:array。然后,您将需要处理控制器级别的输入。

#inside lib/utitilies
class ArrayInput < SimpleForm::Inputs::Base
  def input
    @builder.text_field(attribute_name, input_html_options.merge!({value: object.premium_keyword.join(',')}))
  end
end

#inside view/_form

...
= f.input :premium_keyword, as: :array, label: 'Premium Keyword (case insensitive, comma seperated)'

#inside controller
def update
  pkw = params[:restaurant][:premium_keyword]
  if pkw.present?
    pkw = pkw.split(", ")
    params[:restaurant][:premium_keyword] = pkw
  end

  if @restaurant.update_attributes(params[:restaurant])
    redirect_to admin_city_restaurants_path, flash: { success: "You have successfully edited a restaurant"}
  else
    render :edit
  end   
end

就您而言,只需将:premium_keyword更改为您的数组字段

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.