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 /