diff --git a/lib/active_form.rb b/lib/active_form.rb
index 069fed5..d1148bd 100644
--- a/lib/active_form.rb
+++ b/lib/active_form.rb
@@ -1,8 +1,7 @@
require 'active_form/base'
require 'active_form/form'
-require 'active_form/form_collection'
+require 'active_form/collection_form'
require 'active_form/form_definition'
-require 'active_form/too_many_records'
require 'active_form/view_helpers'
module ActiveForm
diff --git a/lib/active_form/abstract_form.rb b/lib/active_form/abstract_form.rb
new file mode 100644
index 0000000..62564d9
--- /dev/null
+++ b/lib/active_form/abstract_form.rb
@@ -0,0 +1,70 @@
+module ActiveForm
+ class AbstractForm
+ include ActiveModel::Validations
+
+ attr_reader :forms
+
+ def backing_form_for(association)
+ forms.find { |form| form.represents?(association) }
+ end
+
+ def represents?(association)
+ association_name.to_s == association.to_s
+ end
+
+ def valid?
+ super
+ model.valid?
+
+ collect_errors_from(model)
+ aggregate_form_errors
+
+ errors.empty?
+ end
+
+ def submit(params)
+ params.each do |key, value|
+ if nested_params?(value)
+ assign_association_attributes(key, value)
+ else
+ send("#{key}=", value)
+ end
+ end
+ end
+
+ def models
+ self
+ end
+
+ private
+ def nested_params?(params)
+ params.is_a?(Hash)
+ end
+
+ def reject_form?(params)
+ params.all? { |k, v| k == '_destroy' || v.blank? }
+ end
+
+ def extract_association_name(association)
+ $1.to_sym if /\A(.+)_attributes\z/ =~ association
+ end
+
+ def assign_association_attributes(association, attributes)
+ name = extract_association_name(association)
+ backing_form_for(name).submit(attributes)
+ end
+
+ def aggregate_form_errors
+ forms.each do |form|
+ form.valid?
+ collect_errors_from(form)
+ end
+ end
+
+ def collect_errors_from(model)
+ model.errors.each do |attribute, error|
+ errors.add(attribute, error)
+ end
+ end
+ end
+end
diff --git a/lib/active_form/associatable.rb b/lib/active_form/associatable.rb
new file mode 100644
index 0000000..92caf92
--- /dev/null
+++ b/lib/active_form/associatable.rb
@@ -0,0 +1,28 @@
+module ActiveForm
+ concern :Associatable do
+ def association(name, options = {})
+ association = child_class_for(options).new(name, options)
+ association_scope.add_child(association, Proc.new)
+ define_association_accessors(name, association)
+ end
+
+ def association_scope
+ self
+ end
+
+ private
+ def child_class_for(options)
+ options.key?(:records) ? CollectionAssociation : ModelAssociation
+ end
+
+ def define_association_accessors(name, association)
+ class_eval do
+ define_method(name) { association }
+ define_method("#{name}=") { |i| association.instance = i }
+ define_method("#{name}_attributes=") do |attrs|
+ association.attributes = attrs
+ end
+ end
+ end
+ end
+end
diff --git a/lib/active_form/base.rb b/lib/active_form/base.rb
index 3a916de..eea22fc 100644
--- a/lib/active_form/base.rb
+++ b/lib/active_form/base.rb
@@ -1,163 +1,66 @@
+require 'active_form/model_association'
+require 'active_form/collection_association'
+require 'active_form/associatable'
+
module ActiveForm
class Base
- include ActiveModel::Model
- extend ActiveModel::Callbacks
-
- define_model_callbacks :save, only: [:after]
- after_save :update_form_models
+ extend Associatable
- delegate :persisted?, :to_model, :to_key, :to_param, :to_partial_path, to: :model
- attr_reader :model, :forms
-
- def initialize(model)
- @model = model
- @forms = []
- populate_forms
- end
-
- def submit(params)
- params.each do |key, value|
- if nested_params?(value)
- fill_association_with_attributes(key, value)
- else
- send("#{key}=", value)
- end
+ # SignupForm.new(user: User.find(params[:user_id]))
+ def initialize(models = nil)
+ if models.respond_to?(:each)
+ assign_attributes(models)
+ else
+ main_association.instance = models
end
end
- def get_model(assoc_name)
- form = find_form_by_assoc_name(assoc_name)
- form.get_model(assoc_name)
- end
-
def save
- if valid?
- run_callbacks :save do
- ActiveRecord::Base.transaction do
- model.save
- end
- end
- else
- false
- end
+ main_association.save if valid?
end
- def valid?
- super
- model.valid?
-
- collect_errors_from(model)
- aggregate_form_errors
-
- errors.empty?
+ def submit(params)
+ assign_attributes(params)
end
+ delegate :id, :persisted?, :to_model, :to_partial_path, to: :main_association
+
class << self
- attr_accessor :main_class
- attr_writer :main_model
- delegate :reflect_on_association, to: :main_class
+ delegate :attributes, :association_scope, to: :main_association
- def attributes(*names)
- options = names.pop if names.last.is_a?(Hash)
+ attr_writer :main_model
- if options && options[:required]
- validates_presence_of *names
+ private
+ def main_association
+ @@main_association ||= ModelAssociation.new(main_model)
end
- names.each do |attribute|
- delegate attribute, "#{attribute}=", to: :model
+ def main_model
+ @main_model ||= name.sub(/Form$/, '')
end
- end
-
- def main_class
- @main_class ||= main_model.to_s.camelize.constantize
- end
-
- def main_model
- @main_model ||= name.sub(/Form$/, '').singularize
- end
-
- alias_method :attribute, :attributes
-
- def association(name, options={}, &block)
- macro = main_class.reflect_on_association(name).macro
-
- case macro
- when :has_one, :belongs_to
- declare_form(name, &block)
- when :has_many
- declare_form_collection(name, options, &block)
- end
-
- define_method("#{name}_attributes=") {}
- end
-
- def declare_form_collection(name, options={}, &block)
- forms << FormDefinition.new(name, block, options)
- class_eval("def #{name}; @#{name}.models; end")
- end
-
- def declare_form(name, &block)
- forms << FormDefinition.new(name, block)
- attr_reader name
- end
-
- def forms
- @forms ||= []
- end
end
private
-
- def update_form_models
- forms.each do |form|
- form.update_models
+ def respond_to_missing?(meth, include_private = false)
+ main_association.respond_to?(meth)
end
- end
- def populate_forms
- self.class.forms.each do |definition|
- definition.parent = model
- nested_form = definition.to_form
- forms << nested_form
- name = definition.assoc_name
- instance_variable_set("@#{name}", nested_form)
+ def method_missing(meth, *args, &block)
+ if main_association.respond_to?(meth)
+ main_association.send(meth, *args, &block)
+ else
+ super
+ end
end
- end
- def nested_params?(value)
- value.is_a?(Hash)
- end
-
- ATTRIBUTES_KEY_REGEXP = /^(.+)_attributes$/
-
- def find_association_name_in(key)
- ATTRIBUTES_KEY_REGEXP.match(key)[1]
- end
-
- def fill_association_with_attributes(association, attributes)
- assoc_name = find_association_name_in(association).to_sym
- form = find_form_by_assoc_name(assoc_name)
-
- form.submit(attributes)
- end
-
- def find_form_by_assoc_name(assoc_name)
- forms.select { |form| form.represents?(assoc_name) }.first
- end
-
- def aggregate_form_errors
- forms.each do |form|
- form.valid?
- collect_errors_from(form)
+ def main_association
+ @@main_association
end
- end
- def collect_errors_from(validatable_object)
- validatable_object.errors.each do |attribute, error|
- errors.add(attribute, error)
+ def assign_attributes(attributes)
+ attributes.each do |key, value|
+ self.public_send("#{key}=", value)
+ end if attributes
end
- end
end
-
-end
\ No newline at end of file
+end
diff --git a/lib/active_form/collection_association.rb b/lib/active_form/collection_association.rb
new file mode 100644
index 0000000..2afbbe7
--- /dev/null
+++ b/lib/active_form/collection_association.rb
@@ -0,0 +1,37 @@
+require 'active_form/model_association'
+
+module ActiveForm
+ class CollectionAssociation < ModelAssociation
+ def initialize(model_name, options)
+ super
+ @instances = []
+ end
+
+ def dynamic?
+ true # means we can add more instances in a form
+ end
+
+ def records
+ size
+ end
+
+ delegate :each, :size, :[], to: :@instances
+
+ # Map model attributes by key to association
+ # doghouse_attributes: { '1' => { name: 'McDiniis' }, '2' => { name: 'McDunuus' } }
+ def attributes=(model_attributes)
+ model_attributes.each do |model_id, attrs|
+ fetch_instance(model_id.to_i).attributes = attrs
+ end
+ end
+
+ def build_instance
+ model_class.new.tap { |i| @instances << i }
+ end
+
+ private
+ def fetch_instance(id)
+ @instances[id] || build_instance
+ end
+ end
+end
diff --git a/lib/active_form/collection_form.rb b/lib/active_form/collection_form.rb
new file mode 100644
index 0000000..2ba24fe
--- /dev/null
+++ b/lib/active_form/collection_form.rb
@@ -0,0 +1,122 @@
+require 'active_form/abstract_form'
+
+module ActiveForm
+ class CollectionForm < AbstractForm
+ attr_reader :association_name, :records, :parent, :proc
+
+ def initialize(assoc_name, parent, proc, options)
+ @association_name = assoc_name
+ @parent = parent
+ @proc = proc
+ @records = options[:records] || 1
+ @forms = []
+ assign_forms
+ end
+
+ def reset
+ @forms.clear
+ fetch_models
+ end
+
+ def submit(params)
+ params.each do |key, attributes|
+ if parent.persisted?
+ create_or_update_record(attributes)
+ else
+ create_or_assign_record(key, attributes)
+ end
+ end
+ end
+
+ def valid?
+ aggregate_form_errors
+
+ errors.empty?
+ end
+
+ def models
+ forms
+ end
+
+ def each
+ forms.each(&Proc.new)
+ end
+
+ private
+
+ UNASSIGNABLE_KEYS = %w( id _destroy )
+
+ def existing_record?(attributes)
+ attributes[:id] != nil
+ end
+
+ def update_record(attributes)
+ form = form_for_id(attributes[:id].to_i)
+
+ form.submit(attributes.except(*UNASSIGNABLE_KEYS))
+
+ destroy_form!(form) if attributes['_destroy'] == "1"
+ end
+
+ def create_record(attributes)
+ build_form.tap { |f| forms << f }.submit(attributes)
+ end
+
+ def create_or_update_record(attributes)
+ if existing_record?(attributes)
+ update_record(attributes)
+ else
+ create_record(attributes)
+ end
+ end
+
+ def create_or_assign_record(key, attributes)
+ i = key.to_i
+
+ if dynamic_key?(i)
+ create_record(attributes)
+ else
+ forms[i].delete if reject_form?(attributes)
+
+ forms[i].submit(attributes)
+ end
+ end
+
+ def assign_forms
+ if parent.persisted?
+ fetch_models
+ else
+ initialize_models
+ end
+ end
+
+ def dynamic_key?(i)
+ i > forms.size
+ end
+
+ def fetch_models
+ associated_records.each { |model| forms << build_form(model) }
+ end
+
+ def initialize_models
+ records.times { forms << build_form }
+ end
+
+ def form_for_id(id)
+ forms.find { |form| form.id == id }
+ end
+
+ def destroy_form!(form)
+ form.delete
+ forms.delete(form)
+ end
+
+ def build_form(model = nil)
+ Form.new(association_name, parent, proc, model)
+ end
+
+ def associated_records
+ parent.send(association_name)
+ end
+ end
+end
diff --git a/lib/active_form/form.rb b/lib/active_form/form.rb
index b6e6d94..7f5d0c0 100644
--- a/lib/active_form/form.rb
+++ b/lib/active_form/form.rb
@@ -1,16 +1,19 @@
-module ActiveForm
- class Form
- include ActiveModel::Validations
+require 'active_form/abstract_form'
+module ActiveForm
+ class Form < AbstractForm
delegate :id, :_destroy, :persisted?, to: :model
- attr_reader :association_name, :parent, :model, :forms, :proc
+ attr_reader :association_name, :parent, :model, :proc
- def initialize(assoc_name, parent, proc, model=nil)
+ def initialize(assoc_name, parent, proc, options = {})
@association_name = assoc_name
@parent = parent
- @model = assign_model(model)
+
+ model = options unless options.is_a?(Hash)
+ @model = model || build_model
+
@forms = []
- @proc = proc
+ instance_eval(&proc) if proc
enable_autosave
end
@@ -18,23 +21,14 @@ def class
model.class
end
- def association(name, options={}, &block)
- macro = model.class.reflect_on_association(name).macro
- form_definition = FormDefinition.new(name, block, options)
- form_definition.parent = @model
+ def association(name, options = {}, &block)
+ define_singleton_method(name) { instance_variable_get("@#{name}").models }
+ define_singleton_method("#{name}_attributes=") {}
- case macro
- when :has_one, :belongs_to
- class_eval "def #{name}; @#{name}; end"
- when :has_many
- class_eval "def #{name}; @#{name}.models; end"
+ FormDefinition.new(name, block, options).build_for(@model).tap do |form|
+ forms << form
+ instance_variable_set("@#{name}", form)
end
-
- nested_form = form_definition.to_form
- @forms << nested_form
- instance_variable_set("@#{name}", nested_form)
-
- class_eval "def #{name}_attributes=; end"
end
def attributes(*arguments)
@@ -53,150 +47,53 @@ def attributes(*arguments)
alias_method :attribute, :attributes
- def method_missing(method_sym, *arguments, &block)
- if method_sym =~ /^validates?$/
- class_eval do
- send(method_sym, *arguments, &block)
- end
- end
- end
-
- def update_models
- @model = parent.send("#{association_name}")
+ def method_missing(method, *args, &block)
+ self.class.send(method, *args, &block) if method =~ /\Avalidates?\z/
end
- REJECT_ALL_BLANK_PROC = proc { |attributes| attributes.all? { |key, value| key == '_destroy' || value.blank? } }
-
- def call_reject_if(attributes)
- REJECT_ALL_BLANK_PROC.call(attributes)
+ def reset
+ @model = parent.send(association_name)
end
- def params_for_current_scope(attributes)
- attributes.dup.reject { |_, v| v.is_a? Hash }
+ def reject_nested_params(params)
+ params.reject { |_, v| nested_params?(v) }
end
def submit(params)
- reflection = association_reflection
-
- if reflection.macro == :belongs_to
- @model = parent.send("build_#{association_name}") unless call_reject_if(params_for_current_scope(params))
+ if belongs_to_association? && !reject_form?(reject_nested_params(params))
+ @model = parent.send("build_#{association_name}")
end
-
- params.each do |key, value|
- if nested_params?(value)
- fill_association_with_attributes(key, value)
- else
- model.send("#{key}=", value)
- end
- end
- end
- def get_model(assoc_name)
- if represents?(assoc_name)
- form = Form.new(association_name, parent, proc)
- form.instance_eval &proc
- form
- else
- form = find_form_by_assoc_name(assoc_name)
- form.get_model(assoc_name)
- end
+ super
end
def delete
model.mark_for_destruction
end
- def valid?
- super
- model.valid?
-
- collect_errors_from(model)
- aggregate_form_errors
-
- errors.empty?
- end
-
- def represents?(assoc_name)
- association_name.to_s == assoc_name.to_s
- end
-
private
- ATTRIBUTES_KEY_REGEXP = /^(.+)_attributes$/
-
def enable_autosave
- reflection = association_reflection
- reflection.autosave = true
- end
-
- def fill_association_with_attributes(association, attributes)
- assoc_name = find_association_name_in(association).to_sym
- form = find_form_by_assoc_name(assoc_name)
-
- form.submit(attributes)
- end
-
- def find_form_by_assoc_name(assoc_name)
- forms.select { |form| form.represents?(assoc_name) }.first
- end
-
- def nested_params?(value)
- value.is_a?(Hash)
- end
-
- def find_association_name_in(key)
- ATTRIBUTES_KEY_REGEXP.match(key)[1]
+ association_reflection.autosave = true
end
def association_reflection
parent.class.reflect_on_association(association_name)
end
- def build_model
- macro = association_reflection.macro
+ def belongs_to_association?
+ association_reflection.macro == :belongs_to
+ end
- case macro
+ def build_model
+ case association_reflection.macro
when :belongs_to
- if parent.send("#{association_name}")
- parent.send("#{association_name}")
- else
- association_reflection.klass.new
- end
+ parent.send(association_name) || association_reflection.klass.new
when :has_one
- fetch_or_initialize_model
+ parent.send(association_name) || parent.send("build_#{association_name}")
when :has_many
parent.send(association_name).build
end
end
-
- def fetch_or_initialize_model
- if parent.send("#{association_name}")
- parent.send("#{association_name}")
- else
- parent.send("build_#{association_name}")
- end
- end
-
- def assign_model(model)
- if model
- model
- else
- build_model
- end
- end
-
- def aggregate_form_errors
- forms.each do |form|
- form.valid?
- collect_errors_from(form)
- end
- end
-
- def collect_errors_from(validatable_object)
- validatable_object.errors.each do |attribute, error|
- errors.add(attribute, error)
- end
- end
end
-
-end
\ No newline at end of file
+end
diff --git a/lib/active_form/form_collection.rb b/lib/active_form/form_collection.rb
deleted file mode 100644
index fe2f5cc..0000000
--- a/lib/active_form/form_collection.rb
+++ /dev/null
@@ -1,181 +0,0 @@
-module ActiveForm
- class FormCollection
- include ActiveModel::Validations
-
- attr_reader :association_name, :records, :parent, :proc, :forms
-
- def initialize(assoc_name, parent, proc, options)
- @association_name = assoc_name
- @parent = parent
- @proc = proc
- @records = options[:records] || 1
- @forms = []
- assign_forms
- end
-
- def update_models
- @forms = []
- fetch_models
- end
-
- def submit(params)
- params.each do |key, value|
- if parent.persisted?
- create_or_update_record(value)
- else
- create_or_assign_record(key, value)
- end
- end
- end
-
- def get_model(assoc_name)
- form = Form.new(association_name, parent, proc)
- form.instance_eval &proc
- form
- end
-
- def valid?
- aggregate_form_errors
-
- errors.empty?
- end
-
- def represents?(assoc_name)
- association_name.to_s == assoc_name.to_s
- end
-
- def models
- forms
- end
-
- def each(&block)
- forms.each do |form|
- block.call(form)
- end
- end
-
- private
-
- REJECT_ALL_BLANK_PROC = proc { |attributes| attributes.all? { |key, value| key == '_destroy' || value.blank? } }
-
- UNASSIGNABLE_KEYS = %w( id _destroy )
-
- def call_reject_if(attributes)
- REJECT_ALL_BLANK_PROC.call(attributes)
- end
-
- def assign_to_or_mark_for_destruction(form, attributes)
- form.submit(attributes.except(*UNASSIGNABLE_KEYS))
-
- if has_destroy_flag?(attributes)
- form.delete
- remove_form(form)
- end
- end
-
- def existing_record?(attributes)
- attributes[:id] != nil
- end
-
- def update_record(attributes)
- id = attributes[:id]
- form = find_form_by_model_id(id)
- assign_to_or_mark_for_destruction(form, attributes)
- end
-
- def create_record(attributes)
- new_form = create_form
- new_form.submit(attributes)
- end
-
- def create_or_update_record(attributes)
- if existing_record?(attributes)
- update_record(attributes)
- else
- create_record(attributes)
- end
- end
-
- def create_or_assign_record(key, attributes)
- i = key.to_i
-
- if dynamic_key?(i)
- create_record(attributes)
- else
- if call_reject_if(attributes)
- forms[i].delete
- end
- forms[i].submit(attributes)
- end
- end
-
- def has_destroy_flag?(attributes)
- attributes['_destroy'] == "1"
- end
-
- def assign_forms
- if parent.persisted?
- fetch_models
- else
- initialize_models
- end
- end
-
- def dynamic_key?(i)
- i > forms.size
- end
-
- def aggregate_form_errors
- forms.each do |form|
- form.valid?
- collect_errors_from(form)
- end
- end
-
- def fetch_models
- associated_records = parent.send(association_name)
-
- associated_records.each do |model|
- form = Form.new(association_name, parent, proc, model)
- forms << form
- form.instance_eval &proc
- end
- end
-
- def initialize_models
- records.times do
- form = Form.new(association_name, parent, proc)
- forms << form
- form.instance_eval &proc
- end
- end
-
- def collect_errors_from(model)
- model.errors.each do |attribute, error|
- errors.add(attribute, error)
- end
- end
-
- def check_record_limit!(limit, attributes_collection)
- if attributes_collection.size > limit
- raise TooManyRecords, "Maximum #{limit} records are allowed. Got #{attributes_collection.size} records instead."
- end
- end
-
- def find_form_by_model_id(id)
- forms.select { |form| form.id == id.to_i }.first
- end
-
- def remove_form(form)
- forms.delete(form)
- end
-
- def create_form
- new_form = Form.new(association_name, parent, proc)
- forms << new_form
- new_form.instance_eval &proc
- new_form
- end
- end
-
-end
\ No newline at end of file
diff --git a/lib/active_form/form_definition.rb b/lib/active_form/form_definition.rb
index 9b0a3d3..fe336aa 100644
--- a/lib/active_form/form_definition.rb
+++ b/lib/active_form/form_definition.rb
@@ -1,31 +1,19 @@
module ActiveForm
class FormDefinition
- attr_accessor :assoc_name, :proc, :parent, :records
-
- def initialize(assoc_name, block, options={})
- @assoc_name = assoc_name
- @proc = block
- @records = options[:records]
- end
-
- def to_form
- macro = association_reflection.macro
+ attr_reader :assoc_name
- case macro
- when :has_one, :belongs_to
- form = Form.new(assoc_name, parent, proc)
- form.instance_eval &proc
- form
- when :has_many
- FormCollection.new(assoc_name, parent, proc, {records: records})
- end
+ def initialize(assoc_name, block, options)
+ @assoc_name = assoc_name
+ @block = block
+ @options = options
end
- private
-
- def association_reflection
- parent.class.reflect_on_association(@assoc_name)
+ def build_for(model)
+ if model.class.reflect_on_association(@assoc_name).macro == :has_many
+ CollectionForm
+ else
+ Form
+ end.new(@assoc_name, model, @block, @options)
end
end
-
-end
\ No newline at end of file
+end
diff --git a/lib/active_form/model_association.rb b/lib/active_form/model_association.rb
new file mode 100644
index 0000000..1840b54
--- /dev/null
+++ b/lib/active_form/model_association.rb
@@ -0,0 +1,92 @@
+require 'active_support/core_ext/module/delegation'
+require 'active_form/associatable'
+
+module ActiveForm
+ class ModelAssociation
+ include Associatable
+ include ActiveModel::Model
+
+ attr_accessor :parent_association
+
+ def initialize(model_name, options = {})
+ @model_name = model_name
+ @options = options
+ end
+
+ def add_child(child, block = nil)
+ children << child
+ child.parent_association = self
+ child.instance_eval(&block) if block
+ end
+
+ # Test compatibility method
+ def forms
+ @children
+ end
+
+ def instance=(instance)
+ @model = instance if instance.is_a?(model_class)
+ end
+
+ def attributes(*attribute_names)
+ options = attribute_names.extract_options!
+
+ delegate_accessors_to_model attribute_names, options[:prefix]
+
+ if options && options[:required]
+ validates_presence_of(*attribute_names)
+ end
+ end
+ alias :attribute :attributes
+
+ def attributes=(attributes)
+ attributes.each do |name, value|
+ self.public_send("#{name}=", value)
+ end if attributes
+ end
+
+ def model
+ @model ||= model_class.new
+ end
+
+ delegate :persisted?, to: :model
+
+ def dynamic?
+ false
+ end
+
+ def save
+ aggregate(&:save)
+ end
+
+ def valid?
+ aggregate(&:valid?).any?(&:blank?)
+ end
+
+ delegate :reflect_on_association, to: :model_class
+
+ private
+ def children
+ @children ||= []
+ end
+
+ def reflection
+ parent_association.reflect_on_association(@name)
+ end
+
+ def model_class
+ @model_class ||= @model_name.to_s.singularize.camelize.constantize
+ end
+
+ def delegate_accessors_to_model(names, prefix = false)
+ names.each do |attr|
+ self.class.delegate attr, "#{attr}=", to: :model, prefix: prefix
+ end
+ end
+
+ def aggregate
+ yield model
+ children.each { |c| yield c }
+ end
+ end
+end
diff --git a/lib/active_form/too_many_records.rb b/lib/active_form/too_many_records.rb
deleted file mode 100644
index 6214a1b..0000000
--- a/lib/active_form/too_many_records.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-module ActiveForm
- class TooManyRecords < RuntimeError
- end
-end
\ No newline at end of file
diff --git a/lib/active_form/view_helpers.rb b/lib/active_form/view_helpers.rb
index a207b1c..5377c47 100644
--- a/lib/active_form/view_helpers.rb
+++ b/lib/active_form/view_helpers.rb
@@ -29,7 +29,7 @@ def render_association(association, f, new_object, render_options={}, custom_par
else
method_name = :fields_for
end
-
+
f.send(method_name, association, new_object, {:child_index => "new_#{association}"}.merge(render_options)) do |builder|
render(partial: partial, locals: {:f => builder})
end
@@ -46,12 +46,12 @@ def link_to_add_association(name, f, association, html_options={})
new_object = create_object(f, association)
html_options[:'data-association-insertion-template'] = CGI.escapeHTML(render_association(association, f, new_object, render_options, override_partial).to_str).html_safe
-
+
link_to(name, '#', html_options)
end
-
+
def create_object(f, association)
- f.object.get_model(association)
+ f.object.backing_form_for(association)
end
def get_partial_path(partial, association)
diff --git a/test/dummy/test/controllers/assignments_controller_test.rb b/test/dummy/test/controllers/assignments_controller_test.rb
index 25ba6e7..d2b916d 100644
--- a/test/dummy/test/controllers/assignments_controller_test.rb
+++ b/test/dummy/test/controllers/assignments_controller_test.rb
@@ -2,7 +2,7 @@
class AssignmentsControllerTest < ActionController::TestCase
fixtures :assignments, :tasks
-
+
setup do
@assignment = assignments(:yard)
end
@@ -22,7 +22,7 @@ class AssignmentsControllerTest < ActionController::TestCase
assert_difference('Assignment.count') do
post :create, assignment: {
name: "Life",
-
+
tasks_attributes: {
"0" => { name: "Eat" },
"1" => { name: "Pray" },
@@ -35,9 +35,9 @@ class AssignmentsControllerTest < ActionController::TestCase
assert assignment_form.valid?
assert_redirected_to assignment_path(assignment_form)
-
+
assert_equal "Life", assignment_form.name
-
+
assert_equal "Eat", assignment_form.tasks[0].name
assert_equal "Pray", assignment_form.tasks[1].name
assert_equal "Love", assignment_form.tasks[2].name
@@ -45,7 +45,7 @@ class AssignmentsControllerTest < ActionController::TestCase
assignment_form.tasks.each do |task_form|
assert task_form.persisted?
end
-
+
assert_equal "Assignment: Life was successfully created.", flash[:notice]
end
@@ -55,7 +55,7 @@ class AssignmentsControllerTest < ActionController::TestCase
assert_difference('Assignment.count', 0) do
post :create, assignment: {
name: assignment.name,
-
+
tasks_attributes: {
"0" => { name: nil },
"1" => { name: nil },
@@ -68,7 +68,7 @@ class AssignmentsControllerTest < ActionController::TestCase
assert_not assignment_form.valid?
assert_includes assignment_form.errors.messages[:name], "has already been taken"
-
+
assignment_form.tasks.each do |task_form|
assert_includes task_form.errors.messages[:name], "can't be blank"
end
@@ -88,7 +88,7 @@ class AssignmentsControllerTest < ActionController::TestCase
assert_difference('Assignment.count', 0) do
patch :update, id: @assignment, assignment: {
name: "Car service",
-
+
tasks_attributes: {
"0" => { name: "Wash tires", id: tasks(:rake).id },
"1" => { name: "Clean inside", id: tasks(:paint).id },
@@ -100,9 +100,9 @@ class AssignmentsControllerTest < ActionController::TestCase
assignment_form = assigns(:assignment_form)
assert_redirected_to assignment_path(assignment_form)
-
+
assert_equal "Car service", assignment_form.name
-
+
assert_equal "Wash tires", assignment_form.tasks[0].name
assert_equal "Clean inside", assignment_form.tasks[1].name
assert_equal "Check breaks", assignment_form.tasks[2].name
@@ -110,7 +110,7 @@ class AssignmentsControllerTest < ActionController::TestCase
assert_equal "Assignment: Car service was successfully updated.", flash[:notice]
end
- test "should destroy assignment” do
+ test "should destroy assignment" do
assert_difference('Assignment.count', -1) do
delete :destroy, id: @assignment
end
diff --git a/test/forms/conference_form_test.rb b/test/forms/conference_form_test.rb
index 8043cbf..2dbcaa5 100644
--- a/test/forms/conference_form_test.rb
+++ b/test/forms/conference_form_test.rb
@@ -11,34 +11,20 @@ def setup
end
test "contains getter for presentations sub-form" do
- assert_respond_to @form.speaker, :presentations
-
- presentations_form = @form.speaker.forms.first
- assert_instance_of ActiveForm::FormCollection, presentations_form
- end
-
- test "#represents? returns true if the argument matches the Form's association name, false otherwise" do
- presentations_form = @form.speaker.forms.first
-
- assert presentations_form.represents?("presentations")
- assert_not presentations_form.represents?("presentation")
+ assert @form.speaker.presentations
end
test "main form provides getter method for collection objects" do
assert_respond_to @form.speaker, :presentations
- presentations = @form.speaker.presentations
-
- presentations.each do |form|
- assert_instance_of ActiveForm::Form, form
- assert_instance_of Presentation, form.model
+ @form.speaker.presentations.each do |model|
+ assert_instance_of Presentation, model
end
end
test "presentations sub-form contains association name and parent model" do
presentations_form = @form.speaker.forms.first
- assert_equal :presentations, presentations_form.association_name
assert_equal 2, presentations_form.records
assert_equal @form.speaker.model, presentations_form.parent
end
@@ -46,12 +32,10 @@ def setup
test "presentations sub-form initializes the number of records specified" do
presentations_form = @form.speaker.forms.first
- assert_respond_to presentations_form, :models
- assert_equal 2, presentations_form.models.size
-
- presentations_form.each do |form|
- assert_instance_of ActiveForm::Form, form
- assert_instance_of Presentation, form.model
+ assert_equal 2, presentations_form.size
+
+ presentations_form.each do |model|
+ assert_instance_of Presentation, form
assert_respond_to form, :topic
assert_respond_to form, :topic=
@@ -309,7 +293,7 @@ def setup
assert_equal "Rails OOP", form.speaker.presentations[1].topic
assert_equal "1h", form.speaker.presentations[1].duration
assert_equal 2, form.speaker.presentations.size
-
+
assert form.persisted?
end
@@ -349,7 +333,7 @@ def setup
assert_equal "Rails Migrations", form.speaker.presentations[2].topic
assert_equal "1h", form.speaker.presentations[2].duration
assert_equal 3, form.speaker.presentations.size
-
+
assert form.persisted?
end
diff --git a/test/forms/nested_model_form_test.rb b/test/forms/nested_model_form_test.rb
index ac37708..e65941a 100644
--- a/test/forms/nested_model_form_test.rb
+++ b/test/forms/nested_model_form_test.rb
@@ -20,12 +20,6 @@ def setup
assert_respond_to UserWithEmailFormFixture, :forms
end
- test "forms list contains form definitions" do
- email_definition = UserWithEmailFormFixture.forms.first
-
- assert_equal :email, email_definition.assoc_name
- end
-
test "contains getter for email sub-form" do
assert_respond_to @form, :email
assert_instance_of ActiveForm::Form, @form.email
@@ -89,7 +83,7 @@ def setup
test "email sub-form validates the model" do
existing_email = emails(:peters)
@email_form.address = existing_email.address
-
+
assert_not @email_form.valid?
assert_includes @email_form.errors.messages[:address], "has already been taken"
@@ -138,7 +132,7 @@ def setup
assert_equal 23, @form.age
assert_equal 0, @form.gender
assert_equal "petrakos@gmail.com", @email_form.address
-
+
assert @form.persisted?
assert @email_form.persisted?
end
@@ -174,7 +168,7 @@ def setup
name: peter.name,
age: "23",
gender: "0",
-
+
email_attributes: {
address: peter.email.address
}
diff --git a/test/forms/nested_model_rendering_test.rb b/test/forms/nested_model_rendering_test.rb
index 9ae161f..3c26300 100644
--- a/test/forms/nested_model_rendering_test.rb
+++ b/test/forms/nested_model_rendering_test.rb
@@ -4,7 +4,7 @@
class NestedModelRenderingTest < ActionView::TestCase
fixtures :all
-
+
def form_for(*)
@output_buffer = super
end
@@ -180,7 +180,7 @@ def form_for(*)
concat f.label(:age)
concat f.number_field(:age)
-
+
concat f.label(:gender)
concat f.select(:gender, User.get_genders_dropdown)
@@ -303,7 +303,7 @@ def form_for(*)
concat artist_fields.label(:name)
concat artist_fields.text_field(:name)
- concat artist_fields.fields_for(:producer, producer) { |producer_fields|
+ concat artist_fields.fields_for(:producer, producer) { |producer_fields|
concat producer_fields.label(:name)
concat producer_fields.text_field(:name)
@@ -324,7 +324,7 @@ def form_for(*)
assert_match //, output_buffer
assert_match /