Reputation: 1527
I have model Info.rb for keeping info of all exhibitions and contests
class Info < ActiveRecord::Base
serialize :exhibition, Array
serialize :contest, Array
end
I want to have ability of editing updating and adding new elements to exhibiton and contest arrays . This is my info_controller.rb
class Admin::InfoController < ApplicationController
before_action :find_info, only: [:edit, :update]
def index
@info = Info.all
end
def edit
end
def update
@info.update_attributes(info_params)
redirect_to admin_info_index_path
end
private
def find_info
@info = Info.first
end
def info_params
params.require(:info).permit({:contest => []}, {:exhibition => []})
end
end
I can't get how create proper edit form with single field for every element in arrays. Will appreciate any help.
Upvotes: 0
Views: 274
Reputation: 3407
In your model, you can dynamically assign attributes from the keys of the serialized Hash, or Array. I've done something similar so am munging my code for a few examples below. Basically , by dynamically creating virtual attributes, using a DSL like Formtastic becomes much easier.
With serialized Arrays :
class Info < ActiveRecord::Base
serialize :exhibition, Array
serialize :contest, Array
after_initialize :explode_exhibition
after_initialize :explode_contest
before_save :implode_exhibition
before_save :implode_contest
private
def explode_exhibition()
exhibition.each_with_index do |v,i|
self.class.send(:attr_accessor, "@exhibition_#{i}")
self.instance_variable_set("@exhibition_#{i}", v)
end
end
def explode_contest()
contest.each_with_index do |v,i|
self.class.send(:attr_accessor, "@contest_#{i}")
self.instance_variable_set("@contest_#{i}", v)
end
end
def implode_exhibition()
exhibition = []
self.methods.grep(/exhibition_/).each do |method_name|
exhibition << self.instance_variable_get("@#{method_name}", v)
end
end
def implode_contest()
contest = []
self.methods.grep(/contest_/).each do |method_name|
contest << self.instance_variable_get("@#{method_name}", v)
end
end
end
With serialized Hashes :
class Info < ActiveRecord::Base
serialize :exhibition, Hash
serialize :contest, Hash
after_initialize :explode_exhibition
after_initialize :explode_contest
before_save :implode_exhibition
before_save :implode_contest
private
def explode_exhibition()
exhibition.each do |k,v|
self.class.send(:attr_accessor, "@exhibition_#{k}")
self.instance_variable_set("@exhibition_#{k}", v)
end
end
def explode_contest()
contest.each do |k,v|
self.class.send(:attr_accessor, "@contest_#{k}")
self.instance_variable_set("@contest_#{k}", v)
end
end
def implode_exhibition()
exhibition.each do |k,v|
exhibition[k] = self.instance_variable_get("@exhibition_#{k}", v)
end
end
def implode_contest()
contest.each do |k,v|
contest[k] = self.instance_variable_get("@contest_#{k}", v)
end
end
end
And then in Formtastic you can access the attributes and build a form dynamically for each virtual attribute. Note the regex, can use some iteration, as it currently will only match self.exhibition_0 through self.exhibition_9, but it also excludes any setter methods by not matching methods like self.exhibition_0=
f.object.methods.grep(/^exhibition_.*?(?<!=)$/).each do |method_name|
f.input method_name
end
I haven't fully tested this munged code, but the majority of this I have working in a few of my own classesn. Also, there may be a need to dynamically create the setter methods as well. Let me test this out a bit, and improve on this idea.
Upvotes: 2