module Lolita
module Configuration
# Accept those attributes
# * :name - Name of nested relation, like :comments.
# * :field_style - Is fields rendered with as normal (with lable and staff) or like in table (:simple). Default :simple
# * :expandable - Show or not "Add new" and "Delete" links in form,
# by default, it is expandable if association macro is :many
# * :field_rejection_proc - Proc, that contains condition of how to reject field.
# By default form rejects all fields from parent tab that doesn't have current form as field nested_form
# ====Example
# form = Lolita::Configuration::NestedForm.new(Lolita::Configuration::Tab::Content.new,:comments)
# form.field_rejection_proc = Proc.new{|field|
# field.name.to_s.match(/_id$/)
# }
# # form exclude all fields that ends with _id
class NestedForm
include Lolita::Builder
@@last_nested_form=0
attr_reader :parent, :options, :field_style
attr_accessor :name, :expandable, :field_rejection_proc
attr_writer :build_method
def initialize parent,name=nil, options ={}
@parent=parent
@options = options
self.name=name || "nested_form_#{next_nested_form}"
set_attributes_from(options)
end
def allow_destroy?
dbi.klass.nested_attributes_options[name][:allow_destroy]
end
def update_only?
dbi.klass.nested_attributes_options[name][:update_only]
end
def build_method
@build_method || self.name
end
# Set field style - normal or simple. Default - normal.
def field_style=(value)
allowed_values = [:normal,:simple]
raise ArgumentError, "Only #{allowed_values.inspect} are allowed" unless allowed_values.include?(value)
@field_style = value
end
# Detect if it's possible to add more than one field group, like if model has many other objects.
def expandable?
@expandable == true || (@expandable == nil && macro == :many)
end
# Create field, that is not real field, but represents nested attributes as one.
# It is used to create label.
def as_field
Lolita::Configuration::Factory::Field.add(dbi,self.name, :string)
end
# Parent (a.k.a tab) dbi
def dbi
@parent.dbi
end
# Fields setter. Fields should be array and each element should be Lolita::Configuration::Field object.
def fields=(new_fields)
@fields = new_fields
end
# Return all fields. Each time fields ar returned from @fields if its defined or calculated by using #field_rejection_proc
# or collected from parent (tab) where fields nested form is same with self.
def fields
if @fields
@fields
elsif field_rejection_proc
self.parent.fields.reject(&field_rejection_proc)
else
self.parent.fields.reject{|f| f.nested_form!=self}
end
end
# Parent (tab) dbi klass
def klass
dbi.reflect_on_association(name).klass
end
# Parent (tab) dbi klass reflection with #name and macros of that.
def macro
dbi.reflect_on_association(name).macro
end
private
def next_nested_form
@@last_nested_form+=1
end
def set_attributes_from(options)
options.each{|key,value|
instance_variable_set(:"@#{key}",value)
}
end
end
end
end