57 votes

Comment modifier un Rails de sérialisé champ dans un formulaire?

J'ai un modèle de données dans mon Rails de projet qui a un sérialisé champ:

class Widget < ActiveRecord::Base
  serialize :options
end

Les options de champ peut avoir des données de la variable info. Par exemple, voici les options de champ pour l'enregistrement de l'luminaires fichier:

  options:
    query_id: 2 
    axis_y: 'percent'
    axis_x: 'text'
    units: '%'
    css_class: 'occupancy'
    dom_hook: '#average-occupancy-by-day'
    table_scale: 1

Ma question est de savoir quelle est la bonne façon de permettre à l'utilisateur de modifier cette info dans un formulaire standard vue?

Si vous utilisez seulement un simple champ de texte pour le champ des options, vous obtenez juste un yaml vidage de la représentation et que les données voudrais juste être renvoyé à une chaîne.

Quel est le meilleur/la bonne façon de modifier un sérialisé de hachage domaine comme celui-ci dans les Rails?

58voto

austinfromboston Points 3174

Si vous connaissez les touches d'option, allez à l'avance, vous pouvez déclarer spécial des getters et setters pour eux de la sorte:

class Widget < ActiveRecord::Base
  serialize :options

  def self.serialized_attr_accessor(*args)
    args.each do |method_name|
      eval "
        def #{method_name}
          (self.options || {})[:#{method_name}]
        end
        def #{method_name}=(value)
          self.options ||= {}
          self.options[:#{method_name}] = value
        end
        attr_accessible :#{method_name}
      "
    end
  end

  serialized_attr_accessor :query_id, :axis_y, :axis_x, :units
end

La bonne chose à ce sujet est que l'on expose les composantes du tableau options d'attributs, ce qui vous permet d'utiliser les Rails forme aides comme:

#haml
- form_for @widget do |f|
  = f.text_field :axis_y
  = f.text_field :axis_x
  = f.text_field :unit

41voto

Christian Butzke Points 526

Eh bien, j'ai eu le même problème, et j'ai essayé de ne pas trop ingénieur. Le problème, c'est que bien que vous pouvez passer à la sérialisé de hachage pour fields_for, les champs pour fonction de penser, c'est une option de hachage (et pas de votre objet), et de définir la forme de l'objet à néant. Cela signifie, que bien que vous pouvez modifier les valeurs, elles n'apparaissent pas après le montage. Il peut-être un bug ou un comportement inattendu de rails et peut-être résolu dans l'avenir.

Cependant, pour l'instant, il est assez facile à faire (même si ça m'a pris toute la matinée pour comprendre).

Vous pouvez vous laisser le modèle tel qu'il est et dans la vue que vous avez besoin de donner les champs de l'objet comme une struct. Qui va définir correctement l'objet d'enregistrement (donc f2.l'objet sera de retour de vos options) et d'autre part il permet à l'text_field l'accès au générateur de la valeur de votre objet/params.

Depuis que j'ai inclus " || {}", il va travailler avec de nouveaux/créer des formes, trop.

= form_for @widget do |f|
  = f.fields_for :options, OpenStruct.new(f.object.options || {}) do |f2|
    = f2.text_field :axis_y
    = f2.text_field :axis_x
    = f2.text_field :unit

Une bonne journée

29voto

sbzoom Points 766

emh est presque là. Je pense que les Rails serait de retour les valeurs pour les champs de formulaire, mais il ne le fait pas. De sorte que vous pouvez juste le mettre dans n'manuellement dans l' ":valeur =>" paramètre pour chaque champ. Il n'a pas l'air de nappe, mais il fonctionne.

Ici, c'est de haut en bas:

class Widget < ActiveRecord::Base
    serialize :options, Hash
end

<%= form_for :widget, @widget, :url => {:action => "update"}, :html => {:method => :put} do |f| %>
<%= f.error_messages %>
    <%= f.fields_for :options do |o| %>
        <%= o.text_field :axis_x, :size => 10, :value => @widget.options["axis_x"] %>
        <%= o.text_field :axis_y, :size => 10, :value => @widget.options["axis_y"] %>
    <% end %>
<% end %>

Tous les champs que vous ajoutez dans le "fields_for" apparaîtra dans la sérialisé de hachage. Vous pouvez ajouter ou supprimer des champs. Ils seront transmis sous la forme d'attributs pour les "options" de hachage et stockées en YAML.

3voto

gamov Points 968

Pas besoin de poseur/getters, j'ai juste défini dans le modèle:

serialize :content_hash, Hash

Puis dans la vue, j'ai fais (avec simple_form, mais similaire à la vanille, avec des Rails):

  = f.simple_fields_for :content_hash do |chf|
    - @model_instance.content_hash.each_pair do |k,v|
      =chf.input k.to_sym, :as => :string, :input_html => {:value => v}

Ma dernière question est de savoir comment permettre à l'utilisateur d'ajouter une nouvelle paire clé/valeur.

1voto

emh Points 656

Je suis en train de faire quelque chose de similaire et j'ai trouvé ce genre de travaux:

<%= form_for @search do |f| %>
    <%= f.fields_for :params, @search.params do |p| %>
        <%= p.select "property_id", [[ "All", 0 ]] + PropertyType.all.collect { |pt| [ pt.value, pt.id ] } %>

        <%= p.text_field :min_square_footage, :size => 10, :placeholder => "Min" %>
        <%= p.text_field :max_square_footage, :size => 10, :placeholder => "Max" %>
    <% end %>
<% end %>

sauf que les champs du formulaire ne sont pas remplies lorsque le formulaire est rendu. lorsque le formulaire est soumis viennent les valeurs par le biais de très bien et je peux faire:

@search = Search.new(params[:search])

donc sa "moitié" de travail...

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X