Как показать сериализованный атрибут Array для модели Rails ActiveRecord в форме?

Мы используем функцию "serialize" ActiveRecord в Rails, например:

class User < ActiveRecord::Base
    serialize :favorite_colors, Array
    ....
end

Итак, мы можем иметь

u = User.last
u.favorite_colors = [ 'blue', 'red', 'grey' ]
u.save!

Таким образом, в основном ActiveRecord сериализует массив выше и сохраняет его в одном поле базы данных с именем favorite_colors.

Мой вопрос: как вы позволяете пользователю вводить свои любимые цвета в форме? Вы используете серию текстовых полей? И как только они будут введены, как вы показываете их в форме для редактирования?

Это вопрос, связанный с помощниками формы Rails для атрибута сериализованного массива.

Спасибо

Ответ 1

Если вы хотите многоточечное поле HTML, попробуйте:

= form_for @user do |f|
  = f.select :favorite_colors, %w[full colors list], {}, :multiple => true

Если вы используете simple_form gem, вы можете легко представить варианты:

= simple_form_for @user do |f|
  = f.input :favorite_colors, as: :check_boxes, collection: %w[full colors list]

Ответ 2

Чтобы разрешить доступ к атрибутам AR, вы должны предоставить их следующим образом:

class User < ActiveRecord::Base
  serialize :favorite_colors, Array
  attr_accessible :favorite_colors
  ....
end

Ответ 3

Я решил эту проблему, "сглаживая" массив в представлении и восстановление массива в контроллере.

В модели также требуются некоторые изменения, см. ниже.

class User < ActiveRecord::Base

    serialize :favorite_colors, Array

    def self.create_virtual_attributes (*args)
        args.each do |method_name|
            10.times do |key|
                define_method "#{method_name}_#{key}" do
                end
                define_method "#{method_name}_#{key}=" do
                end
            end
        end
    end

    create_virtual_attributes :favorite_colors
end

Если вы не определяете такие методы, как указано выше, Rails будет жаловаться на элемент формы имена в представлении, например "favorite_colors_0" (см. ниже).

В представлении я динамически создаю 10 текстовых полей, favorite_colors_0, favorite_colors_1 и т.д.

<% 10.times do |key| %>
    <%= form.label :favorite_color %>
    <%= form.text_field "favorite_colors_#{key}", :value => @user.favorite_colors[key] %>
<% end %>

В контроллере я должен объединить текстовые поля favorite_colors_ * в массив, прежде чем звонить save или update_attributes:

unless params[:user].select{|k,v| k =~ /^favorite_colors_/}.empty?
    params[:user][:favorite_colors] = params[:user].select{|k,v| k =~ /^favorite_colors_/}.values.reject{|v| v.empty?}
    params[:user].reject! {|k,v| k=~ /^favorite_colors_/}
end

Одна вещь, которую я делаю, это жесткий код 10, который ограничивает количество элементов, которые вы можете иметь в массиве favorite_colors. В форме он также выводит 10 текстовых полей. Мы можем легко изменить 10 - 100. Но у нас все еще будет предел. Ваше предложение о том, как удалить этот предел, приветствуется.

Надеюсь, вы сочтете это сообщение полезным.