Ruby on Rails: отправка массива в форме

У меня есть модель, которая имеет атрибут, который является массивом. Как мне правильно заполнить этот атрибут при отправке формы?

Я знаю, что ввод формы с полем, имя которого включает в себя скобки, создает хэш из ввода. Должен ли я просто взять это и пройти через контроллер, чтобы массировать его в массив?

Пример, чтобы сделать его менее абстрактным:

class Article
  serialize :links, Array
end

Переменная links принимает форму массива URL, т.е. [["http://www.google.com"], ["http://stackru.com"]]

Когда я использую что-то вроде следующего в моей форме, это создает хэш:

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

Результирующий хеш выглядит так:

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

Если я не включу URL-адрес в название ссылки, дополнительные значения перекрывают друг друга:

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

Результат выглядит так: "links" => "http://stackru.com"

8 ответов

Решение

Если ваша HTML-форма имеет поля ввода с пустыми квадратными скобками, то они будут превращены в массив внутри параметров в контроллере.

# 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, поскольку помощники флажков создают дополнительные скрытые поля для обработки неконтролируемого случая.

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

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' } }

Я также узнал, что если вы передадите свой помощник ввода таким образом, вы получите массив курсов, каждый со своими атрибутами.

# 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    

Я просто создал решение, используя 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

У меня была аналогичная проблема, но я хотел, чтобы пользователь вводил серию элементов, разделенных запятыми, в качестве значения для массива. Моя миграция использует новую способность 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: [])

Теперь пользователь может вводить столько ссылок, сколько хочет, и форма ведет себя правильно как при создании, так и при обновлении. И я все еще могу использовать сильные параметры.

Для тех, кто использует простую форму, вы можете рассмотреть это решение. В основном нужно настроить свой собственный ввод и использовать его как: массив. Тогда вам нужно будет обрабатывать ввод на уровне вашего контроллера.

#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 на поле вашего массива

У меня возникли проблемы с редактированием массива после реализации этого для моего new.html.erb, поэтому я оставлю свое решение этой проблемы здесь:

Редактировать свойство модели массива типов с помощью формы Rails?

Другие вопросы по тегам