binda 0.0.7 → 0.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 +850 -18
- data/Rakefile +1 -13
- data/app/assets/javascripts/binda/application.js +23 -0
- data/app/assets/javascripts/binda/components/bootstrap.js +9 -0
- data/app/assets/javascripts/binda/components/field_group_editor.js +18 -0
- data/app/assets/javascripts/binda/components/fileupload.js +182 -0
- data/app/assets/javascripts/binda/components/form_item.js +91 -23
- data/app/assets/javascripts/binda/components/form_item_choice.js +15 -8
- data/app/assets/javascripts/binda/components/form_item_editor.js +6 -6
- data/app/assets/javascripts/binda/components/form_item_image.js +23 -0
- data/app/assets/javascripts/binda/components/form_item_repeater.js +70 -23
- data/app/assets/javascripts/binda/components/login-shader.js +193 -0
- data/app/assets/javascripts/binda/components/login_form.js +116 -0
- data/app/assets/javascripts/binda/components/radio-toggle.js +18 -0
- data/app/assets/javascripts/binda/components/select2.js +22 -0
- data/app/assets/javascripts/binda/components/sortable.js +53 -8
- data/app/assets/javascripts/binda/dist/binda.bundle.js +914 -107
- data/app/assets/javascripts/binda/index.js +26 -3
- data/app/assets/stylesheets/binda/application.scss +6 -0
- data/app/assets/stylesheets/binda/components/assets_manager.scss +46 -36
- data/app/assets/stylesheets/binda/components/b-btn.scss +114 -0
- data/app/assets/stylesheets/binda/components/button.scss +4 -1
- data/app/assets/stylesheets/binda/components/fileupload.scss +134 -0
- data/app/assets/stylesheets/binda/components/form_item.scss +233 -168
- data/app/assets/stylesheets/binda/components/form_item_image.scss +0 -0
- data/app/assets/stylesheets/binda/components/form_item_video.scss +25 -0
- data/app/assets/stylesheets/binda/components/main_container.scss +3 -0
- data/app/assets/stylesheets/binda/components/main_content.scss +1 -2
- data/app/assets/stylesheets/binda/components/main_header.scss +21 -20
- data/app/assets/stylesheets/binda/components/main_sidebar.scss +121 -0
- data/app/assets/stylesheets/binda/components/main_table.scss +84 -28
- data/app/assets/stylesheets/binda/components/popup_warning.scss +71 -0
- data/app/assets/stylesheets/binda/components/select2.scss +126 -0
- data/app/assets/stylesheets/binda/components/sortable.scss +83 -56
- data/app/assets/stylesheets/binda/components/standard-form.scss +228 -0
- data/app/assets/stylesheets/binda/components/texts.scss +6 -0
- data/app/assets/stylesheets/binda/controllers/components_index.scss +3 -0
- data/app/assets/stylesheets/binda/controllers/users_sessions_new.scss +309 -0
- data/app/assets/stylesheets/binda/index.scss +16 -8
- data/app/assets/stylesheets/binda/settings/bootstrap_overrides.scss +0 -0
- data/app/assets/stylesheets/binda/settings/buttons.scss +36 -0
- data/app/assets/stylesheets/binda/settings/common.scss +36 -79
- data/app/assets/stylesheets/binda/settings/fonts.scss +88 -31
- data/app/assets/stylesheets/binda/settings/tiny_mce_overrides.scss +82 -0
- data/app/assets/stylesheets/binda/settings/variables.scss +36 -31
- data/app/controllers/binda/application_controller.rb +0 -2
- data/app/controllers/binda/assets_controller.rb +1 -1
- data/app/controllers/binda/boards_controller.rb +15 -4
- data/app/controllers/binda/components_controller.rb +30 -15
- data/app/controllers/binda/field_groups_controller.rb +19 -4
- data/app/controllers/binda/images_controller.rb +68 -0
- data/app/controllers/binda/repeaters_controller.rb +3 -12
- data/app/controllers/binda/structures_controller.rb +8 -1
- data/app/controllers/binda/videos_controller.rb +68 -0
- data/app/controllers/concerns/binda/fieldable_helpers.rb +113 -28
- data/app/controllers/concerns/binda/maintenance_helpers.rb +34 -0
- data/app/helpers/binda/components_helper.rb +26 -2
- data/app/helpers/binda/field_groups_helper.rb +16 -0
- data/app/helpers/binda/structures_helper.rb +6 -0
- data/app/models/binda/asset.rb +0 -4
- data/app/models/binda/b.rb +5 -0
- data/app/models/binda/board.rb +1 -18
- data/app/models/binda/choice.rb +48 -12
- data/app/models/binda/component.rb +20 -0
- data/app/models/binda/field_group.rb +2 -2
- data/app/models/binda/field_setting.rb +61 -28
- data/app/models/binda/gallery.rb +0 -2
- data/app/models/binda/image.rb +7 -0
- data/app/models/binda/relation.rb +79 -0
- data/app/models/binda/relation_link.rb +11 -0
- data/app/models/binda/repeater.rb +1 -1
- data/app/models/binda/selection.rb +0 -9
- data/app/models/binda/structure.rb +41 -39
- data/app/models/binda/video.rb +7 -0
- data/app/models/concerns/binda/default_helpers.rb +186 -0
- data/app/models/concerns/binda/fieldable_associations.rb +276 -30
- data/app/uploaders/binda/{asset → image}/image_uploader.rb +27 -9
- data/app/uploaders/binda/video/video_uploader.rb +51 -0
- data/app/views/binda/boards/edit.html.erb +6 -1
- data/app/views/binda/categories/_form.html.erb +41 -40
- data/app/views/binda/categories/edit.html.erb +1 -1
- data/app/views/binda/categories/index.html.erb +16 -13
- data/app/views/binda/components/edit.html.erb +6 -3
- data/app/views/binda/components/index.html.erb +69 -28
- data/app/views/binda/components/new.html.erb +1 -1
- data/app/views/binda/components/sort_index.html.erb +46 -0
- data/app/views/binda/field_groups/_form_body.html.erb +65 -44
- data/app/views/binda/field_groups/_form_item.html.erb +66 -23
- data/app/views/binda/field_groups/_form_item_choice.erb +34 -15
- data/app/views/binda/field_groups/_form_section.html.erb +6 -10
- data/app/views/binda/field_groups/_form_section_repeater.html.erb +3 -3
- data/app/views/binda/field_groups/edit.html.erb +1 -1
- data/app/views/binda/field_settings/_form_body.html.erb +5 -5
- data/app/views/binda/field_settings/edit.html.erb +1 -1
- data/app/views/binda/fieldable/_form_body.html.erb +93 -79
- data/app/views/binda/fieldable/_form_item_date.html.erb +14 -14
- data/app/views/binda/fieldable/_form_item_image.html.erb +35 -0
- data/app/views/binda/fieldable/_form_item_new_repeater.html.erb +12 -5
- data/app/views/binda/fieldable/_form_item_relation.html.erb +44 -0
- data/app/views/binda/fieldable/_form_item_repeater.html.erb +80 -58
- data/app/views/binda/fieldable/_form_item_selections.html.erb +109 -87
- data/app/views/binda/fieldable/_form_item_string.html.erb +19 -17
- data/app/views/binda/fieldable/_form_item_text.html.erb +19 -16
- data/app/views/binda/fieldable/_form_item_video.html.erb +32 -0
- data/app/views/binda/fieldable/_form_section.html.erb +27 -5
- data/app/views/binda/fieldable/_form_section_repeater.html.erb +30 -10
- data/app/views/binda/fieldable/_form_sidebar.html.erb +44 -20
- data/app/views/binda/manage/users/_form_body.html.erb +42 -37
- data/app/views/binda/manage/users/edit.html.erb +1 -1
- data/app/views/binda/manage/users/index.html.erb +21 -21
- data/app/views/binda/structures/_form_body.html.erb +54 -60
- data/app/views/binda/structures/_form_section.html.erb +32 -18
- data/app/views/binda/structures/_form_sidebar.html.erb +35 -0
- data/app/views/binda/structures/edit.html.erb +2 -2
- data/app/views/binda/structures/index.html.erb +21 -16
- data/app/views/binda/structures/sort_index.html.erb +36 -0
- data/app/views/{users → binda/users}/confirmations/new.html.erb +1 -1
- data/app/views/{users → binda/users}/mailer/confirmation_instructions.html.erb +0 -0
- data/app/views/{users → binda/users}/mailer/password_change.html.erb +0 -0
- data/app/views/{users → binda/users}/mailer/reset_password_instructions.html.erb +0 -0
- data/app/views/{users → binda/users}/mailer/unlock_instructions.html.erb +0 -0
- data/app/views/{users → binda/users}/passwords/edit.html.erb +1 -1
- data/app/views/{users → binda/users}/passwords/new.html.erb +1 -1
- data/app/views/{users → binda/users}/registrations/edit.html.erb +0 -0
- data/app/views/{users → binda/users}/registrations/new.html.erb +1 -1
- data/app/views/binda/users/sessions/_background.html.erb +139 -0
- data/app/views/binda/users/sessions/new.html.erb +62 -0
- data/app/views/{users → binda/users}/shared/_links.html.erb +3 -3
- data/app/views/{users → binda/users}/unlocks/new.html.erb +1 -1
- data/app/views/kaminari/_first_page.html.erb +11 -0
- data/app/views/kaminari/_gap.html.erb +8 -0
- data/app/views/kaminari/_last_page.html.erb +11 -0
- data/app/views/kaminari/_next_page.html.erb +11 -0
- data/app/views/kaminari/_page.html.erb +12 -0
- data/app/views/kaminari/_paginator.html.erb +19 -0
- data/app/views/kaminari/_prev_page.html.erb +11 -0
- data/app/views/layouts/binda/_flash.html.erb +1 -1
- data/app/views/layouts/binda/_header.html.erb +2 -6
- data/app/views/layouts/binda/_sidebar.html.erb +11 -4
- data/app/views/layouts/binda/application.html.erb +15 -7
- data/config/autoprefixer.yml +5 -0
- data/config/database.yml.travis +3 -0
- data/config/initializers/assets.rb +1 -0
- data/config/initializers/autoprefixer.yml +5 -0
- data/config/initializers/carrierwave.rb +32 -0
- data/config/initializers/devise.rb +14 -10
- data/config/initializers/devise_patch.rb +8 -8
- data/config/initializers/simple_form.rb +4 -0
- data/config/initializers/simple_form__fileupload.rb +121 -0
- data/config/initializers/{simple_form_bootstrap.rb → simple_form_custom.rb} +79 -50
- data/config/locales/en.yml +61 -3
- data/config/locales/it.yml +51 -0
- data/config/locales/simple_form.en.yml +3 -3
- data/config/routes.rb +41 -24
- data/db/migrate/1_create_binda_tables.rb +18 -7
- data/db/migrate/20171214140451_add_preview_mode.rb +5 -0
- data/lib/binda.rb +1 -1
- data/lib/binda/engine.rb +19 -23
- data/lib/binda/version.rb +2 -2
- data/lib/generators/binda/install/install_generator.rb +59 -54
- data/lib/generators/binda/install/templates/config/initializers/carrierwave.rb +11 -2
- data/lib/generators/binda/maintenance/USAGE +8 -0
- data/lib/generators/binda/maintenance/maintenance_generator.rb +50 -0
- data/lib/generators/binda/maintenance/templates/app/assets/javascripts/maintenance.js +0 -0
- data/lib/generators/binda/maintenance/templates/app/assets/stylesheets/maintenance.scss +0 -0
- data/lib/generators/binda/maintenance/templates/app/views/layouts/maintenance.html.erb +16 -0
- data/lib/generators/binda/maintenance/templates/config/initializers/maintenance.rb +1 -0
- data/lib/generators/binda/setup/setup_generator.rb +41 -30
- data/lib/tasks/add_default_helpers_class_task.rake +11 -0
- data/lib/tasks/add_video_feature_task.rake +15 -0
- data/lib/tasks/remove_orphan_fields_task.rake +16 -0
- data/lib/tasks/set_repeater_position_task.rake +13 -0
- data/lib/tasks/upgrade_to_v007_task.rake +72 -0
- data/lib/tasks/user_tasks.rake +14 -0
- data/vendor/assets/fonts/font-awesome/fa-brands-400.eot +0 -0
- data/vendor/assets/fonts/font-awesome/fa-brands-400.svg +978 -0
- data/vendor/assets/fonts/font-awesome/fa-brands-400.ttf +0 -0
- data/vendor/assets/fonts/font-awesome/fa-brands-400.woff +0 -0
- data/vendor/assets/fonts/font-awesome/fa-brands-400.woff2 +0 -0
- data/vendor/assets/fonts/font-awesome/fa-regular-400.eot +0 -0
- data/vendor/assets/fonts/font-awesome/fa-regular-400.svg +363 -0
- data/vendor/assets/fonts/font-awesome/fa-regular-400.ttf +0 -0
- data/vendor/assets/fonts/font-awesome/fa-regular-400.woff +0 -0
- data/vendor/assets/fonts/font-awesome/fa-regular-400.woff2 +0 -0
- data/vendor/assets/fonts/font-awesome/fa-solid-900.eot +0 -0
- data/vendor/assets/fonts/font-awesome/fa-solid-900.svg +1410 -0
- data/vendor/assets/fonts/font-awesome/fa-solid-900.ttf +0 -0
- data/vendor/assets/fonts/font-awesome/fa-solid-900.woff +0 -0
- data/vendor/assets/fonts/font-awesome/fa-solid-900.woff2 +0 -0
- data/vendor/assets/javascripts/GSAP/CSSPlugin.min.js +13 -0
- data/vendor/assets/javascripts/GSAP/EasePack.min.js +12 -0
- data/vendor/assets/javascripts/GSAP/ScrollToPlugin.min.js +12 -0
- data/vendor/assets/javascripts/GSAP/TweenLite.min.js +12 -0
- data/vendor/assets/javascripts/select2/i18n/af.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/ar.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/az.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/bg.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/bs.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/ca.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/cs.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/da.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/de.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/dsb.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/el.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/en.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/es.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/et.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/eu.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/fa.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/fi.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/fr.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/gl.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/he.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/hi.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/hr.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/hsb.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/hu.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/hy.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/id.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/is.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/it.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/ja.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/km.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/ko.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/lt.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/lv.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/mk.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/ms.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/nb.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/nl.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/pl.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/ps.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/pt-BR.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/pt.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/ro.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/ru.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/sk.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/sl.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/sr-Cyrl.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/sr.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/sv.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/th.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/tr.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/uk.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/vi.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/zh-CN.js +3 -0
- data/vendor/assets/javascripts/select2/i18n/zh-TW.js +3 -0
- data/vendor/assets/javascripts/select2/select2.full.min.js +1 -0
- data/vendor/assets/javascripts/select2/select2.min.js +1 -0
- data/vendor/assets/javascripts/tether.min.js +1 -0
- data/vendor/assets/stylesheets/{bootstrap-select.css → bootstrap/bootstrap-select.css} +0 -0
- data/vendor/assets/stylesheets/font-awesome/_animated.scss +6 -20
- data/vendor/assets/stylesheets/font-awesome/_bordered-pulled.scss +6 -11
- data/vendor/assets/stylesheets/font-awesome/_core.scss +11 -7
- data/vendor/assets/stylesheets/font-awesome/_fixed-width.scss +1 -1
- data/vendor/assets/stylesheets/font-awesome/_icons.scss +785 -787
- data/vendor/assets/stylesheets/font-awesome/_larger.scss +16 -6
- data/vendor/assets/stylesheets/font-awesome/_list.scss +7 -8
- data/vendor/assets/stylesheets/font-awesome/_mixins.scss +17 -20
- data/vendor/assets/stylesheets/font-awesome/_rotated-flipped.scss +9 -6
- data/vendor/assets/stylesheets/font-awesome/_screen-reader.scss +2 -2
- data/vendor/assets/stylesheets/font-awesome/_stacked.scss +19 -8
- data/vendor/assets/stylesheets/font-awesome/_variables.scss +795 -795
- data/vendor/assets/stylesheets/font-awesome/fa-brands.scss +21 -0
- data/vendor/assets/stylesheets/font-awesome/fa-regular.scss +22 -0
- data/vendor/assets/stylesheets/font-awesome/fa-solid.scss +23 -0
- data/vendor/assets/stylesheets/font-awesome/fontawesome.scss +20 -0
- data/vendor/assets/stylesheets/select2/select2.min.css +1 -0
- metadata +278 -125
- data/app/assets/javascripts/binda/components/form_item_asset.js +0 -25
- data/app/assets/stylesheets/binda/application.css +0 -6
- data/app/assets/stylesheets/binda/components/form_body.scss +0 -2
- data/app/assets/stylesheets/binda/components/form_item_asset.scss +0 -20
- data/app/assets/stylesheets/binda/components/form_section.scss +0 -40
- data/app/assets/stylesheets/binda/components/sidebar.scss +0 -131
- data/app/assets/stylesheets/binda/layout/components_index.scss +0 -9
- data/app/assets/stylesheets/binda/layout/dashboard.scss +0 -7
- data/app/assets/stylesheets/binda/layout/users_sign_in.scss +0 -29
- data/app/controllers/binda/bindings_controller.rb +0 -62
- data/app/controllers/concerns/binda/default_helpers.rb +0 -226
- data/app/helpers/binda/bindings_helper.rb +0 -4
- data/app/models/binda/binda.rb +0 -7
- data/app/models/binda/binding.rb +0 -24
- data/app/views/binda/bindings/_form.html.erb +0 -32
- data/app/views/binda/bindings/edit.html.erb +0 -6
- data/app/views/binda/bindings/index.html.erb +0 -31
- data/app/views/binda/bindings/new.html.erb +0 -5
- data/app/views/binda/bindings/show.html.erb +0 -19
- data/app/views/binda/field_groups/index.html.erb +0 -34
- data/app/views/binda/fieldable/_form_item_asset.html.erb +0 -20
- data/app/views/users/sessions/new.html.erb +0 -27
- data/lib/tasks/binda.rake +0 -79
- data/vendor/assets/fonts/font-awesome/FontAwesome.otf +0 -0
- data/vendor/assets/fonts/font-awesome/fontawesome-webfont.eot +0 -0
- data/vendor/assets/fonts/font-awesome/fontawesome-webfont.svg +0 -2671
- data/vendor/assets/fonts/font-awesome/fontawesome-webfont.ttf +0 -0
- data/vendor/assets/fonts/font-awesome/fontawesome-webfont.woff +0 -0
- data/vendor/assets/fonts/font-awesome/fontawesome-webfont.woff2 +0 -0
- data/vendor/assets/stylesheets/font-awesome/_path.scss +0 -15
- data/vendor/assets/stylesheets/font-awesome/font-awesome.scss +0 -18
data/app/models/binda/gallery.rb
CHANGED
@@ -0,0 +1,79 @@
|
|
1
|
+
module Binda
|
2
|
+
# Relation
|
3
|
+
#
|
4
|
+
# This model is used to connect components and boards to each others.
|
5
|
+
#
|
6
|
+
# `Relation` gathers all connection a `Component` record has with other records (being
|
7
|
+
# another `Component` or `Board`). It's possible to have multiple relations for the
|
8
|
+
# same component and each one can gather connections to several other components.
|
9
|
+
# Any relation has one owner and several dependents. A relation is a one-direction operation
|
10
|
+
# meaning that an owner can choose its dependents, not the other way around.
|
11
|
+
#
|
12
|
+
# Reference: https://www.railstutorial.org/book/following_users
|
13
|
+
#
|
14
|
+
# @example: owner = Binda::Component.first
|
15
|
+
# dependent = Binda::Component.last
|
16
|
+
# relation_setting = Binda::FieldSetting.create(field_type: relation, field_group_id: owner.structure.field_groups.first)
|
17
|
+
# relation = owner.relations.where(field_setting_id: relation_setting.id).first
|
18
|
+
# relation.dependent_components << dependent
|
19
|
+
class Relation < ApplicationRecord
|
20
|
+
|
21
|
+
belongs_to :fieldable, polymorphic: true
|
22
|
+
belongs_to :field_setting
|
23
|
+
|
24
|
+
# Relations are the connection between a Owner to its Dependents
|
25
|
+
# The Active Relation connects a Relation to a Dependent (which is can be a Component or a Board)
|
26
|
+
# The Passive Relation connects a Relation to a Owner (which is can be a Component or a Board)
|
27
|
+
has_many :dependent_relations, class_name: "RelationLink",
|
28
|
+
dependent: :destroy,
|
29
|
+
as: :owner
|
30
|
+
|
31
|
+
|
32
|
+
# Dependents are connected to a owner in a Passive Relation
|
33
|
+
# Strictly speaking you cannot choose an Owner for a Dependent,
|
34
|
+
# you can do just the opposite: choose a Dependent starting from a Owner
|
35
|
+
#
|
36
|
+
# The current version support components and boards separately
|
37
|
+
has_many :dependent_components, through: :dependent_relations,
|
38
|
+
source: :dependent,
|
39
|
+
source_type: "Binda::Component"
|
40
|
+
|
41
|
+
|
42
|
+
# Owner are connected to its Dependents in a Active Relation
|
43
|
+
# meaning its possible to connect a Owner to as many Dependents
|
44
|
+
# as it's needed.
|
45
|
+
#
|
46
|
+
# The current version support components and boards separately
|
47
|
+
has_many :dependent_boards, through: :dependent_relations,
|
48
|
+
source: :dependent,
|
49
|
+
source_type: "Binda::Board"
|
50
|
+
|
51
|
+
|
52
|
+
# Owner are connected to its Dependents in a Active Relation
|
53
|
+
# meaning its possible to connect a Owner to as many Dependents
|
54
|
+
# as it's needed.
|
55
|
+
#
|
56
|
+
# The current version support components and boards separately
|
57
|
+
has_many :dependent_repeaters, through: :dependent_relations,
|
58
|
+
source: :dependent,
|
59
|
+
source_type: "Binda::Repeater"
|
60
|
+
|
61
|
+
|
62
|
+
# Makes sure that the group of related components doesn't include the component that owns the group
|
63
|
+
# in other words makes sure that the component doesn't relate to itself
|
64
|
+
validates_each :dependent_component_ids do |model, attr, value|
|
65
|
+
if model.fieldable_type == 'Binda::Component' && value.include?(model.fieldable_id)
|
66
|
+
model.errors.add(attr, "#{FieldSetting.find(model.field_setting_id).name.capitalize} contains a reference to the current #{model.fieldable_type.constantize.find(model.fieldable_id).structure.name.capitalize}")
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Makes sure that the group of related components doesn't include the component that owns the group
|
71
|
+
# in other words makes sure that the component doesn't relate to itself
|
72
|
+
validates_each :dependent_board_ids do |model, attr, value|
|
73
|
+
if model.fieldable_type == 'Binda::Board' && value.include?(model.fieldable_id)
|
74
|
+
model.errors.add(attr, "#{FieldSetting.find(model.field_setting_id).name.capitalize} contains a reference to the current #{model.fieldable_type.constantize.find(model.fieldable_id).structure.name.capitalize}")
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
@@ -13,11 +13,11 @@ module Binda
|
|
13
13
|
|
14
14
|
after_create :set_default_position
|
15
15
|
|
16
|
-
|
17
16
|
# Set default position after create
|
18
17
|
#
|
19
18
|
# This methods ensure that every repeater instance has an explicit position.
|
20
19
|
# The latest repeater created gets the highest position number.
|
20
|
+
# The first position is 1 (not 0).
|
21
21
|
#
|
22
22
|
# @return [object] Repeater instance
|
23
23
|
def set_default_position
|
@@ -4,14 +4,5 @@ module Binda
|
|
4
4
|
has_and_belongs_to_many :choices
|
5
5
|
belongs_to :field_setting
|
6
6
|
|
7
|
-
after_create :set_choice
|
8
|
-
|
9
|
-
# Set the default choice if the field must have at least one.
|
10
|
-
# This method run after the record is created.
|
11
|
-
def set_choice
|
12
|
-
return if self.field_setting.allow_null
|
13
|
-
self.choices << self.field_setting.default_choice if self.choices.empty?
|
14
|
-
end
|
15
|
-
|
16
7
|
end
|
17
8
|
end
|
@@ -2,10 +2,12 @@ module Binda
|
|
2
2
|
class Structure < ApplicationRecord
|
3
3
|
|
4
4
|
# Associations
|
5
|
-
has_many :components
|
6
|
-
has_one :board
|
7
|
-
has_many :categories
|
8
|
-
has_many :field_groups
|
5
|
+
has_many :components, dependent: :destroy
|
6
|
+
has_one :board, dependent: :destroy
|
7
|
+
has_many :categories, dependent: :destroy
|
8
|
+
has_many :field_groups, dependent: :destroy
|
9
|
+
|
10
|
+
has_and_belongs_to_many :field_settings
|
9
11
|
|
10
12
|
# Validations
|
11
13
|
validates :name, presence: true
|
@@ -19,15 +21,15 @@ module Binda
|
|
19
21
|
|
20
22
|
after_create :add_default_field_group
|
21
23
|
after_create :add_instance_details
|
22
|
-
|
24
|
+
after_create :set_default_position
|
23
25
|
|
24
26
|
# Friendly id preference on slug generation
|
25
27
|
#
|
26
28
|
# Method inherited from friendly id
|
27
29
|
# @see https://github.com/norman/friendly_id/issues/436
|
28
|
-
|
29
|
-
|
30
|
-
|
30
|
+
def should_generate_new_friendly_id?
|
31
|
+
slug.blank? || name_changed?
|
32
|
+
end
|
31
33
|
|
32
34
|
#
|
33
35
|
# Sets the validation rules to accept and save an attribute
|
@@ -51,39 +53,39 @@ module Binda
|
|
51
53
|
# field group called 'General Details' after the structure is created.
|
52
54
|
# @return [redirect]
|
53
55
|
def add_default_field_group
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
56
|
+
# Creates a default empty field group
|
57
|
+
field_group = self.field_groups.build( name: 'General Details', position: 1 )
|
58
|
+
# Unless there is a problem...
|
59
|
+
unless field_group.save
|
60
|
+
return redirect_to structure_path( self.slug ), flash: { error: 'General Details group hasn\'t been created' }
|
61
|
+
end
|
62
|
+
end
|
61
63
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
64
|
+
# Add details based on instance type
|
65
|
+
#
|
66
|
+
# If instance_type is set to 'setting' it generates a default Binda::Setting instance after creation.
|
67
|
+
# The generated instance will be associated to the structure and named after it.
|
68
|
+
# It also disable categories (this could be a different method, or method could be more explicit)
|
69
|
+
def add_instance_details
|
70
|
+
if self.instance_type == 'board'
|
71
|
+
self.update_attribute 'has_categories', false
|
72
|
+
board = self.build_board( name: self.name )
|
73
|
+
unless board.save
|
74
|
+
return redirect_to structure_path( self.slug ), flash: { error: 'The board instance hasn\'t been created' }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
76
78
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
79
|
+
# Set default position after create
|
80
|
+
#
|
81
|
+
# This methods ensure that every repeater instance has an explicit position.
|
82
|
+
# The latest repeater created gets the highest position number.
|
83
|
+
#
|
84
|
+
# @return [object] Repeater instance
|
85
|
+
def set_default_position
|
86
|
+
position = Structure.all.length
|
87
|
+
self.update_attribute 'position', position
|
88
|
+
end
|
87
89
|
|
88
90
|
end
|
89
91
|
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
module Binda
|
2
|
+
# Binda comes with a bunch of helpers to make life easier.
|
3
|
+
module DefaultHelpers
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
end
|
8
|
+
|
9
|
+
class_methods do
|
10
|
+
|
11
|
+
# Get components
|
12
|
+
#
|
13
|
+
# This method retrieves **all components** belonging to a specific structure.
|
14
|
+
# See the following example.
|
15
|
+
#
|
16
|
+
# @example Assuming you have two structures 'page' and 'post':
|
17
|
+
# B.get_components()
|
18
|
+
# # returns all components from all structures
|
19
|
+
#
|
20
|
+
# B.get_components(['page', 'post'])
|
21
|
+
# # returns pages and posts, i.e. all components belonging to 'page' and 'post' structures
|
22
|
+
#
|
23
|
+
# B.get_components('page')
|
24
|
+
# # returns all pages
|
25
|
+
#
|
26
|
+
# B.get_components('page').find_by(slug: 'my-first-page')
|
27
|
+
# # returns `my-first-page`
|
28
|
+
#
|
29
|
+
# # expand query
|
30
|
+
# B.get_components('page').where(publish_state: 'published').order('position')
|
31
|
+
#
|
32
|
+
# # reduce N+1 query issue by including dependencies
|
33
|
+
# B.get_components('page').includes(:strings, :texts, repeaters: [:images, :selections])
|
34
|
+
#
|
35
|
+
# @param slug [string] The slug of the structure to which the components belong
|
36
|
+
# @param slug [array] The slugs of the structures to which the components belongs
|
37
|
+
#
|
38
|
+
# @return [ActiveRelation Object] if slug is nil or is an array
|
39
|
+
#
|
40
|
+
def get_components slug = nil
|
41
|
+
if slug.nil?
|
42
|
+
Component.all
|
43
|
+
else
|
44
|
+
# Generate query
|
45
|
+
Component.where( structure_id: Structure.where( slug: slug ) )
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Get boards
|
50
|
+
#
|
51
|
+
# This method retrieves **boards**.
|
52
|
+
# See the following example.
|
53
|
+
#
|
54
|
+
# @example Assuming you have a `default-dashboard`
|
55
|
+
# B.get_boards()
|
56
|
+
# # returns all boards of all structures
|
57
|
+
#
|
58
|
+
# B.get_boards('default-dashboard').first
|
59
|
+
# # returns the board
|
60
|
+
#
|
61
|
+
# # reduce N+1 query issue by including dependencies
|
62
|
+
# B.get_boards('default-dashboard').includes(:strings, :texts, repeaters: [:images, :selections]).first
|
63
|
+
#
|
64
|
+
# @param slug [string] The slug of the structure on which the board is based
|
65
|
+
# @param slug [array] The slugs of the structures to which the board belongs
|
66
|
+
#
|
67
|
+
# @return [ActiveRelation Object] if slug is nil or is an array
|
68
|
+
#
|
69
|
+
def get_boards slug = nil
|
70
|
+
if slug.nil?
|
71
|
+
Board.all
|
72
|
+
else
|
73
|
+
Board.where( structure_id: Structure.where( slug: slug ) )
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Get categories
|
78
|
+
#
|
79
|
+
# This method retrieves **categories**.
|
80
|
+
# See the following example.
|
81
|
+
#
|
82
|
+
# @example Assuming you have two structures 'page' and 'post':
|
83
|
+
# B.get_categories()
|
84
|
+
# # returns all categories belonging to all structures
|
85
|
+
#
|
86
|
+
# B.get_categories('page')
|
87
|
+
# # returns all categories belonging to the 'page' structure
|
88
|
+
#
|
89
|
+
# B.get_categories(['page', 'post'])
|
90
|
+
# # returns all categories belonging to 'page' structure and the ones belonging to 'post' structure
|
91
|
+
#
|
92
|
+
# @param slug [string] The slug of the structure to which categories belong
|
93
|
+
# @param slug [array] The slugs of the structures to which categories belong
|
94
|
+
#
|
95
|
+
# @return [ActiveRelation Object]
|
96
|
+
#
|
97
|
+
def get_categories slug = nil
|
98
|
+
if slug.nil?
|
99
|
+
Category.all
|
100
|
+
else
|
101
|
+
Category.where( structure_id: Structure.where( slug: slug ) )
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# Get field settings
|
106
|
+
#
|
107
|
+
# This method retrieves **field settings**.
|
108
|
+
# See the following example.
|
109
|
+
#
|
110
|
+
# @example Assuming you have two field settings 'subtitle' and 'description':
|
111
|
+
# B.get_field_settings()
|
112
|
+
# # returns all field settings
|
113
|
+
#
|
114
|
+
# B.get_field_settings('subtitle')
|
115
|
+
# # returns an ActiveRelation (a sort of Array) containing the 'subtitle' field setting
|
116
|
+
#
|
117
|
+
# @param slug [string] The slug of a specific field setting
|
118
|
+
# @param slug [array] The slugs of the selected field settings
|
119
|
+
#
|
120
|
+
# @return [ActiveRelation Object]
|
121
|
+
#
|
122
|
+
def get_field_settings slug = nil
|
123
|
+
if slug.nil?
|
124
|
+
FieldSetting.all
|
125
|
+
else
|
126
|
+
FieldSetting.where(slug: slug)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# Get each owner of all relations with the specified slug (or slugs)
|
131
|
+
#
|
132
|
+
# @param slug [string] The slug of the field setting to which the relations belong
|
133
|
+
# @param slug [array] The slugs of the field settings to which the relations belong
|
134
|
+
#
|
135
|
+
# @return [Array]
|
136
|
+
#
|
137
|
+
def get_relation_owners field_slug
|
138
|
+
owner_class = Structure.includes(field_groups: :field_settings)
|
139
|
+
.where(binda_field_settings: {id: FieldSetting.where(slug: field_slug)})
|
140
|
+
.first
|
141
|
+
obj = "Binda::#{owner_class.instance_type.classify}".constantize
|
142
|
+
.distinct
|
143
|
+
.includes(relations: :dependent_components)
|
144
|
+
.where(binda_relations: {field_setting_id: FieldSetting.where(slug: field_slug)})
|
145
|
+
raise ArgumentError, "There isn't any instance with a relation associated to the current slug (#{field_slug}).", caller if obj.nil?
|
146
|
+
return obj
|
147
|
+
end
|
148
|
+
|
149
|
+
|
150
|
+
# Get each dependent of all relations with the specified slug (or slugs)
|
151
|
+
#
|
152
|
+
# This can be useful to retrieve only the instances which have a owner. For example, you have several
|
153
|
+
# 'event' components, where each one is related to several 'artist' components with a 'partecipants'
|
154
|
+
# relation field where every event owns some artists.
|
155
|
+
# If you want to retrieve all artists which have been involved in at least one event you can try with
|
156
|
+
# `B.get_relation_dependents('partecipants')`.
|
157
|
+
#
|
158
|
+
# You can also ask for all instance type of dependent or specify 'components' or 'boards' using
|
159
|
+
# the second parameter.
|
160
|
+
#
|
161
|
+
# @param slug [string] The slug of the field setting to which the relations belong
|
162
|
+
#
|
163
|
+
# @return [Array]
|
164
|
+
#
|
165
|
+
def get_relation_dependents field_slug, instance_type = nil
|
166
|
+
raise ArgumentError, "There isn't any instance named: #{instance_type}. Make sure is either 'component' or 'board'", caller if !instance_type.nil? && ['board','component'].include?(instance_type)
|
167
|
+
|
168
|
+
dependents = []
|
169
|
+
if instance_type != 'board'
|
170
|
+
dependent_components = Component.distinct
|
171
|
+
.includes(:owner_components)
|
172
|
+
.where(binda_relations: {field_setting_id: FieldSetting.where(slug: field_slug)})
|
173
|
+
dependents = [ *dependents, *dependent_components ]
|
174
|
+
elsif instance_type != 'component'
|
175
|
+
dependent_boards = Board.distinct
|
176
|
+
.includes(:owner_components)
|
177
|
+
.where(binda_relations: {field_setting_id: FieldSetting.where(slug: field_slug)})
|
178
|
+
dependents = [ *dependents, *dependent_boards ]
|
179
|
+
end
|
180
|
+
|
181
|
+
raise ArgumentError, "There isn't any instance with a relation associated to the current slug (#{field_slug}).", caller unless dependents.any?
|
182
|
+
return dependents
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
@@ -15,22 +15,74 @@ module Binda
|
|
15
15
|
# - get_fieldables (see here below)
|
16
16
|
# - get_field_types (see here below)
|
17
17
|
# - component_params (app/controllers/binda/components_controller.rb)
|
18
|
+
|
18
19
|
has_many :texts, as: :fieldable, dependent: :delete_all
|
19
20
|
has_many :strings, as: :fieldable, dependent: :delete_all
|
20
21
|
has_many :dates, as: :fieldable, dependent: :delete_all
|
21
22
|
has_many :galleries, as: :fieldable, dependent: :delete_all
|
22
23
|
has_many :assets, as: :fieldable, dependent: :delete_all
|
24
|
+
has_many :images, as: :fieldable, dependent: :delete_all
|
25
|
+
has_many :videos, as: :fieldable, dependent: :delete_all
|
23
26
|
has_many :radios, as: :fieldable, dependent: :delete_all
|
24
27
|
has_many :selections, as: :fieldable, dependent: :delete_all
|
25
28
|
has_many :checkboxes, as: :fieldable, dependent: :delete_all
|
26
29
|
# Repeaters need destroy_all, not delete_all
|
27
30
|
has_many :repeaters, as: :fieldable, dependent: :destroy
|
31
|
+
has_many :relations, as: :fieldable, dependent: :destroy
|
32
|
+
|
33
|
+
|
34
|
+
has_many :owner_relations, class_name: "RelationLink",
|
35
|
+
dependent: :destroy,
|
36
|
+
as: :dependent
|
37
|
+
|
38
|
+
# Owner are connected to its Dependents in a Active Relation
|
39
|
+
# meaning its possible to connect a Owner to as many Dependents
|
40
|
+
# as it's needed.
|
41
|
+
#
|
42
|
+
# The current version support components and boards separately
|
43
|
+
has_many :owner_components, through: :owner_relations,
|
44
|
+
source: :owner
|
28
45
|
|
29
|
-
|
30
|
-
|
46
|
+
has_many :owner_boards, through: :owner_relations,
|
47
|
+
source: :owner
|
31
48
|
|
32
|
-
|
49
|
+
has_many :owner_repeaters, through: :owner_relations,
|
50
|
+
source: :owner
|
33
51
|
|
52
|
+
|
53
|
+
accepts_nested_attributes_for :texts, :strings, :dates, :assets, :images, :videos, :galleries, :repeaters, :radios, :selections, :checkboxes, :relations, allow_destroy: true
|
54
|
+
|
55
|
+
validates_associated :texts
|
56
|
+
validates_associated :strings
|
57
|
+
validates_associated :dates
|
58
|
+
validates_associated :assets
|
59
|
+
validates_associated :images
|
60
|
+
validates_associated :videos
|
61
|
+
validates_associated :repeaters
|
62
|
+
validates_associated :radios
|
63
|
+
validates_associated :selections
|
64
|
+
validates_associated :checkboxes
|
65
|
+
validates_associated :relations
|
66
|
+
|
67
|
+
after_save :generate_fields
|
68
|
+
|
69
|
+
# Uncomment these "validate do" loop to better debug validation.
|
70
|
+
# This makes method gather errors of the associated records and
|
71
|
+
# make them available to the instance object. After using this method
|
72
|
+
# you will be able to see the actual error inside `instance.errors` array.
|
73
|
+
# Example: @component.errors #=> [ ... ]
|
74
|
+
#
|
75
|
+
# validate do |instance|
|
76
|
+
# instance.texts.each do |text|
|
77
|
+
# binding.pry
|
78
|
+
# next if text.valid?
|
79
|
+
# text.errors.full_messages.each do |msg|
|
80
|
+
# # you can customize the error message here:
|
81
|
+
# errors[:base] << "Error in #{text.field_setting.name} (text): #{msg}"
|
82
|
+
# end
|
83
|
+
# end
|
84
|
+
# end
|
85
|
+
|
34
86
|
end
|
35
87
|
|
36
88
|
# Get the object related to that field setting
|
@@ -40,15 +92,15 @@ module Binda
|
|
40
92
|
# @return [string] Returns the content of the text
|
41
93
|
# @return [error] Raise an error if no record is found
|
42
94
|
def get_text field_slug
|
43
|
-
obj = self.texts.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) && t.type
|
95
|
+
obj = self.texts.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) && t.type != 'Binda::String' }
|
44
96
|
unless obj.nil?
|
45
97
|
obj.content
|
46
98
|
else
|
47
99
|
you_mean_string = !self.strings.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) && t.type = 'Binda::String' }.nil?
|
48
100
|
if you_mean_string
|
49
|
-
raise ArgumentError, "This slug is associated to a string not a text. Use get_string() instead.", caller
|
101
|
+
raise ArgumentError, "This slug (#{field_slug}) is associated to a string not a text. Use get_string() instead on instance (#{self.class.name} ##{self.id}).", caller
|
50
102
|
else
|
51
|
-
raise ArgumentError, "There isn't any text associated to the current slug.", caller
|
103
|
+
raise ArgumentError, "There isn't any text associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller
|
52
104
|
end
|
53
105
|
end
|
54
106
|
end
|
@@ -58,7 +110,8 @@ module Binda
|
|
58
110
|
# @param field_slug [string] The slug of the field setting
|
59
111
|
# @return [boolean]
|
60
112
|
def has_text field_slug
|
61
|
-
obj = self.texts.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) && t.type
|
113
|
+
obj = self.texts.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) && t.type != 'Binda::String' }
|
114
|
+
raise ArgumentError, "There isn't any text associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller if obj.nil?
|
62
115
|
if obj.present?
|
63
116
|
return !obj.content.blank?
|
64
117
|
else
|
@@ -73,15 +126,15 @@ module Binda
|
|
73
126
|
# @return [string] Returns the content of the string
|
74
127
|
# @return [error] Raise an error if no record is found
|
75
128
|
def get_string field_slug
|
76
|
-
obj = self.strings.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) && t.type
|
129
|
+
obj = self.strings.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) && t.type == 'Binda::String' }
|
77
130
|
unless obj.nil?
|
78
131
|
obj.content
|
79
132
|
else
|
80
133
|
you_mean_text = !self.strings.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) && t.type = 'Binda::Text' }.nil?
|
81
134
|
if you_mean_text
|
82
|
-
raise ArgumentError, "This slug is associated to a text not a string. Use get_text() instead.", caller
|
135
|
+
raise ArgumentError, "This slug (#{field_slug}) is associated to a text not a string. Use get_text() instead on instance (#{self.class.name} ##{self.id}).", caller
|
83
136
|
else
|
84
|
-
raise ArgumentError, "There isn't any string associated to the current slug.", caller
|
137
|
+
raise ArgumentError, "There isn't any string associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller
|
85
138
|
end
|
86
139
|
end
|
87
140
|
end
|
@@ -91,7 +144,8 @@ module Binda
|
|
91
144
|
# @param field_slug [string] The slug of the field setting
|
92
145
|
# @return [boolean]
|
93
146
|
def has_string field_slug
|
94
|
-
obj = self.strings.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) && t.type
|
147
|
+
obj = self.strings.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) && t.type == 'Binda::String' }
|
148
|
+
raise ArgumentError, "There isn't any string associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller if obj.nil?
|
95
149
|
if obj.present?
|
96
150
|
return !obj.content.blank?
|
97
151
|
else
|
@@ -104,8 +158,11 @@ module Binda
|
|
104
158
|
# @param field_slug [string] The slug of the field setting
|
105
159
|
# @return [boolean]
|
106
160
|
def has_image field_slug
|
107
|
-
obj = self.
|
108
|
-
|
161
|
+
obj = self.images.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) }
|
162
|
+
# Alternative query
|
163
|
+
# obj = Image.where(field_setting_id: FieldSetting.get_id( field_slug ), fieldable_id: self.id, fieldable_type: self.class.to_s ).first
|
164
|
+
raise ArgumentError, "There isn't any image associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller if obj.nil?
|
165
|
+
return obj.image.present?
|
109
166
|
end
|
110
167
|
|
111
168
|
# Get the image url based on the size provided,
|
@@ -139,7 +196,23 @@ module Binda
|
|
139
196
|
# @return [string] The info requested if present
|
140
197
|
# @return [boolean] Returns false if no info is found or if image isn't found
|
141
198
|
def get_image_info field_slug, size, info
|
142
|
-
obj = self.
|
199
|
+
obj = self.images.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) }
|
200
|
+
# Alternative query
|
201
|
+
# obj = Image.where(field_setting_id: FieldSetting.get_id( field_slug ), fieldable_id: self.id, fieldable_type: self.class.to_s ).first
|
202
|
+
raise ArgumentError, "There isn't any image associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller if obj.nil?
|
203
|
+
if obj.image.present?
|
204
|
+
if obj.image.respond_to?(size) && %w[thumb medium large].include?(size)
|
205
|
+
obj.image.send(size).send(info)
|
206
|
+
else
|
207
|
+
obj.image.send(info)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
def get_image_dimension field_slug
|
213
|
+
obj = self.images.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) }
|
214
|
+
|
215
|
+
raise ArgumentError, "There isn't any image associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller if obj.nil?
|
143
216
|
if obj.image.present?
|
144
217
|
if obj.image.respond_to?(size) && %w[thumb medium large].include?(size)
|
145
218
|
obj.image.send(size).send(info)
|
@@ -149,6 +222,56 @@ module Binda
|
|
149
222
|
end
|
150
223
|
end
|
151
224
|
|
225
|
+
# Check if the field has an attached video
|
226
|
+
#
|
227
|
+
# @param field_slug [string] The slug of the field setting
|
228
|
+
# @return [boolean]
|
229
|
+
def has_video field_slug
|
230
|
+
obj = self.videos.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) }
|
231
|
+
# Alternative query
|
232
|
+
# obj = Image.where(field_setting_id: FieldSetting.get_id( field_slug ), fieldable_id: self.id, fieldable_type: self.class.to_s ).first
|
233
|
+
raise ArgumentError, "There isn't any video associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller if obj.nil?
|
234
|
+
return obj.video.present?
|
235
|
+
end
|
236
|
+
|
237
|
+
# Get the video url based on the size provided,
|
238
|
+
# default is Carrierwave default (usually the real size)
|
239
|
+
#
|
240
|
+
# @param field_slug [string] The slug of the field setting
|
241
|
+
# @param size [string] The size. It can be 'thumb' 200x200 cropped,
|
242
|
+
# 'medium' 700x700 max size, 'large' 1400x1400 max size, or blank
|
243
|
+
# @return [string] The url of the video
|
244
|
+
def get_video_url field_slug
|
245
|
+
get_video_info( field_slug, 'url' )
|
246
|
+
end
|
247
|
+
|
248
|
+
# Get the video path based on the size provided,
|
249
|
+
# default is Carrierwave default (usually the real size)
|
250
|
+
#
|
251
|
+
# @param field_slug [string] The slug of the field setting
|
252
|
+
# @param size [string] The size. It can be 'thumb' 200x200 cropped,
|
253
|
+
# 'medium' 700x700 max size, 'large' 1400x1400 max size, or blank
|
254
|
+
# @return [string] The url of the video
|
255
|
+
def get_video_path field_slug
|
256
|
+
get_video_info( field_slug, 'path' )
|
257
|
+
end
|
258
|
+
|
259
|
+
# Get the object related to that field setting
|
260
|
+
#
|
261
|
+
# @param field_slug [string] The slug of the field setting
|
262
|
+
# @param info [string] String of the info to be retrieved
|
263
|
+
# @return [string] The info requested if present
|
264
|
+
# @return [boolean] Returns false if no info is found or if image isn't found
|
265
|
+
def get_video_info field_slug, info
|
266
|
+
obj = self.videos.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) }
|
267
|
+
# Alternative query
|
268
|
+
# obj = video.where(field_setting_id: FieldSetting.get_id( field_slug ), fieldable_id: self.id, fieldable_type: self.class.to_s ).first
|
269
|
+
raise ArgumentError, "There isn't any video associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller if obj.nil?
|
270
|
+
if obj.video.present?
|
271
|
+
obj.video.send(info)
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
152
275
|
# Check if the field has an attached date
|
153
276
|
#
|
154
277
|
# @param field_slug [string] The slug of the field setting
|
@@ -156,6 +279,7 @@ module Binda
|
|
156
279
|
# @return [boolean] Reutrn false if nothing is found
|
157
280
|
def has_date field_slug
|
158
281
|
obj = self.dates.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) }
|
282
|
+
raise ArgumentError, "There isn't any date associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller if obj.nil?
|
159
283
|
if obj.present?
|
160
284
|
return !obj.date.nil?
|
161
285
|
else
|
@@ -169,7 +293,8 @@ module Binda
|
|
169
293
|
# @return [boolean]
|
170
294
|
def get_date field_slug
|
171
295
|
obj = self.dates.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) }
|
172
|
-
|
296
|
+
raise ArgumentError, "There isn't any date associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller if obj.nil?
|
297
|
+
obj.date
|
173
298
|
end
|
174
299
|
|
175
300
|
# Check if exists any repeater with that slug
|
@@ -178,6 +303,7 @@ module Binda
|
|
178
303
|
# @return [boolean]
|
179
304
|
def has_repeater field_slug
|
180
305
|
obj = self.repeaters.find_all{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) }
|
306
|
+
raise ArgumentError, "There isn't any repeater associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller if obj.nil?
|
181
307
|
return obj.present?
|
182
308
|
end
|
183
309
|
|
@@ -187,7 +313,8 @@ module Binda
|
|
187
313
|
# @return [hash]
|
188
314
|
def get_repeater field_slug
|
189
315
|
obj = self.repeaters.find_all{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) }
|
190
|
-
|
316
|
+
raise ArgumentError, "There isn't any repeater associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller if obj.nil?
|
317
|
+
obj.sort_by(&:position)
|
191
318
|
end
|
192
319
|
|
193
320
|
# Get the radio choice
|
@@ -196,46 +323,165 @@ module Binda
|
|
196
323
|
# only the first one will be retrieved.
|
197
324
|
#
|
198
325
|
# @param field_slug [string] The slug of the field setting
|
199
|
-
# @return [hash] A hash of containing the label and value of the selected choice.
|
326
|
+
# @return [hash] A hash of containing the label and value of the selected choice. `{ label: 'the label', value: 'the value'}`
|
200
327
|
def get_radio_choice field_slug
|
201
|
-
|
328
|
+
field_setting = FieldSetting.find_by(slug:field_slug)
|
329
|
+
obj = self.radios.find{ |t| t.field_setting_id == field_setting.id }
|
330
|
+
raise ArgumentError, "There isn't any radio associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller if obj.nil?
|
331
|
+
raise "There isn't any choice available for the current radio (#{field_slug}) on instance (#{self.class.name} ##{self.id})." unless field_setting.choices.any?
|
202
332
|
return { label: obj.choices.first.label, value: obj.choices.first.value }
|
203
333
|
end
|
204
334
|
|
205
335
|
# Get the select choices
|
206
336
|
#
|
207
337
|
# @param field_slug [string] The slug of the field setting
|
208
|
-
# @return [hash] A hash of containing the label and value of the selected choice.
|
338
|
+
# @return [hash] A hash of containing the label and value of the selected choice. `{ label: 'the label', 'value': 'the value'}`
|
209
339
|
def get_selection_choice field_slug
|
210
|
-
|
211
|
-
obj = self.selections.find{ |t| t.field_setting_id
|
340
|
+
field_setting = FieldSetting.find_by(slug:field_slug)
|
341
|
+
obj = self.selections.find{ |t| t.field_setting_id == field_setting.id }
|
342
|
+
raise ArgumentError, "There isn't any radio associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller if obj.nil?
|
343
|
+
raise "There isn't any choice available for the current radio (#{field_slug}) on instance (#{self.class.name} ##{self.id})." unless field_setting.choices.any?
|
212
344
|
return { label: obj.choices.first.label, value: obj.choices.first.value }
|
213
345
|
end
|
214
346
|
|
215
347
|
# Get the checkbox choice
|
216
348
|
#
|
217
349
|
# @param field_slug [string] The slug of the field setting
|
218
|
-
# @return [
|
350
|
+
# @return [array] An array of labels and values of the selected choices. `[{ label: '1st label', value: '1st-value'}, { label: '2nd label', value: '2nd-value'}]`
|
219
351
|
def get_checkbox_choices field_slug
|
220
|
-
|
221
|
-
|
352
|
+
field_setting = FieldSetting.find_by(slug:field_slug)
|
353
|
+
obj = self.checkboxes.find{ |t| t.field_setting_id == field_setting.id }
|
354
|
+
raise ArgumentError, "There isn't any checkbox associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller if obj.nil?
|
355
|
+
raise "There isn't any choice available for the current radio (#{field_slug}) on instance (#{self.class.name} ##{self.id})." unless field_setting.choices.any?
|
356
|
+
obj_array = []
|
222
357
|
obj.choices.order('label').each do |o|
|
223
|
-
|
358
|
+
obj_array << { label: o.label, value: o.value }
|
224
359
|
end
|
225
|
-
return
|
360
|
+
return obj_array
|
361
|
+
end
|
362
|
+
|
363
|
+
# Check if has related components
|
364
|
+
#
|
365
|
+
# @param field_slug [string] The slug of the field setting
|
366
|
+
# @return [boolean]
|
367
|
+
def has_related_components field_slug
|
368
|
+
obj = self.relations.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) }
|
369
|
+
raise ArgumentError, "There isn't any related field associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller if obj.nil?
|
370
|
+
return obj.dependent_relations.any?
|
371
|
+
end
|
372
|
+
|
373
|
+
# Alias for has_related_components
|
374
|
+
def has_dependent_components field_slug
|
375
|
+
has_related_components field_slug
|
376
|
+
end
|
377
|
+
|
378
|
+
# Get related components
|
379
|
+
#
|
380
|
+
# @param field_slug [string] The slug of the field setting
|
381
|
+
# @return [array] An array of components
|
382
|
+
def get_related_components field_slug
|
383
|
+
obj = self.relations.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) }
|
384
|
+
raise ArgumentError, "There isn't any related field associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller if obj.nil?
|
385
|
+
return obj.dependent_relations.map{|relation| relation.dependent}
|
386
|
+
end
|
387
|
+
|
388
|
+
# Alias for get_related_components
|
389
|
+
def get_dependent_components field_slug
|
390
|
+
get_related_components field_slug
|
391
|
+
end
|
392
|
+
|
393
|
+
# Get all components which owns a relation where the current instance is a dependent
|
394
|
+
#
|
395
|
+
# @param field_slug [string] The slug of the field setting of the relation
|
396
|
+
# @return [array] An array of components and/or boards
|
397
|
+
def get_owner_components field_slug
|
398
|
+
# obj = self.owner_relations.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) }
|
399
|
+
obj = Relation.where(field_setting_id: B.get_field_settings(field_slug)).includes(dependent_relations: :dependent).where(binda_relation_links: {dependent_type: self.class.name})
|
400
|
+
raise ArgumentError, "There isn't any relation associated to the current slug (#{field_slug}) where the current instance (#{self.class.name} ##{self.id}) is a dependent.", caller if obj.nil?
|
401
|
+
return obj
|
402
|
+
end
|
403
|
+
|
404
|
+
# Check if has related boards
|
405
|
+
#
|
406
|
+
# @param field_slug [string] The slug of the field setting
|
407
|
+
# @return [boolean]
|
408
|
+
def has_related_boards field_slug
|
409
|
+
obj = self.relations.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) }
|
410
|
+
raise ArgumentError, "There isn't any related field associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller if obj.nil?
|
411
|
+
return obj.dependent_relations.any?
|
412
|
+
end
|
413
|
+
|
414
|
+
# Get related boards
|
415
|
+
#
|
416
|
+
# @param field_slug [string] The slug of the field setting
|
417
|
+
# @return [array] An array of boards
|
418
|
+
def get_related_boards field_slug
|
419
|
+
obj = self.relations.find{ |t| t.field_setting_idid == FieldSetting.get_id( field_slug ) }
|
420
|
+
raise ArgumentError, "There isn't any related field associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller if obj.nil?
|
421
|
+
return obj.dependent_relations.map{|relation| relation.dependent}
|
226
422
|
end
|
227
423
|
|
228
424
|
# Find or create a field by field setting and field type
|
229
|
-
#
|
425
|
+
#
|
426
|
+
# This is used in Binda's editor views.
|
427
|
+
#
|
428
|
+
# Please, check the code to know more about the way this method works as it's pretty complex yet important.
|
230
429
|
#
|
231
430
|
# @param field_setting_id [string] The field setting id
|
232
431
|
# @param field_type [string] THe field type
|
233
432
|
def find_or_create_a_field_by field_setting_id, field_type
|
234
|
-
if FieldSetting.get_field_classes.include?( field_type.
|
235
|
-
|
433
|
+
if FieldSetting.get_field_classes.include?( field_type.classify ) && field_setting_id.is_a?( Integer )
|
434
|
+
# It's mandatory to use `select{}.first`!!!
|
435
|
+
# If you use any ActiveRecord method (like `where` of `find`) the validation errors are wiped out
|
436
|
+
# from the object and not rendered next to the form in the editor view
|
437
|
+
obj = self.send( field_type.pluralize ).select{|rf| rf.field_setting_id == field_setting_id}.first
|
438
|
+
if obj.nil?
|
439
|
+
# As we are using the `select{}.first` method, asynchronous requests passing through
|
440
|
+
# this method will create some inconsistentcy between this `self` object and the real object.
|
441
|
+
# In other words `self` should be reloaded, but we won't reload it otherwise we will
|
442
|
+
# erase the errors shipped with it initially. Therefore we will check again with `find_or_create_by!`.
|
443
|
+
# This leads to another issue, which is: errors coming from asynchronous requests won't be considered
|
444
|
+
# as the `self` object is the initial one, not the "updated" one. At the current time this is not
|
445
|
+
# a problem because the only asynchronous requests are for brand new records which don't need validation.
|
446
|
+
return self.send( field_type.pluralize ).find_or_create_by!( field_setting_id: field_setting_id )
|
447
|
+
else
|
448
|
+
return obj
|
449
|
+
end
|
236
450
|
else
|
237
|
-
raise ArgumentError, "One parameter in find_or_create_a_field_by() is not correct.", caller
|
451
|
+
raise ArgumentError, "One parameter in find_or_create_a_field_by() is not correct on instance (#{self.class.name} ##{self.id}).", caller
|
238
452
|
end
|
239
453
|
end
|
454
|
+
|
455
|
+
# This method is called upon the creation/update of a fieldable record (component, board or repeater)
|
456
|
+
# and generates all fields related to each field settings which belongs to it.
|
457
|
+
#
|
458
|
+
# This avoids any situation in which, for example, a component have a field setting for a text
|
459
|
+
# but there is no text (meaning `Binda::Text` instance) that correspond to that field setting.
|
460
|
+
# This causes issues when looping a bunch of components which will thow a error if you try to access
|
461
|
+
# a component field, as some might have it some might not. This make sure that you can always expect
|
462
|
+
# to find a field instance which might be empty, but certainly it exists.
|
463
|
+
#
|
464
|
+
# TODO check if find_or_create_a_field_by method should be used instead (it's used in editors views)
|
465
|
+
#
|
466
|
+
def generate_fields
|
467
|
+
# If this is a component or a board
|
468
|
+
if self.respond_to?('structure')
|
469
|
+
field_settings = FieldSetting.where(field_group_id: FieldGroup.where(structure_id: self.structure.id))
|
470
|
+
field_settings.each do |field_setting|
|
471
|
+
"Binda::#{field_setting.field_type.classify}".constantize.find_or_create_by!(
|
472
|
+
fieldable_id: self.id, fieldable_type: self.class.name, field_setting_id: field_setting.id )
|
473
|
+
end
|
474
|
+
# If this is a repeater
|
475
|
+
else
|
476
|
+
self.field_setting.children.each do |field_setting|
|
477
|
+
"Binda::#{field_setting.field_type.classify}".constantize.find_or_create_by!(
|
478
|
+
fieldable_id: self.id, fieldable_type: self.class.name, field_setting_id: field_setting.id )
|
479
|
+
end
|
480
|
+
end
|
481
|
+
end
|
482
|
+
|
483
|
+
# TODO: Update all helpers replacing `find` method with ruby `select`.
|
484
|
+
# This should improve performance avoiding generating useless ActiveRecord objects.
|
485
|
+
|
240
486
|
end
|
241
487
|
end
|