alchemy_cms 8.0.12 → 8.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +14 -10
- data/app/assets/builds/alchemy/admin.css +1 -1
- data/app/assets/builds/alchemy/dark-theme.css +1 -1
- data/app/assets/builds/alchemy/light-theme.css +1 -1
- data/app/assets/builds/alchemy/preview.min.js +1 -1
- data/app/assets/builds/alchemy/theme.css +1 -1
- data/app/{views/alchemy/admin/elements/_element.html.erb → components/alchemy/admin/element_editor.html.erb} +34 -29
- data/app/components/alchemy/admin/element_editor.rb +115 -0
- data/app/components/alchemy/admin/element_select.rb +12 -9
- data/app/components/alchemy/admin/ingredient_editor.rb +54 -0
- data/app/components/alchemy/admin/list_filter.rb +16 -5
- data/app/components/alchemy/admin/page_node.html.erb +214 -0
- data/app/components/alchemy/admin/page_node.rb +70 -0
- data/app/components/alchemy/admin/picture_thumbnail.rb +36 -0
- data/app/components/alchemy/admin/publish_page_button.html.erb +15 -0
- data/app/components/alchemy/admin/publish_page_button.rb +54 -0
- data/app/{helpers/alchemy/admin/tags_helper.rb → components/alchemy/admin/tags_list.rb} +19 -11
- data/app/components/alchemy/admin/toolbar_button.rb +17 -13
- data/app/components/alchemy/ingredients/audio_editor.rb +8 -0
- data/app/components/alchemy/ingredients/base_editor.rb +222 -0
- data/app/components/alchemy/ingredients/boolean_editor.rb +21 -0
- data/app/components/alchemy/ingredients/color_editor.rb +80 -0
- data/app/components/alchemy/ingredients/color_view.rb +13 -0
- data/app/components/alchemy/ingredients/datetime_editor.rb +28 -0
- data/app/components/alchemy/ingredients/file_editor.rb +69 -0
- data/app/components/alchemy/ingredients/headline_editor.rb +88 -0
- data/app/components/alchemy/ingredients/html_editor.rb +11 -0
- data/app/components/alchemy/ingredients/link_editor.rb +29 -0
- data/app/components/alchemy/ingredients/node_editor.rb +23 -0
- data/app/components/alchemy/ingredients/number_editor.rb +28 -0
- data/app/components/alchemy/ingredients/page_editor.rb +19 -0
- data/app/components/alchemy/ingredients/picture_editor.rb +81 -0
- data/app/components/alchemy/ingredients/richtext_editor.rb +31 -0
- data/app/components/alchemy/ingredients/select_editor.rb +37 -0
- data/app/components/alchemy/ingredients/select_view.rb +7 -0
- data/app/components/alchemy/ingredients/text_editor.rb +41 -0
- data/app/components/alchemy/ingredients/video_editor.rb +8 -0
- data/app/controllers/alchemy/admin/attachments_controller.rb +8 -15
- data/app/controllers/alchemy/admin/base_controller.rb +7 -18
- data/app/controllers/alchemy/admin/clipboard_controller.rb +15 -11
- data/app/controllers/alchemy/admin/dashboard_controller.rb +2 -2
- data/app/controllers/alchemy/admin/elements_controller.rb +34 -32
- data/app/controllers/alchemy/admin/ingredients_controller.rb +1 -0
- data/app/controllers/alchemy/admin/languages_controller.rb +0 -3
- data/app/controllers/alchemy/admin/layoutpages_controller.rb +2 -1
- data/app/controllers/alchemy/admin/legacy_page_urls_controller.rb +1 -1
- data/app/controllers/alchemy/admin/nodes_controller.rb +24 -1
- data/app/controllers/alchemy/admin/pages_controller.rb +36 -42
- data/app/controllers/alchemy/admin/pictures_controller.rb +4 -28
- data/app/controllers/alchemy/admin/resources_controller.rb +1 -1
- data/app/controllers/alchemy/api/ingredients_controller.rb +1 -1
- data/app/controllers/alchemy/api/pages_controller.rb +5 -3
- data/app/controllers/alchemy/base_controller.rb +6 -6
- data/app/controllers/alchemy/pages_controller.rb +12 -6
- data/app/controllers/concerns/alchemy/admin/archive_overlay.rb +0 -1
- data/app/controllers/concerns/alchemy/admin/clipboard.rb +57 -0
- data/app/controllers/concerns/alchemy/admin/uploader_responses.rb +2 -2
- data/app/controllers/concerns/alchemy/site_redirects.rb +1 -1
- data/app/decorators/alchemy/ingredient_editor.rb +37 -4
- data/app/helpers/alchemy/admin/base_helper.rb +10 -6
- data/app/helpers/alchemy/admin/ingredients_helper.rb +6 -3
- data/app/helpers/alchemy/base_helper.rb +1 -1
- data/app/helpers/alchemy/pages_helper.rb +1 -1
- data/app/javascript/alchemy_admin/components/action.js +5 -1
- data/app/javascript/alchemy_admin/components/color_select.js +73 -0
- data/app/javascript/alchemy_admin/components/element_editor/delete_element_button.js +11 -3
- data/app/javascript/alchemy_admin/components/element_editor/publish_element_button.js +7 -2
- data/app/javascript/alchemy_admin/components/element_editor.js +11 -12
- data/app/javascript/alchemy_admin/components/element_select.js +39 -17
- data/app/javascript/alchemy_admin/components/elements_window.js +0 -2
- data/app/javascript/alchemy_admin/components/file_editor.js +26 -0
- data/app/javascript/alchemy_admin/components/index.js +9 -0
- data/app/javascript/alchemy_admin/components/list_filter.js +57 -8
- data/app/javascript/alchemy_admin/components/message.js +9 -3
- data/app/javascript/alchemy_admin/components/page_node.js +119 -0
- data/app/javascript/alchemy_admin/{page_publication_fields.js → components/page_publication_fields.js} +9 -8
- data/app/javascript/alchemy_admin/{picture_editors.js → components/picture_editor.js} +30 -45
- data/app/javascript/alchemy_admin/components/picture_thumbnail.js +107 -0
- data/app/javascript/alchemy_admin/components/publish_page_button.js +41 -0
- data/app/javascript/alchemy_admin/components/select.js +3 -1
- data/app/javascript/alchemy_admin/components/sitemap.js +210 -0
- data/app/javascript/alchemy_admin/{sortable_elements.js → components/sortable_elements.js} +22 -25
- data/app/javascript/alchemy_admin/components/tinymce.js +10 -5
- data/app/javascript/alchemy_admin/components/uploader.js +30 -0
- data/app/javascript/alchemy_admin/image_overlay.js +0 -2
- data/app/javascript/alchemy_admin/initializer.js +0 -3
- data/app/javascript/alchemy_admin/link_dialog.js +1 -6
- data/app/javascript/alchemy_admin/templates/compiled.js +1 -1
- data/app/javascript/alchemy_admin/utils/ajax.js +15 -3
- data/app/javascript/alchemy_admin.js +0 -6
- data/app/models/alchemy/attachment.rb +4 -44
- data/app/models/alchemy/element/definitions.rb +1 -2
- data/app/models/alchemy/element/element_ingredients.rb +6 -2
- data/app/models/alchemy/element.rb +54 -13
- data/app/models/alchemy/element_definition.rb +4 -1
- data/app/models/alchemy/elements_repository.rb +6 -0
- data/app/models/alchemy/folded_page.rb +2 -2
- data/app/models/alchemy/ingredient.rb +38 -1
- data/app/models/alchemy/ingredient_definition.rb +4 -1
- data/app/models/alchemy/ingredient_validator.rb +6 -2
- data/app/models/alchemy/ingredients/color.rb +10 -0
- data/app/models/alchemy/ingredients/headline.rb +2 -17
- data/app/models/alchemy/ingredients/picture.rb +4 -4
- data/app/models/alchemy/ingredients/select.rb +19 -0
- data/app/models/alchemy/language/code.rb +0 -1
- data/app/models/alchemy/node.rb +28 -1
- data/app/models/alchemy/page/page_naming.rb +0 -7
- data/app/models/alchemy/page/page_natures.rb +7 -3
- data/app/models/alchemy/page/page_scopes.rb +13 -1
- data/app/models/alchemy/page/publisher.rb +14 -2
- data/app/models/alchemy/page.rb +102 -23
- data/app/models/alchemy/page_definition.rb +4 -1
- data/app/models/alchemy/page_version.rb +22 -6
- data/app/models/alchemy/picture.rb +10 -11
- data/app/models/alchemy/picture_variant.rb +1 -3
- data/app/models/alchemy/resource.rb +1 -1
- data/app/models/alchemy/storage_adapter/active_storage.rb +14 -2
- data/app/models/alchemy/storage_adapter/dragonfly.rb +12 -0
- data/app/models/alchemy/storage_adapter.rb +2 -0
- data/app/models/concerns/alchemy/picture_thumbnails.rb +4 -4
- data/app/models/concerns/alchemy/publishable.rb +54 -0
- data/app/models/concerns/alchemy/relatable_resource.rb +4 -14
- data/app/serializers/alchemy/page_tree_serializer.rb +11 -31
- data/app/services/alchemy/copy_page.rb +17 -0
- data/app/services/alchemy/duplicate_element.rb +1 -1
- data/app/services/alchemy/page_tree_preloader.rb +105 -0
- data/app/stylesheets/alchemy/_extends.scss +3 -9
- data/app/stylesheets/alchemy/_mixins.scss +3 -1
- data/app/stylesheets/alchemy/_themes.scss +19 -10
- data/app/stylesheets/alchemy/admin/archive.scss +1 -0
- data/app/stylesheets/alchemy/admin/base.scss +5 -2
- data/app/stylesheets/alchemy/admin/buttons.scss +3 -3
- data/app/stylesheets/alchemy/admin/element-select.scss +18 -0
- data/app/stylesheets/alchemy/admin/elements.scss +123 -23
- data/app/stylesheets/alchemy/admin/errors.scss +1 -1
- data/app/stylesheets/alchemy/admin/flash.scss +6 -4
- data/app/stylesheets/alchemy/admin/images.scss +9 -5
- data/app/stylesheets/alchemy/admin/list_filter.scss +4 -4
- data/app/stylesheets/alchemy/admin/navigation.scss +1 -1
- data/app/stylesheets/alchemy/admin/notices.scss +1 -2
- data/app/stylesheets/alchemy/admin/selects.scss +36 -21
- data/app/stylesheets/alchemy/admin/shoelace.scss +14 -1
- data/app/stylesheets/alchemy/admin/sitemap.scss +11 -3
- data/app/stylesheets/alchemy/admin/tags.scss +3 -1
- data/app/stylesheets/alchemy/admin/toolbar.scss +1 -1
- data/app/views/alchemy/_edit_mode.html.erb +1 -1
- data/app/views/alchemy/_menubar.html.erb +1 -1
- data/app/views/alchemy/admin/attachments/_archive_overlay.html.erb +35 -31
- data/app/views/alchemy/admin/attachments/_files_list.html.erb +1 -1
- data/app/views/alchemy/admin/attachments/_library_sidebar.html.erb +6 -0
- data/app/views/alchemy/admin/attachments/_overlay_file_list.html.erb +1 -1
- data/app/views/alchemy/admin/attachments/_replace_button.html.erb +1 -8
- data/app/views/alchemy/admin/attachments/_sorting_select.html.erb +13 -0
- data/app/views/alchemy/admin/attachments/_tag_list.html.erb +2 -3
- data/app/views/alchemy/admin/attachments/index.html.erb +5 -11
- data/app/views/alchemy/admin/attachments/show.html.erb +1 -1
- data/app/views/alchemy/admin/clipboard/_button.html.erb +1 -0
- data/app/views/alchemy/admin/clipboard/index.html.erb +4 -5
- data/app/views/alchemy/admin/clipboard/insert.turbo_stream.erb +1 -1
- data/app/views/alchemy/admin/crop.html.erb +5 -7
- data/app/views/alchemy/admin/dashboard/widgets/_locked_pages.html.erb +1 -1
- data/app/views/alchemy/admin/elements/_add_nested_element_form.html.erb +6 -6
- data/app/views/alchemy/admin/elements/_fixed_element.html.erb +1 -1
- data/app/views/alchemy/admin/elements/_footer.html.erb +7 -1
- data/app/views/alchemy/admin/elements/_header.html.erb +5 -5
- data/app/views/alchemy/admin/elements/_toolbar.html.erb +33 -8
- data/app/views/alchemy/admin/elements/create.turbo_stream.erb +10 -10
- data/app/views/alchemy/admin/elements/index.html.erb +29 -16
- data/app/views/alchemy/admin/elements/new.html.erb +2 -2
- data/app/views/alchemy/admin/ingredients/update.turbo_stream.erb +3 -5
- data/app/views/alchemy/admin/leave.html.erb +1 -1
- data/app/views/alchemy/admin/nodes/_node.html.erb +19 -0
- data/app/views/alchemy/admin/nodes/edit.html.erb +1 -1
- data/app/views/alchemy/admin/nodes/index.html.erb +3 -1
- data/app/views/alchemy/admin/nodes/new.html.erb +14 -1
- data/app/views/alchemy/admin/pages/_current_page.html.erb +3 -1
- data/app/views/alchemy/admin/pages/_form.html.erb +21 -9
- data/app/views/alchemy/admin/pages/_page_status.html.erb +1 -1
- data/app/views/alchemy/admin/pages/_publication_fields.html.erb +28 -26
- data/app/views/alchemy/admin/pages/_table.html.erb +0 -7
- data/app/views/alchemy/admin/pages/_toolbar.html.erb +3 -6
- data/app/views/alchemy/admin/pages/edit.html.erb +5 -11
- data/app/views/alchemy/admin/pages/flush.turbo_stream.erb +2 -0
- data/app/views/alchemy/admin/pages/fold.turbo_stream.erb +5 -0
- data/app/views/alchemy/admin/pages/index.html.erb +5 -3
- data/app/views/alchemy/admin/pages/new.html.erb +2 -12
- data/app/views/alchemy/admin/pages/publish.turbo_stream.erb +12 -0
- data/app/views/alchemy/admin/pages/tree.html.erb +13 -0
- data/app/views/alchemy/admin/pages/update.turbo_stream.erb +5 -16
- data/app/views/alchemy/admin/partials/_flash_notices.html.erb +1 -1
- data/app/views/alchemy/admin/partials/{_remote_search_form.html.erb → _overlay_search_form.html.erb} +1 -2
- data/app/views/alchemy/admin/partials/_paste_from_clipboard_form.html.erb +12 -0
- data/app/views/alchemy/admin/pictures/_archive_overlay.html.erb +24 -21
- data/app/views/alchemy/admin/pictures/_filter_and_size_bar.html.erb +18 -26
- data/app/views/alchemy/admin/pictures/_picture.html.erb +12 -16
- data/app/views/alchemy/admin/pictures/_picture_to_assign.html.erb +3 -6
- data/app/views/alchemy/admin/pictures/_tag_list.html.erb +2 -3
- data/app/views/alchemy/admin/pictures/index.html.erb +0 -1
- data/app/views/alchemy/admin/pictures/update.turbo_stream.erb +1 -1
- data/app/views/alchemy/admin/resources/_resource_usage_info.html.erb +1 -1
- data/app/views/alchemy/admin/resources/_tag_list.html.erb +2 -3
- data/app/views/alchemy/admin/styleguide/index.html.erb +25 -20
- data/app/views/alchemy/admin/tags/edit.html.erb +1 -1
- data/app/views/alchemy/admin/tinymce/_setup.html.erb +2 -2
- data/app/views/alchemy/admin/uploader/_button.html.erb +1 -15
- data/app/views/alchemy/attachments/show.html.erb +1 -1
- data/app/views/alchemy/base/permission_denied.js.erb +1 -1
- data/app/views/alchemy/ingredients/shared/_anchor.html.erb +9 -7
- data/app/views/alchemy/ingredients/shared/_link_tools.html.erb +12 -5
- data/app/views/alchemy/ingredients/shared/_picture_tools.html.erb +10 -11
- data/app/views/alchemy/language_links/_spacer.html.erb +1 -1
- data/app/views/alchemy/messages_mailer/new.html.erb +1 -1
- data/app/views/alchemy/welcome.html.erb +1 -1
- data/config/locales/alchemy.en.yml +12 -3
- data/config/routes.rb +2 -2
- data/db/migrate/20230123112425_add_searchable_to_alchemy_pages.rb +1 -1
- data/db/migrate/20230505132743_add_indexes_to_alchemy_pictures.rb +1 -1
- data/db/migrate/20231113104432_create_page_mutexes.rb +1 -1
- data/db/migrate/20240314105244_create_alchemy_picture_descriptions.rb +1 -1
- data/db/migrate/20250626160259_add_unique_index_to_picture_descriptions.rb +1 -1
- data/db/migrate/20250905140323_add_created_at_index_to_pictures_and_attachments.rb +1 -1
- data/db/migrate/20251106150010_convert_select_value_for_multiple.rb +11 -0
- data/db/migrate/20260102121232_add_metadata_to_page_versions.rb +9 -0
- data/db/migrate/20260115164704_add_publication_timestamps_to_alchemy_elements.rb +30 -0
- data/db/migrate/20260115164705_add_index_to_element_publication_timestamps.rb +13 -0
- data/lib/alchemy/ability_helper.rb +1 -3
- data/lib/alchemy/auth_accessors.rb +51 -117
- data/lib/alchemy/configuration.rb +1 -2
- data/lib/alchemy/configurations/main.rb +63 -0
- data/lib/alchemy/controller_actions.rb +2 -3
- data/lib/alchemy/engine.rb +9 -12
- data/lib/alchemy/error_tracking/error_logger.rb +1 -1
- data/lib/alchemy/errors.rb +1 -1
- data/lib/alchemy/logger.rb +34 -4
- data/lib/alchemy/name_conversions.rb +0 -6
- data/lib/alchemy/seeder.rb +2 -2
- data/lib/alchemy/tasks/usage.rb +4 -4
- data/lib/alchemy/test_support/factories/page_version_factory.rb +3 -0
- data/lib/alchemy/test_support/having_picture_thumbnails_examples.rb +30 -0
- data/lib/alchemy/test_support/shared_ingredient_editor_examples.rb +26 -6
- data/lib/alchemy/test_support/shared_publishable_examples.rb +114 -0
- data/lib/alchemy/upgrader/eight_one.rb +56 -0
- data/lib/alchemy/upgrader.rb +9 -1
- data/lib/alchemy/version.rb +1 -1
- data/lib/alchemy.rb +1 -4
- data/lib/alchemy_cms.rb +0 -1
- data/lib/generators/alchemy/elements/templates/view.html.erb +3 -3
- data/lib/generators/alchemy/ingredient/ingredient_generator.rb +6 -8
- data/lib/generators/alchemy/ingredient/templates/editor_component.rb.tt +22 -0
- data/lib/generators/alchemy/page_layouts/templates/layout.html.erb +1 -1
- data/lib/generators/alchemy/site_layouts/templates/layout.html.erb +1 -1
- data/lib/tasks/alchemy/upgrade.rake +21 -7
- data/vendor/javascript/shoelace.min.js +713 -31
- data/vendor/javascript/tinymce.min.js +1 -1
- metadata +104 -84
- data/app/decorators/alchemy/element_editor.rb +0 -90
- data/app/helpers/alchemy/admin/pictures_helper.rb +0 -14
- data/app/javascript/alchemy_admin/file_editors.js +0 -28
- data/app/javascript/alchemy_admin/image_loader.js +0 -54
- data/app/javascript/alchemy_admin/page_sorter.js +0 -71
- data/app/javascript/alchemy_admin/sitemap.js +0 -154
- data/app/javascript/alchemy_admin/templates/page_folder.hbs +0 -3
- data/app/views/alchemy/admin/attachments/archive_overlay.js.erb +0 -4
- data/app/views/alchemy/admin/pages/_page.html.erb +0 -163
- data/app/views/alchemy/admin/pages/_sitemap.html.erb +0 -30
- data/app/views/alchemy/admin/pages/flush.js.erb +0 -2
- data/app/views/alchemy/admin/pictures/archive_overlay.js.erb +0 -5
- data/app/views/alchemy/admin/pictures/index.js.erb +0 -2
- data/app/views/alchemy/ingredients/_audio_editor.html.erb +0 -5
- data/app/views/alchemy/ingredients/_boolean_editor.html.erb +0 -11
- data/app/views/alchemy/ingredients/_datetime_editor.html.erb +0 -20
- data/app/views/alchemy/ingredients/_file_editor.html.erb +0 -52
- data/app/views/alchemy/ingredients/_headline_editor.html.erb +0 -44
- data/app/views/alchemy/ingredients/_html_editor.html.erb +0 -8
- data/app/views/alchemy/ingredients/_link_editor.html.erb +0 -30
- data/app/views/alchemy/ingredients/_node_editor.html.erb +0 -13
- data/app/views/alchemy/ingredients/_number_editor.html.erb +0 -24
- data/app/views/alchemy/ingredients/_page_editor.html.erb +0 -13
- data/app/views/alchemy/ingredients/_picture_editor.html.erb +0 -59
- data/app/views/alchemy/ingredients/_richtext_editor.html.erb +0 -15
- data/app/views/alchemy/ingredients/_select_editor.html.erb +0 -31
- data/app/views/alchemy/ingredients/_text_editor.html.erb +0 -29
- data/app/views/alchemy/ingredients/_video_editor.html.erb +0 -5
- data/lib/generators/alchemy/ingredient/templates/editor.html.erb +0 -14
- /data/{lib → app/models}/alchemy/permissions.rb +0 -0
|
@@ -1,134 +1,68 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# Provides authentication accessors.
|
|
4
|
-
#
|
|
5
|
-
# Alchemy has some defaults for user model name and login logout path names:
|
|
6
|
-
#
|
|
7
|
-
# +Alchemy.user_class_name+ defaults to +'User'+
|
|
8
|
-
# +Alchemy.user_class_primary_key+ defaults to +:id+
|
|
9
|
-
# +Alchemy.current_user_method defaults to +'current_user'+
|
|
10
|
-
# +Alchemy.signup_path defaults to +'/signup'+
|
|
11
|
-
# +Alchemy.login_path defaults to +'/login'+
|
|
12
|
-
# +Alchemy.logout_path defaults to +'/logout'+
|
|
13
|
-
# +Alchemy.logout_method defaults to +'delete'+
|
|
14
|
-
# +Alchemy.unauthorized_path defaults to +'/'+
|
|
15
|
-
#
|
|
16
|
-
# Anyway, you can tell Alchemy about your authentication model configuration:
|
|
17
|
-
#
|
|
18
|
-
# 1. Your user class name - @see: Alchemy.user_class
|
|
19
|
-
# 2. Your users table primary key - @see: Alchemy.user_class_primary_key
|
|
20
|
-
# 3. A method on your ApplicationController to get current user -
|
|
21
|
-
# @see: Alchemy.current_user_method
|
|
22
|
-
# 4. The path to the signup form - @see: Alchemy.signup_path
|
|
23
|
-
# 5. The path to the login form - @see: Alchemy.login_path
|
|
24
|
-
# 6. The path to the logout method - @see: Alchemy.logout_path
|
|
25
|
-
# 7. The http verb for the logout method - @see: Alchemy.logout_method
|
|
26
|
-
# 8. The path to the page showing the user she's unauthorized - @see: Alchemy.unauthorized_path
|
|
27
|
-
#
|
|
28
|
-
# == Example
|
|
29
|
-
#
|
|
30
|
-
# # config/initializers/alchemy.rb
|
|
31
|
-
# Alchemy.user_class_name = 'Admin'
|
|
32
|
-
# Alchemy.user_class_primary_key = :user_id
|
|
33
|
-
# Alchemy.current_user_method = 'current_admin'
|
|
34
|
-
# Alchemy.signup_path = '/auth/signup'
|
|
35
|
-
# Alchemy.login_path = '/auth/login'
|
|
36
|
-
# Alchemy.logout_path = '/auth/logout'
|
|
37
|
-
# Alchemy.logout_method = 'get'
|
|
38
|
-
# Alchemy.unauthorized_path = '/home'
|
|
39
|
-
#
|
|
40
|
-
# If you don't have your own user model or don't want to provide one,
|
|
41
|
-
# add the `alchemy-devise` gem into your App's Gemfile.
|
|
42
|
-
#
|
|
43
|
-
# == Adding your own CanCan abilities
|
|
44
|
-
#
|
|
45
|
-
# If your app or your engine has own CanCan abilities you must register them:
|
|
46
|
-
#
|
|
47
|
-
# Alchemy.register_ability MyCustom::Ability
|
|
48
|
-
#
|
|
49
3
|
module Alchemy
|
|
50
|
-
|
|
51
|
-
:
|
|
52
|
-
:
|
|
53
|
-
:login_path,
|
|
54
|
-
:logout_path,
|
|
55
|
-
:logout_method,
|
|
56
|
-
:unauthorized_path
|
|
57
|
-
|
|
58
|
-
# Defaults
|
|
59
|
-
#
|
|
60
|
-
@@user_class_name = "User"
|
|
61
|
-
@@user_class_primary_key = :id
|
|
62
|
-
@@current_user_method = "current_user"
|
|
63
|
-
@@signup_path = "/signup"
|
|
64
|
-
@@login_path = "/login"
|
|
65
|
-
@@logout_path = "/logout"
|
|
66
|
-
@@logout_method = "delete"
|
|
67
|
-
@@unauthorized_path = "/"
|
|
68
|
-
|
|
69
|
-
# Returns the user class
|
|
70
|
-
#
|
|
71
|
-
# Set your App's user class to Alchemy.user_class_name in an initializer.
|
|
72
|
-
#
|
|
73
|
-
# Defaults to +User+
|
|
74
|
-
#
|
|
75
|
-
# == Example
|
|
76
|
-
#
|
|
77
|
-
# # config/initializers/alchemy.rb
|
|
78
|
-
# Alchemy.user_class_name = 'Admin'
|
|
79
|
-
#
|
|
80
|
-
|
|
81
|
-
# Prefix with :: when getting to avoid constant name conflicts
|
|
82
|
-
def self.user_class_name
|
|
83
|
-
if !@@user_class_name.is_a?(String)
|
|
84
|
-
raise TypeError, "Alchemy.user_class_name must be a String, not a Class."
|
|
85
|
-
end
|
|
4
|
+
class << self
|
|
5
|
+
delegate :user_class_primary_key, to: :config
|
|
6
|
+
deprecate user_class_primary_key: "Use `Alchemy.config.user_class_primary_key instead", deprecator: Alchemy::Deprecation
|
|
86
7
|
|
|
87
|
-
|
|
88
|
-
|
|
8
|
+
delegate :user_class_primary_key=, to: :config
|
|
9
|
+
deprecate :user_class_primary_key= => "Use `Alchemy.config.user_class_primary_key instead", :deprecator => Alchemy::Deprecation
|
|
89
10
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
11
|
+
delegate :current_user_method, to: :config
|
|
12
|
+
deprecate current_user_method: "Use `Alchemy.config.current_user_method instead", deprecator: Alchemy::Deprecation
|
|
13
|
+
|
|
14
|
+
delegate :current_user_method=, to: :config
|
|
15
|
+
deprecate :current_user_method= => "Use `Alchemy.config.current_user_method instead", :deprecator => Alchemy::Deprecation
|
|
16
|
+
|
|
17
|
+
delegate :signup_path, to: :config
|
|
18
|
+
deprecate signup_path: "Use `Alchemy.config.signup_path instead", deprecator: Alchemy::Deprecation
|
|
19
|
+
|
|
20
|
+
delegate :signup_path=, to: :config
|
|
21
|
+
deprecate :signup_path= => "Use `Alchemy.config.signup_path instead", :deprecator => Alchemy::Deprecation
|
|
22
|
+
|
|
23
|
+
delegate :login_path, to: :config
|
|
24
|
+
deprecate login_path: "Use `Alchemy.config.login_path instead", deprecator: Alchemy::Deprecation
|
|
93
25
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
@@user_class_name.constantize
|
|
97
|
-
rescue NameError => e
|
|
98
|
-
if /#{Regexp.escape(@@user_class_name)}/.match?(e.message)
|
|
99
|
-
Rails.logger.warn <<~MSG
|
|
100
|
-
#{e.message}
|
|
101
|
-
#{e.backtrace.join("\n")}
|
|
26
|
+
delegate :login_path=, to: :config
|
|
27
|
+
deprecate :login_path= => "Use `Alchemy.config.login_path instead", :deprecator => Alchemy::Deprecation
|
|
102
28
|
|
|
103
|
-
|
|
29
|
+
delegate :logout_path, to: :config
|
|
30
|
+
deprecate logout_path: "Use `Alchemy.config.logout_path instead", deprecator: Alchemy::Deprecation
|
|
104
31
|
|
|
105
|
-
|
|
32
|
+
delegate :logout_path=, to: :config
|
|
33
|
+
deprecate :logout_path= => "Use `Alchemy.config.logout_path instead", :deprecator => Alchemy::Deprecation
|
|
106
34
|
|
|
107
|
-
|
|
108
|
-
|
|
35
|
+
delegate :logout_method, to: :config
|
|
36
|
+
deprecate logout_method: "Use `Alchemy.config.logout_method instead", deprecator: Alchemy::Deprecation
|
|
109
37
|
|
|
110
|
-
|
|
38
|
+
delegate :logout_method=, to: :config
|
|
39
|
+
deprecate :logout_method= => "Use `Alchemy.config.logout_method instead", :deprecator => Alchemy::Deprecation
|
|
111
40
|
|
|
112
|
-
|
|
41
|
+
delegate :unauthorized_path, to: :config
|
|
42
|
+
deprecate unauthorized_path: "Use `Alchemy.config.unauthorized_path instead", deprecator: Alchemy::Deprecation
|
|
113
43
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
44
|
+
delegate :unauthorized_path=, to: :config
|
|
45
|
+
deprecate :unauthorized_path= => "Use `Alchemy.config.unauthorized_path instead", :deprecator => Alchemy::Deprecation
|
|
46
|
+
|
|
47
|
+
delegate :user_class, to: :config
|
|
48
|
+
deprecate user_class: "Use `Alchemy.config.user_class instead", deprecator: Alchemy::Deprecation
|
|
49
|
+
|
|
50
|
+
delegate :user_class_name, to: :config
|
|
51
|
+
deprecate user_class_name: "Use `Alchemy.config.user_class_name instead", deprecator: Alchemy::Deprecation
|
|
52
|
+
|
|
53
|
+
def user_class_name=(klass_name)
|
|
54
|
+
config.user_class = klass_name
|
|
119
55
|
end
|
|
120
|
-
|
|
56
|
+
deprecate :user_class_name= => "Use `Alchemy.config.user_class instead", :deprecator => Alchemy::Deprecation
|
|
121
57
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
@abilities << klass
|
|
127
|
-
end
|
|
58
|
+
def register_ability(klass)
|
|
59
|
+
config.abilities.add(klass.name)
|
|
60
|
+
end
|
|
61
|
+
deprecate register_ability: 'Use `Alchemy.config.abilities.add("MyClass")` instead', deprecator: Alchemy::Deprecation
|
|
128
62
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
63
|
+
def registered_abilities
|
|
64
|
+
config.abilities
|
|
65
|
+
end
|
|
66
|
+
deprecate registered_abilities: "Use `Alchemy.config.abilities` instead", deprecator: Alchemy::Deprecation
|
|
133
67
|
end
|
|
134
68
|
end
|
|
@@ -39,6 +39,7 @@ module Alchemy
|
|
|
39
39
|
|
|
40
40
|
alias_method :get, :send
|
|
41
41
|
alias_method :[], :get
|
|
42
|
+
alias_method :configure, :tap
|
|
42
43
|
|
|
43
44
|
def show = self
|
|
44
45
|
|
|
@@ -67,8 +68,6 @@ module Alchemy
|
|
|
67
68
|
).to_h
|
|
68
69
|
end
|
|
69
70
|
|
|
70
|
-
delegate :to_json, to: :to_h
|
|
71
|
-
|
|
72
71
|
class << self
|
|
73
72
|
def defined_configurations = []
|
|
74
73
|
|
|
@@ -378,6 +378,69 @@ module Alchemy
|
|
|
378
378
|
# Default is 1 hour.
|
|
379
379
|
#
|
|
380
380
|
option :update_check_cache_duration, :integer, default: 1
|
|
381
|
+
|
|
382
|
+
# === The user class to be used for Alchemy
|
|
383
|
+
#
|
|
384
|
+
# If you don't have your own user model or don't want to provide one,
|
|
385
|
+
# add the `alchemy-devise` gem into your App's Gemfile.
|
|
386
|
+
#
|
|
387
|
+
# == Example
|
|
388
|
+
# Alchemy.config.user_class = "MyUser"
|
|
389
|
+
option :user_class, :class
|
|
390
|
+
|
|
391
|
+
# Returns the user class name
|
|
392
|
+
#
|
|
393
|
+
# Prefixed with :: when getting to avoid constant name conflicts
|
|
394
|
+
def user_class_name = "::#{raw_user_class}"
|
|
395
|
+
|
|
396
|
+
# === User class primary key
|
|
397
|
+
#
|
|
398
|
+
# Your users table primary key. Defaults to +id+
|
|
399
|
+
#
|
|
400
|
+
# == Example
|
|
401
|
+
# Alchemy.config.user_class_primary_key = :uuid
|
|
402
|
+
option :user_class_primary_key, :symbol, default: :id
|
|
403
|
+
|
|
404
|
+
# === Current user method
|
|
405
|
+
#
|
|
406
|
+
# A method on your ApplicationController to get current user. Defaults to +:id+
|
|
407
|
+
#
|
|
408
|
+
# == Example
|
|
409
|
+
# Alchemy.config.current_user_method = :my_current_user
|
|
410
|
+
option :current_user_method, :symbol, default: :current_user
|
|
411
|
+
|
|
412
|
+
# === Signup Path
|
|
413
|
+
#
|
|
414
|
+
# The path to the signup form. Defaults to "/signup"
|
|
415
|
+
option :signup_path, :string, default: "/signup"
|
|
416
|
+
|
|
417
|
+
# === Login Path
|
|
418
|
+
#
|
|
419
|
+
# The path to the login form. Defaults to "/login"
|
|
420
|
+
option :login_path, :string, default: "/login"
|
|
421
|
+
|
|
422
|
+
# === Logout Path
|
|
423
|
+
#
|
|
424
|
+
# The path to the logout method.
|
|
425
|
+
option :logout_path, :string, default: "/logout"
|
|
426
|
+
|
|
427
|
+
# === Logout Method
|
|
428
|
+
#
|
|
429
|
+
# The http verb for the logout method. Defaults to "delete"
|
|
430
|
+
option :logout_method, :string, default: "delete"
|
|
431
|
+
|
|
432
|
+
# === Unauthorized Path
|
|
433
|
+
#
|
|
434
|
+
# The path to the page showing the user they're unauthorized
|
|
435
|
+
option :unauthorized_path, :string, default: "/"
|
|
436
|
+
|
|
437
|
+
# === CanCan abilities
|
|
438
|
+
#
|
|
439
|
+
# If your app or your engine has own CanCan abilities you must register them.
|
|
440
|
+
#
|
|
441
|
+
# == Example
|
|
442
|
+
# Alchemy.config.abilities.add("MyCustom::Ability")
|
|
443
|
+
option :abilities, :collection, item_type: :class
|
|
381
444
|
end
|
|
382
445
|
end
|
|
383
446
|
end
|
|
@@ -34,7 +34,7 @@ module Alchemy
|
|
|
34
34
|
# you can install the `alchemy-devise` gem that provides everything you need.
|
|
35
35
|
#
|
|
36
36
|
def current_alchemy_user
|
|
37
|
-
current_user_method = Alchemy.current_user_method
|
|
37
|
+
current_user_method = Alchemy.config.current_user_method
|
|
38
38
|
raise NoCurrentUserFoundError if !respond_to?(current_user_method, true)
|
|
39
39
|
|
|
40
40
|
send current_user_method
|
|
@@ -80,8 +80,7 @@ module Alchemy
|
|
|
80
80
|
|
|
81
81
|
def load_alchemy_language_from_id_or_code(id_or_code)
|
|
82
82
|
Language.find_by(id: id_or_code) ||
|
|
83
|
-
Language.find_by_code(id_or_code)
|
|
84
|
-
Language.default
|
|
83
|
+
Language.find_by_code(id_or_code)
|
|
85
84
|
end
|
|
86
85
|
|
|
87
86
|
# Stores language in +Current.language+
|
data/lib/alchemy/engine.rb
CHANGED
|
@@ -79,11 +79,11 @@ module Alchemy
|
|
|
79
79
|
config.to_prepare do
|
|
80
80
|
# Definition files
|
|
81
81
|
elements_reloader = Rails.application.config.file_watcher.new([ElementDefinition.definitions_file_path]) do
|
|
82
|
-
|
|
82
|
+
Logger.info "Reloading Element Definitions."
|
|
83
83
|
ElementDefinition.reset!
|
|
84
84
|
end
|
|
85
85
|
page_layouts_reloader = Rails.application.config.file_watcher.new([PageDefinition.layouts_file_path]) do
|
|
86
|
-
|
|
86
|
+
Logger.info "Reloading Page Layouts."
|
|
87
87
|
PageDefinition.reset!
|
|
88
88
|
end
|
|
89
89
|
[elements_reloader, page_layouts_reloader].each do |reloader|
|
|
@@ -122,6 +122,10 @@ module Alchemy
|
|
|
122
122
|
ActiveStorage::Blob.define_singleton_method(:ransackable_attributes) do |_auth_object|
|
|
123
123
|
%w[filename]
|
|
124
124
|
end
|
|
125
|
+
|
|
126
|
+
ActiveStorage::Blob.define_singleton_method(:ransackable_associations) do |_auth_object|
|
|
127
|
+
%w[]
|
|
128
|
+
end
|
|
125
129
|
end
|
|
126
130
|
end
|
|
127
131
|
|
|
@@ -143,10 +147,10 @@ module Alchemy
|
|
|
143
147
|
end
|
|
144
148
|
|
|
145
149
|
config.after_initialize do
|
|
146
|
-
if Alchemy.user_class
|
|
150
|
+
if Alchemy.config.user_class
|
|
147
151
|
ActiveSupport.on_load(:active_record) do
|
|
148
|
-
Alchemy.user_class.model_stamper
|
|
149
|
-
Alchemy.user_class.stampable(stamper_class_name: Alchemy.user_class_name)
|
|
152
|
+
Alchemy.config.user_class.model_stamper
|
|
153
|
+
Alchemy.config.user_class.stampable(stamper_class_name: Alchemy.config.user_class_name)
|
|
150
154
|
end
|
|
151
155
|
end
|
|
152
156
|
|
|
@@ -167,14 +171,7 @@ module Alchemy
|
|
|
167
171
|
Rack::Mime::MIME_TYPES[".webp"] = webp
|
|
168
172
|
end
|
|
169
173
|
|
|
170
|
-
# ActiveStorage 7.2 adds support for webp, but we still support Rails 7.1
|
|
171
174
|
if app.config.active_storage
|
|
172
|
-
unless app.config.active_storage.web_image_content_types.include? webp
|
|
173
|
-
app.config.active_storage.web_image_content_types += [webp]
|
|
174
|
-
end
|
|
175
|
-
unless app.config.active_storage.content_types_allowed_inline.include? webp
|
|
176
|
-
app.config.active_storage.content_types_allowed_inline += [webp]
|
|
177
|
-
end
|
|
178
175
|
# Rails sends svg images as attachment instead of inline.
|
|
179
176
|
# We want to display svgs and not download them.
|
|
180
177
|
unless app.config.active_storage.content_types_allowed_inline.include? svg
|
|
@@ -4,7 +4,7 @@ module Alchemy
|
|
|
4
4
|
module ErrorTracking
|
|
5
5
|
class ErrorLogger < BaseHandler
|
|
6
6
|
def self.call(exception)
|
|
7
|
-
::Rails.logger.tagged("
|
|
7
|
+
::Rails.logger.tagged("alchemy") do
|
|
8
8
|
::Rails.logger.error("#{exception.class.name}: #{exception.message} in #{exception.backtrace.first}")
|
|
9
9
|
end
|
|
10
10
|
end
|
data/lib/alchemy/errors.rb
CHANGED
data/lib/alchemy/logger.rb
CHANGED
|
@@ -2,14 +2,44 @@
|
|
|
2
2
|
|
|
3
3
|
module Alchemy
|
|
4
4
|
module Logger
|
|
5
|
-
# Logs a debug message to the Rails standard logger
|
|
6
|
-
def self.
|
|
7
|
-
Rails.logger.
|
|
5
|
+
# Logs a debug message to the Rails standard logger
|
|
6
|
+
def self.debug(message)
|
|
7
|
+
Rails.logger.tagged("alchemy") do
|
|
8
|
+
Rails.logger.debug(message)
|
|
9
|
+
end
|
|
10
|
+
nil
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Logs a error message to the Rails standard logger
|
|
14
|
+
def self.error(message)
|
|
15
|
+
Rails.logger.tagged("alchemy") do
|
|
16
|
+
Rails.logger.error("ERROR: #{message}")
|
|
17
|
+
end
|
|
18
|
+
nil
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Logs a info message to the Rails standard logger
|
|
22
|
+
def self.info(message)
|
|
23
|
+
Rails.logger.tagged("alchemy") do
|
|
24
|
+
Rails.logger.info(message)
|
|
25
|
+
end
|
|
26
|
+
nil
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Logs a warning message to the Rails standard logger
|
|
30
|
+
def self.warn(message, caller_string = nil)
|
|
31
|
+
if caller_string
|
|
32
|
+
Alchemy::Deprecation.warn("Alchemy::Logger.warn second argument is deprecated and will be removed in Alchemy 9.0")
|
|
33
|
+
end
|
|
34
|
+
Rails.logger.tagged("alchemy") do
|
|
35
|
+
Rails.logger.warn("WARNING: #{message}")
|
|
36
|
+
end
|
|
8
37
|
nil
|
|
9
38
|
end
|
|
10
39
|
|
|
11
40
|
def log_warning(message)
|
|
12
|
-
Alchemy::Logger.warn(message
|
|
41
|
+
Alchemy::Logger.warn(message)
|
|
13
42
|
end
|
|
43
|
+
deprecate log_warning: "Alchemy::Logger.warn", deprecator: Alchemy::Deprecation
|
|
14
44
|
end
|
|
15
45
|
end
|
|
@@ -17,12 +17,6 @@ module Alchemy
|
|
|
17
17
|
.parameterize
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
# Converts a filename and suffix into a human readable name.
|
|
21
|
-
#
|
|
22
|
-
def convert_to_humanized_name(name, suffix)
|
|
23
|
-
name.gsub(/\.#{::Regexp.quote(suffix)}$/i, "").tr("_", " ").strip
|
|
24
|
-
end
|
|
25
|
-
|
|
26
20
|
# Sanitizes a given filename by removing directory traversal attempts and HTML entities.
|
|
27
21
|
def sanitized_filename(file_name)
|
|
28
22
|
file_name = File.basename(file_name)
|
data/lib/alchemy/seeder.rb
CHANGED
|
@@ -63,14 +63,14 @@ module Alchemy
|
|
|
63
63
|
def seed_users
|
|
64
64
|
desc "Seeding Alchemy users from #{user_seeds_file}"
|
|
65
65
|
|
|
66
|
-
if Alchemy.user_class.exists?
|
|
66
|
+
if Alchemy.config.user_class.exists?
|
|
67
67
|
log "There are already users present in your database. " \
|
|
68
68
|
"Please use `rake db:reset' if you want to rebuild your database.", :skip
|
|
69
69
|
false
|
|
70
70
|
else
|
|
71
71
|
users = load_yaml_file(user_seeds_file)
|
|
72
72
|
users.each do |draft|
|
|
73
|
-
user = Alchemy.user_class.create!(draft)
|
|
73
|
+
user = Alchemy.config.user_class.create!(draft)
|
|
74
74
|
log "Created user: #{user.try(:email) || user.try(:login) || user.id}"
|
|
75
75
|
end
|
|
76
76
|
end
|
data/lib/alchemy/tasks/usage.rb
CHANGED
|
@@ -18,11 +18,11 @@ module Alchemy
|
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
def pages_count_by_type
|
|
21
|
-
res = Alchemy::Page
|
|
22
|
-
.select("page_layout, COUNT(*) AS count")
|
|
21
|
+
res = Alchemy::Page
|
|
23
22
|
.group(:page_layout)
|
|
24
|
-
.order("
|
|
25
|
-
.
|
|
23
|
+
.order("count_all DESC, page_layout ASC")
|
|
24
|
+
.count
|
|
25
|
+
.map { |layout, count| {"page_layout" => layout, "count" => count} }
|
|
26
26
|
Alchemy::PageDefinition.all.reject { |page_layout| res.map { |p| p["page_layout"] }.include?(page_layout.name) }.sort_by(&:name).each do |page_layout|
|
|
27
27
|
res << {"page_layout" => page_layout.name, "count" => 0}
|
|
28
28
|
end
|
|
@@ -212,6 +212,22 @@ RSpec.shared_examples_for "having picture thumbnails" do
|
|
|
212
212
|
thumbnail_url
|
|
213
213
|
end
|
|
214
214
|
|
|
215
|
+
context "with size given" do
|
|
216
|
+
subject(:thumbnail_url) { record.thumbnail_url(size: "10x10") }
|
|
217
|
+
|
|
218
|
+
it "passes it to the thumbnail url options." do
|
|
219
|
+
expect(picture).to receive(:url).with(hash_including(size: "10x10"))
|
|
220
|
+
thumbnail_url
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
context "with no size given" do
|
|
225
|
+
it "passes default size to the thumbnail url options." do
|
|
226
|
+
expect(picture).to receive(:url).with(hash_including(size: "160x120"))
|
|
227
|
+
thumbnail_url
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
|
|
215
231
|
context "when crop is enabled in the settings" do
|
|
216
232
|
let(:settings) do
|
|
217
233
|
{crop: true}
|
|
@@ -300,6 +316,20 @@ RSpec.shared_examples_for "having picture thumbnails" do
|
|
|
300
316
|
allow(record).to receive(:settings) { settings }
|
|
301
317
|
end
|
|
302
318
|
|
|
319
|
+
context "with size given" do
|
|
320
|
+
subject(:thumbnail_url_options) { record.thumbnail_url_options(size: "10x10") }
|
|
321
|
+
|
|
322
|
+
it "passes it to the thumbnail url options." do
|
|
323
|
+
expect(thumbnail_url_options[:size]).to eq("10x10")
|
|
324
|
+
end
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
context "with no size given" do
|
|
328
|
+
it "passes default size to the thumbnail url options." do
|
|
329
|
+
expect(thumbnail_url_options[:size]).to eq("160x120")
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
|
|
303
333
|
context "with picture assigned" do
|
|
304
334
|
let(:picture) do
|
|
305
335
|
create(:alchemy_picture)
|
|
@@ -1,21 +1,41 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
RSpec.shared_examples_for "an alchemy ingredient editor" do
|
|
4
|
-
let(:ingredient_editor) {
|
|
4
|
+
let(:ingredient_editor) { described_class.new(ingredient) }
|
|
5
5
|
|
|
6
6
|
before do
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
allow(element_editor).to receive(:ingredients) { [ingredient_editor] }
|
|
7
|
+
vc_test_view_context.class.include Alchemy::Admin::BaseHelper
|
|
8
|
+
allow(vc_test_view_context).to receive(:can?).and_return(true)
|
|
10
9
|
end
|
|
11
10
|
|
|
12
11
|
subject do
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
render_inline(ingredient_editor)
|
|
13
|
+
page
|
|
15
14
|
end
|
|
16
15
|
|
|
17
16
|
it "renders a ingredient editor", :aggregate_failures do
|
|
18
17
|
is_expected.to have_css(".ingredient-editor.#{ingredient_editor.partial_name}")
|
|
19
18
|
is_expected.to have_css("[data-ingredient-role]")
|
|
19
|
+
is_expected.to have_css("##{ingredient.class.model_name.param_key}_#{ingredient.id}")
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "provides a label" do
|
|
23
|
+
is_expected.to have_css("label[for]", text: Alchemy.t(
|
|
24
|
+
ingredient_editor.role,
|
|
25
|
+
scope: "ingredient_roles.#{element.name}",
|
|
26
|
+
default: Alchemy.t("ingredient_roles.#{ingredient_editor.role}", default: ingredient_editor.role.humanize)
|
|
27
|
+
))
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "provides a ingredient input field" do
|
|
31
|
+
is_expected.to have_css("input[name]")
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "provides an ingredient id field for nested attributes" do
|
|
35
|
+
counter = ingredient_editor.send(:form_field_counter)
|
|
36
|
+
is_expected.to have_css(
|
|
37
|
+
"input[type='hidden'][name='element[ingredients_attributes][#{counter}][id]'][value='#{ingredient.id}']",
|
|
38
|
+
visible: :hidden
|
|
39
|
+
)
|
|
20
40
|
end
|
|
21
41
|
end
|