diff --git a/lib/action_view/helpers/dynamic_form.rb b/lib/action_view/helpers/dynamic_form.rb index ecc171a..243d78a 100644 --- a/lib/action_view/helpers/dynamic_form.rb +++ b/lib/action_view/helpers/dynamic_form.rb @@ -15,10 +15,12 @@ module DynamicForm # has an attribute +title+ mapped to a +VARCHAR+ column that holds "Hello World": # # input("post", "title") - # # => - def input(record_name, method, options = {}) - raise_broken_code_error - InstanceTag.new(record_name, method, self).to_tag(options) + # # => + # + # input("post", "title", "maxlength" => 10) + # # => + def input(object_name, method, options = {}) + InputBuilder.new(object_name, method, self, options).to_tag end # Returns an entire form with all needed input tags for a specified Active Record object. For example, if @post @@ -262,29 +264,55 @@ def default_input_block Proc.new { |record, column| %(


#{input(record, column.name)}

) } end - module InstanceTagMethods - def to_tag(options = {}) + + module InputBuilderMethods + DEFAULT_MAXLENGTH = 30 + + def initialize(object_name, method, context, options) + @object_name = object_name + @context = context + @method = method + @options = options + end + + def to_tag case column_type - when :string - field_type = @method_name.include?("password") ? "password" : "text" - to_input_field_tag(field_type, options) - when :text - to_text_area_tag(options) - when :integer, :float, :decimal - to_input_field_tag("text", options) - when :date - to_date_select_tag(options) - when :datetime, :timestamp - to_datetime_select_tag(options) - when :time - to_time_select_tag(options) - when :boolean - to_boolean_select_tag(options).html_safe + when :string + @options["type"] = @method.include?("password") ? "password" : "text" + Tags::TextField.new(*generic_args).render + when :text + Tags::TextArea.new(*generic_args).render + when :integer, :float, :decimal + Tags::TextField.new(*generic_args).render + when :date + Tags::DateField.new(*generic_args).render + when :datetime, :timestamp + Tags::DatetimeLocalField.new(*generic_args).render + when :time + Tags::TimeField.new(*generic_args).render + when :boolean + Tags::CheckBox.new(@object_name, @method, @context, "1", "0", @options).render + end + end + + private + + def options_with_default + @options.tap do |options| + options["maxlength"] = DEFAULT_MAXLENGTH unless @options.key?("maxlength") end end + def generic_args + [ @object_name, @method, @context, options_with_default ] + end + + def object + @context.instance_variable_get("@#{@object_name}") + end + def column_type - object.send(:column_for_attribute, @method_name).type + object.send(:column_for_attribute, @method).type end end @@ -299,8 +327,8 @@ def error_messages(options = {}) end end - class InstanceTag - include DynamicForm::InstanceTagMethods + class InputBuilder + include DynamicForm::InputBuilderMethods end class FormBuilder diff --git a/test/dynamic_form_test.rb b/test/dynamic_form_test.rb index 0a5ec72..1cf1925 100644 --- a/test/dynamic_form_test.rb +++ b/test/dynamic_form_test.rb @@ -10,12 +10,12 @@ def form_for(*) end silence_warnings do - class Post < Struct.new(:title, :author_name, :body, :secret, :written_on) + class Post < Struct.new(:title, :author_name, :body, :secret, :written_on, :published_on, :started_at, :published) extend ActiveModel::Naming include ActiveModel::Conversion end - class User < Struct.new(:email) + class User < Struct.new(:email, :password) extend ActiveModel::Naming include ActiveModel::Conversion end @@ -78,14 +78,27 @@ def @post.column_for_attribute(attr_name) end silence_warnings do - def Post.content_columns() [ Column.new(:string, "title", "Title"), Column.new(:text, "body", "Body") ] end + def Post.content_columns() + [ + Column.new(:string, "title", "Title"), + Column.new(:text, "body", "Body"), + Column.new(:integer, "secret", "Secret"), + Column.new(:date, "written_on", "Written On"), + Column.new(:datetime, "published_on", "Published On"), + Column.new(:time, "started_at", "Started At"), + Column.new(:boolean, "published", "Published") + ] + end end - @post.title = "Hello World" - @post.author_name = "" - @post.body = "Back to the hill and over it again!" - @post.secret = 1 - @post.written_on = Date.new(2004, 6, 15) + @post.title = "Hello World" + @post.author_name = "" + @post.body = "Back to the hill and over it again!" + @post.secret = 1 + @post.written_on = Date.new(2004, 6, 15) + @post.published_on = Date.new(2005, 8, 23) + @post.started_at = Time.new(2024, 4, 2, 21, 44, 10) + @post.published = true end def setup_user @@ -107,10 +120,11 @@ def @user.column_for_attribute(attr_name) end silence_warnings do - def User.content_columns() [ Column.new(:string, "email", "Email") ] end + def User.content_columns() [ Column.new(:string, "email", "Email"), Column.new(:string, "password", "Password") ] end end @user.email = "" + @user.password = "password" end def protect_against_forgery? @@ -130,11 +144,59 @@ def url_for(options) end def test_generic_input_tag - assert_raise(BrokenFeatureError) do assert_dom_equal( - %(), input("post", "title") + %(), input("post", "title") + ) + end + + def test_input_tag_with_maxlength + assert_dom_equal( + %(), input("post", "title", "maxlength" => 10) + ) + end + + def test_input_for_password + assert_dom_equal( + %(), input("user", "password") + ) + end + + def test_input_for_text + def @post.errors; end + + assert_dom_equal( + %(), input("post", "body") + ) + end + + def test_input_tag_for_integer + assert_dom_equal( + %(), input("post", "secret") + ) + end + + def test_input_tag_for_date + assert_dom_equal( + %(), input("post", "written_on") + ) + end + + def test_input_tag_for_datetime + assert_dom_equal( + %(), input("post", "published_on") + ) + end + + def test_input_tag_for_time + assert_dom_equal( + %(), input("post", "started_at") + ) + end + + def test_input_tag_for_boolean + assert_dom_equal( + %(), input("post", "published") ) - end end def test_text_area_with_errors @@ -225,10 +287,10 @@ def inner_test_form_with_method_option def test_form_with_action_option assert_raise(BrokenFeatureError) do - output_buffer << form("post", :action => "sign") - assert_select "form[action=sign]" do |form| - assert_select "input[type=submit][value=Sign]" - end + output_buffer << form("post", :action => "sign") + assert_select "form[action=sign]" do |form| + assert_select "input[type=submit][value=Sign]" + end end end