From e4be6fdbfb7cef0b8816161bdd4d0b989fbe1799 Mon Sep 17 00:00:00 2001 From: Artem Bolshakov Date: Thu, 16 Jun 2016 16:36:58 +0300 Subject: [PATCH] Show "Create another" checkbox on new resource page. If this checkbox is selected, user will be redirected to new resource page after successfully creating current record. This feature may be very helpful when entering large amount of data. --- CHANGELOG.md | 16 ++++-- activeadmin.gemspec | 2 +- .../stylesheets/active_admin/_forms.scss | 10 ++++ config/locales/en.yml | 1 + docs/5-forms.md | 19 +++++++ features/create_another.feature | 55 +++++++++++++++++++ features/edit_page.feature | 1 + features/step_definitions/web_steps.rb | 7 ++- lib/active_admin/application.rb | 4 ++ lib/active_admin/resource.rb | 7 +++ .../resource_controller/data_access.rb | 17 ++++++ lib/active_admin/resource_dsl.rb | 9 ++- .../views/components/active_admin_form.rb | 26 +++++++++ .../install/templates/active_admin.rb.erb | 7 +++ spec/unit/form_builder_spec.rb | 32 ++++++++++- 15 files changed, 203 insertions(+), 10 deletions(-) create mode 100644 features/create_another.feature diff --git a/CHANGELOG.md b/CHANGELOG.md index dc94fc4117e..295a3813403 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ #### Minor +* "Create another" checkbox for the new resource page. [#4477][] by [@bolshakov][] * Page supports belongs_to [#4759][] by [@Fivell][] and [@zorab47][] * Support for custom sorting strategies [#4768][] by [@Fivell][] * Stream CSV downloads as they're generated [#3038][] by [@craigmcnamara][] @@ -109,24 +110,29 @@ Please check [0-6-stable](https://github.com/activeadmin/activeadmin/blob/0-6-st [#3731]: https://github.com/activeadmin/activeadmin/issues/3731 [#3783]: https://github.com/activeadmin/activeadmin/issues/3783 [#4187]: https://github.com/activeadmin/activeadmin/issues/4187 +[#4477]: https://github.com/activeadmin/activeadmin/pull/4477 [#4759]: https://github.com/activeadmin/activeadmin/pull/4759 [#4768]: https://github.com/activeadmin/activeadmin/pull/4768 [#4848]: https://github.com/activeadmin/activeadmin/pull/4848 [#4867]: https://github.com/activeadmin/activeadmin/pull/4867 -[@PChambino]: https://github.com/PChambino -[@TimPetricola]: https://github.com/TimPetricola + +[@bolshakov]: https://github.com/bolshakov [@chancancode]: https://github.com/chancancode [@craigmcnamara]: https://github.com/craigmcnamara -[@drn]: https://github.com/drn +[@deivid-rodriguez]: https://github.com/deivid-rodriguez [@dmitry]: https://github.com/dmitry +[@drn]: https://github.com/drn +[@Fivell]: https://github.com/Fivell [@gonzedge]: https://github.com/gonzedge [@johnnyshields]: https://github.com/johnnyshields +[@PChambino]: https://github.com/PChambino +[@PChambino]: https://github.com/PChambino [@potatosalad]: https://github.com/potatosalad [@pranas]: https://github.com/pranas [@seanlinsley]: https://github.com/seanlinsley [@shekibobo]: https://github.com/shekibobo [@timoschilling]: https://github.com/timoschilling +[@TimPetricola]: https://github.com/TimPetricola +[@TimPetricola]: https://github.com/TimPetricola [@varyonic]: https://github.com/varyonic [@zorab47]: https://github.com/zorab47 -[@Fivell]: https://github.com/Fivell -[@deivid-rodriguez]: https://github.com/deivid-rodriguez diff --git a/activeadmin.gemspec b/activeadmin.gemspec index 3e8a04589fc..4b72f1fe6cf 100644 --- a/activeadmin.gemspec +++ b/activeadmin.gemspec @@ -18,7 +18,7 @@ Gem::Specification.new do |s| s.required_ruby_version = '>= 2.1' - s.add_dependency 'arbre', '~> 1.0', '>= 1.0.2' + s.add_dependency 'arbre', '>= 1.1.1' s.add_dependency 'bourbon' s.add_dependency 'coffee-rails' s.add_dependency 'formtastic', '~> 3.1' diff --git a/app/assets/stylesheets/active_admin/_forms.scss b/app/assets/stylesheets/active_admin/_forms.scss index ab93bbab99d..08e0fbd12ac 100644 --- a/app/assets/stylesheets/active_admin/_forms.scss +++ b/app/assets/stylesheets/active_admin/_forms.scss @@ -242,6 +242,16 @@ form { input[type=submit], input[type=button], button { margin-right: 10px; } } + .buttons .actions .create_another { + float: none; + margin-bottom: 10px; + + label { + float: none; + display: inline; + } + } + fieldset.buttons li, fieldset.actions li { float:left; padding: 0; diff --git a/config/locales/en.yml b/config/locales/en.yml index e73d0f58552..6923f1c3255 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -8,6 +8,7 @@ en: edit: "Edit" delete: "Delete" delete_confirmation: "Are you sure you want to delete this?" + create_another: "Create another %{model}" new_model: "New %{model}" edit_model: "Edit %{model}" delete_model: "Delete %{model}" diff --git a/docs/5-forms.md b/docs/5-forms.md index 4309cd75994..de563467d72 100644 --- a/docs/5-forms.md +++ b/docs/5-forms.md @@ -173,3 +173,22 @@ You can arrange content in tabs as shown below: f.actions end ``` + +## Customize the Create Another checkbox + +In order to simplify creating multiple resources you may enable ActiveAdmin to show nice "Create Another" checkbox alongside of Create Model +button. It may be enabled for the whole application: + +```ruby +ActiveAdmin.setup do |config| + config.create_another = true +end +``` + +or for the particular resource: + +```ruby +ActiveAdmin.register Post do + config.create_another = true +end +``` diff --git a/features/create_another.feature b/features/create_another.feature new file mode 100644 index 00000000000..1bf8aa4a52f --- /dev/null +++ b/features/create_another.feature @@ -0,0 +1,55 @@ +Feature: Create Another checkbox + + Background: + Given I am logged in + + Scenario: On a new page + Given a configuration of: + """ + ActiveAdmin.register Post do + config.create_another = true + + permit_params :custom_category_id, :author_id, :title, + :body, :position, :published_date, :starred + end + """ + Then I am on the index page for posts + And I follow "New Post" + When I fill in "Title" with "Hello World" + And I fill in "Body" with "This is the body" + And the "Create another Post" checkbox should not be checked + And I check "Create another" + And I press "Create Post" + Then I should see "Post was successfully created." + And I should see "New Post" + And the "Create another" checkbox should be checked + When I fill in "Title" with "Another Hello World" + And I fill in "Body" with "This is the another body" + And I uncheck "Create another" + And I press "Create Post" + Then I should see "Post was successfully created." + And I should see the attribute "Title" with "Another Hello World" + And I should see the attribute "Body" with "This is the another body" + + Scenario: Application config of false and a resource config of true + Given a configuration of: + """ + ActiveAdmin.application.create_another = false + ActiveAdmin.register Post do + config.create_another = true + end + """ + When I am on the new post page + Then I should see the element ".create_another" + Then the "Create another Post" checkbox should not be checked + + Scenario: Application config of true and a resource config of false + Given a configuration of: + """ + ActiveAdmin.application.create_another = true + ActiveAdmin.register Post do + config.create_another = false + end + """ + When I am on the new post page + Then I should not see the element ".create_another" diff --git a/features/edit_page.feature b/features/edit_page.feature index 55f82f684d3..9834f00a28c 100644 --- a/features/edit_page.feature +++ b/features/edit_page.feature @@ -23,6 +23,7 @@ Feature: Edit Page And the "Category" field should contain "" And the "Author" field should contain the option "John Doe" When I fill in "Title" with "Hello World from update" + And I should not see the element "Create another" When I press "Update Post" Then I should see "Post was successfully updated." And I should see the attribute "Title" with "Hello World from update" diff --git a/features/step_definitions/web_steps.rb b/features/step_definitions/web_steps.rb index 0626344f2bb..79108ff89f0 100644 --- a/features/step_definitions/web_steps.rb +++ b/features/step_definitions/web_steps.rb @@ -72,7 +72,12 @@ def with_scope(locator) Then /^the "([^"]*)" checkbox(?: within (.*))? should( not)? be checked$/ do |label, parent, negate| with_scope(parent) do - expect(find_field(label)['checked']).to negate ? eq(false) : eq(true) + checkbox = find_field(label) + if negate + expect(checkbox).not_to be_checked + else + expect(checkbox).to be_checked + end end end diff --git a/lib/active_admin/application.rb b/lib/active_admin/application.rb index d55ee70f16a..699291fdec3 100644 --- a/lib/active_admin/application.rb +++ b/lib/active_admin/application.rb @@ -89,6 +89,10 @@ def initialize # Display breadcrumbs inheritable_setting :breadcrumb, true + # Display create another checkbox on a new page + # @return [Boolean] (true) + inheritable_setting :create_another, false + # Default CSV options inheritable_setting :csv_options, { col_sep: ',', byte_order_mark: "\xEF\xBB\xBF" } diff --git a/lib/active_admin/resource.rb b/lib/active_admin/resource.rb index aadcc083fd3..1cce67af28e 100644 --- a/lib/active_admin/resource.rb +++ b/lib/active_admin/resource.rb @@ -54,6 +54,9 @@ def sort_order #Set order clause attr_writer :order_clause + # Display create another checkbox on a new page + # @return [Boolean] + attr_writer :create_another # Store a reference to the DSL so that we can dereference it during garbage collection. attr_accessor :dsl @@ -160,6 +163,10 @@ def order_clause @order_clause || namespace.order_clause end + def create_another + instance_variable_defined?(:@create_another) ? @create_another : namespace.create_another + end + def find_resource(id) resource = resource_class.public_send *method_for_find(id) (decorator_class && resource) ? decorator_class.new(resource) : resource diff --git a/lib/active_admin/resource_controller/data_access.rb b/lib/active_admin/resource_controller/data_access.rb index eb35b3197e2..85f5a7946e7 100644 --- a/lib/active_admin/resource_controller/data_access.rb +++ b/lib/active_admin/resource_controller/data_access.rb @@ -298,6 +298,23 @@ def assign_attributes(resource, attributes) def apply_decorations(resource) apply_decorator(resource) end + + # @return [String] + def smart_resource_url + if create_another? + new_resource_url(create_another: params[:create_another]) + else + super + end + end + + private + + # @return [Boolean] true if user requested to create one more + # resource after creating this one. + def create_another? + params[:create_another].present? + end end end end diff --git a/lib/active_admin/resource_dsl.rb b/lib/active_admin/resource_dsl.rb index 17ca69c4fae..39eecf94cd7 100644 --- a/lib/active_admin/resource_dsl.rb +++ b/lib/active_admin/resource_dsl.rb @@ -63,11 +63,16 @@ def includes(*args) def permit_params(*args, &block) param_key = config.param_key.to_sym belongs_to_param = config.belongs_to_param + create_another_param = :create_another if config.create_another controller do define_method :permitted_params do - params.permit *(active_admin_namespace.permitted_params + Array.wrap(belongs_to_param)), - param_key => block ? instance_exec(&block) : args + permitted_params = + active_admin_namespace.permitted_params + + Array.wrap(belongs_to_param) + + Array.wrap(create_another_param) + + params.permit(*permitted_params, param_key => block ? instance_exec(&block) : args) end end end diff --git a/lib/active_admin/views/components/active_admin_form.rb b/lib/active_admin/views/components/active_admin_form.rb index 4492e60fe9b..b8d805c22cb 100644 --- a/lib/active_admin/views/components/active_admin_form.rb +++ b/lib/active_admin/views/components/active_admin_form.rb @@ -72,10 +72,17 @@ def actions(*args, &block) end def commit_action_with_cancel_link + add_create_another_checkbox action(:submit) cancel_link end + def add_create_another_checkbox + if %w(new create).include?(action_name) && active_admin_config && active_admin_config.create_another + current_arbre_element.add_child(create_another_checkbox) + end + end + def has_many(*args, &block) insert_tag(HasManyProxy, form_builder, *args, &block) end @@ -91,6 +98,25 @@ def object def form_buffers raise "'form_buffers' has been removed from ActiveAdmin::FormBuilder, please read https://github.com/activeadmin/activeadmin/blob/master/docs/5-forms.md for details." end + + private + + def create_another_checkbox + create_another = params[:create_another] + label = @resource.class.model_name.human + Arbre::Context.new do + li do + input( + checked: create_another, + id: 'create_another', + class: 'create_another', + name: 'create_another', + type: 'checkbox', + ) + label(I18n.t('active_admin.create_another', model: label), for: 'create_another') + end + end + end end class SemanticInputsProxy < FormtasticProxy diff --git a/lib/generators/active_admin/install/templates/active_admin.rb.erb b/lib/generators/active_admin/install/templates/active_admin.rb.erb index a699d1d6aad..b61ca1592e6 100644 --- a/lib/generators/active_admin/install/templates/active_admin.rb.erb +++ b/lib/generators/active_admin/install/templates/active_admin.rb.erb @@ -179,6 +179,13 @@ ActiveAdmin.setup do |config| # # config.breadcrumb = false + # == Create Another Checkbox + # + # Create another checkbox is disabled by default. You can customize it for individual + # resources or you can enable them globally from here. + # + # config.create_another = true + # == Register Stylesheets & Javascripts # # We recommend using the built in Active Admin layout and loading diff --git a/spec/unit/form_builder_spec.rb b/spec/unit/form_builder_spec.rb index 7c43ee3da53..b15bd1d8621 100644 --- a/spec/unit/form_builder_spec.rb +++ b/spec/unit/form_builder_spec.rb @@ -30,6 +30,10 @@ def view.fa_icon(*args) args.inspect end + def view.action_name + 'edit' + end + view end @@ -157,13 +161,39 @@ def build_form(options = {}, form_object = Post.new, &block) end expect(body).to have_selector("[id=post_title]", count: 1) end - it "should generate one button and a cancel link" do + + context "create another checkbox" do + subject do + build_form do |f| + f.actions + end + end + + %w(new create).each do |action_name| + it "generates create another checkbox on #{action_name} page" do + expect(helpers).to receive(:action_name) { action_name } + allow(helpers).to receive(:active_admin_config) { instance_double(ActiveAdmin::Resource, create_another: true) } + + is_expected.to have_selector("[type=checkbox]", count: 1) + .and have_selector("[name=create_another]", count: 1) + end + end + + %w(show edit update).each do |action_name| + it "doesn't generate create another checkbox on #{action_name} page" do + is_expected.not_to have_selector("[name=create_another]", count: 1) + end + end + end + + it "should generate one button create another checkbox and a cancel link" do body = build_form do |f| f.actions end expect(body).to have_selector("[type=submit]", count: 1) expect(body).to have_selector("[class=cancel]", count: 1) end + it "should generate multiple actions" do body = build_form do |f| f.actions do