web-dev-qa-db-fra.com

Ruby on Rails: Soumettre un tableau dans un formulaire

J'ai un modèle qui a un attribut qui est un tableau. Quelle est la bonne façon pour moi de renseigner cet attribut à partir d'une soumission de formulaire?

Je sais qu'une entrée de formulaire avec un champ dont le nom inclut des crochets crée un hachage à partir de l'entrée. Devrais-je simplement prendre cela et passer à travers dans le contrôleur pour le masser dans un tableau?

Exemple pour le rendre moins abstrait:

class Article
  serialize :links, Array
end

La variable links se présente sous la forme d’un tableau d’URL, c.-à-d. [["http://www.google.com"], ["http://stackoverflow.com"]]

Lorsque j'utilise quelque chose comme ce qui suit dans mon formulaire, cela crée un hachage:

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

Le hachage résultant ressemble à ceci: 

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

Si je n'inclus pas l'URL dans le nom du lien, des valeurs supplémentaires s'imbriquent:

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

Le résultat ressemble à ceci: "links" => "http://stackoverflow.com"

60
William Jones

Si votre formulaire html comporte des champs de saisie avec des crochets vides, ils seront transformés en un tableau à l'intérieur des paramètres du contrôleur. 

# 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

Ajoutée:

Notez que les helpers Rails sont not setup pour effectuer le tour de matrice de manière automatique. Vous devrez donc peut-être créer les attributs name manuellement. De plus, les cases à cocher ont leurs propres problèmes si les aides de Rails sont utilisées, car elles créent des champs cachés supplémentaires pour gérer le cas non vérifié.

83
Larry K
= simple_form_for @article do |f|
  = f.input_field :name, multiple: true
  = f.input_field :name, multiple: true
  = f.submit
45
stAndrei

TL; DR version de HTML convention []:

Tableau:

<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">

Paramètres reçus:

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

Hacher

<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">

Paramètres reçus:

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

J'ai également découvert que, si vous réussissiez votre assistant de saisie comme ceci, vous obtiendrez un tableau de cours, chacun avec ses propres attributs.

# 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    
8
Ana Franco

Je viens de mettre en place une solution utilisant jquery taginput: 

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

J'ai écrit une extension simple_form personnalisée

# 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

Un extrait de café:

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

Et un Tweak à mon contrôleur, qui doit malheureusement être légèrement spécifique: 

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

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

Pour ceux qui utilisent un formulaire simple, vous pouvez envisager cette solution. Fondamentalement, vous devez configurer votre propre entrée et l’utiliser comme: array. Ensuite, vous devrez gérer les entrées au niveau de votre contrôleur.

#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

Dans votre cas, remplacez simplement: premium_keyword par le champ votre tableau.

0
sovanlandy