hyper-mesh 0.4.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 +7 -0
- data/.gitignore +27 -0
- data/.rspec +2 -0
- data/.rubocop.yml +11 -0
- data/.travis.yml +4 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +396 -0
- data/Rakefile +6 -0
- data/app/controllers/reactive_record/application_controller.rb +4 -0
- data/app/controllers/reactive_record/reactive_record_controller.rb +49 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/codeship.database.yml +18 -0
- data/config/routes.rb +7 -0
- data/docs/action_cable_quickstart.md +151 -0
- data/docs/authorization-policies.md +449 -0
- data/docs/client_side_scoping.md +103 -0
- data/docs/pusher_quickstart.md +0 -0
- data/docs/simple_poller_quickstart.md +121 -0
- data/docs/todo-example.md +116 -0
- data/docs/words-example.md +65 -0
- data/examples/action-cable/.gitignore +21 -0
- data/examples/action-cable/Gemfile +58 -0
- data/examples/action-cable/Gemfile.lock +247 -0
- data/examples/action-cable/README.md +24 -0
- data/examples/action-cable/Rakefile +6 -0
- data/examples/action-cable/app/assets/config/manifest.js +3 -0
- data/examples/action-cable/app/assets/javascripts/application.js +18 -0
- data/examples/action-cable/app/assets/stylesheets/application.css +15 -0
- data/examples/action-cable/app/controllers/application_controller.rb +3 -0
- data/examples/action-cable/app/controllers/test_controller.rb +6 -0
- data/examples/action-cable/app/models/models.rb +2 -0
- data/examples/action-cable/app/models/public/application_record.rb +3 -0
- data/examples/action-cable/app/models/public/word.rb +2 -0
- data/examples/action-cable/app/policies/application_policy.rb +6 -0
- data/examples/action-cable/app/views/components.rb +17 -0
- data/examples/action-cable/app/views/components/app.rb +18 -0
- data/examples/action-cable/app/views/layouts/application.html.erb +14 -0
- data/examples/action-cable/app/views/layouts/mailer.html.erb +13 -0
- data/examples/action-cable/app/views/layouts/mailer.text.erb +1 -0
- data/examples/action-cable/bin/bundle +3 -0
- data/examples/action-cable/bin/rails +9 -0
- data/examples/action-cable/bin/rake +9 -0
- data/examples/action-cable/bin/setup +34 -0
- data/examples/action-cable/bin/spring +15 -0
- data/examples/action-cable/bin/update +29 -0
- data/examples/action-cable/config.ru +5 -0
- data/examples/action-cable/config/application.rb +30 -0
- data/examples/action-cable/config/boot.rb +3 -0
- data/examples/action-cable/config/cable.yml +9 -0
- data/examples/action-cable/config/database.yml +25 -0
- data/examples/action-cable/config/environment.rb +5 -0
- data/examples/action-cable/config/environments/development.rb +45 -0
- data/examples/action-cable/config/environments/production.rb +86 -0
- data/examples/action-cable/config/environments/test.rb +42 -0
- data/examples/action-cable/config/initializers/application_controller_renderer.rb +6 -0
- data/examples/action-cable/config/initializers/assets.rb +11 -0
- data/examples/action-cable/config/initializers/backtrace_silencers.rb +7 -0
- data/examples/action-cable/config/initializers/cookies_serializer.rb +5 -0
- data/examples/action-cable/config/initializers/filter_parameter_logging.rb +4 -0
- data/examples/action-cable/config/initializers/inflections.rb +16 -0
- data/examples/action-cable/config/initializers/mime_types.rb +4 -0
- data/examples/action-cable/config/initializers/new_framework_defaults.rb +24 -0
- data/examples/action-cable/config/initializers/session_store.rb +3 -0
- data/examples/action-cable/config/initializers/synchromesh.rb +5 -0
- data/examples/action-cable/config/initializers/wrap_parameters.rb +14 -0
- data/examples/action-cable/config/locales/en.yml +23 -0
- data/examples/action-cable/config/puma.rb +47 -0
- data/examples/action-cable/config/routes.rb +5 -0
- data/examples/action-cable/config/secrets.yml +22 -0
- data/examples/action-cable/config/spring.rb +6 -0
- data/examples/action-cable/db/migrate/20160921223808_create_words.rb +9 -0
- data/examples/action-cable/db/schema.rb +21 -0
- data/examples/action-cable/log/.keep +0 -0
- data/examples/action-cable/public/404.html +67 -0
- data/examples/action-cable/public/422.html +67 -0
- data/examples/action-cable/public/500.html +66 -0
- data/examples/action-cable/public/apple-touch-icon-precomposed.png +0 -0
- data/examples/action-cable/public/apple-touch-icon.png +0 -0
- data/examples/action-cable/public/favicon.ico +0 -0
- data/examples/action-cable/public/robots.txt +5 -0
- data/examples/action-cable/rails_cache_dir2/C91/480/synchromesh_active_connections +0 -0
- data/examples/action-cable/tmp/.keep +0 -0
- data/examples/action-cable/vendor/assets/javascripts/.keep +0 -0
- data/examples/action-cable/vendor/assets/stylesheets/.keep +0 -0
- data/examples/simple-poller/.gitignore +21 -0
- data/examples/simple-poller/Gemfile +64 -0
- data/examples/simple-poller/Gemfile.lock +272 -0
- data/examples/simple-poller/README.md +24 -0
- data/examples/simple-poller/Rakefile +6 -0
- data/examples/simple-poller/app/assets/config/manifest.js +3 -0
- data/examples/simple-poller/app/assets/images/.keep +0 -0
- data/examples/simple-poller/app/assets/javascripts/application.js +20 -0
- data/examples/simple-poller/app/assets/javascripts/channels/.keep +0 -0
- data/examples/simple-poller/app/assets/stylesheets/application.css +15 -0
- data/examples/simple-poller/app/channels/application_cable/channel.rb +4 -0
- data/examples/simple-poller/app/channels/application_cable/connection.rb +4 -0
- data/examples/simple-poller/app/controllers/application_controller.rb +3 -0
- data/examples/simple-poller/app/controllers/concerns/.keep +0 -0
- data/examples/simple-poller/app/controllers/test_controller.rb +6 -0
- data/examples/simple-poller/app/helpers/application_helper.rb +2 -0
- data/examples/simple-poller/app/jobs/application_job.rb +2 -0
- data/examples/simple-poller/app/mailers/application_mailer.rb +4 -0
- data/examples/simple-poller/app/models/concerns/.keep +0 -0
- data/examples/simple-poller/app/models/models.rb +2 -0
- data/examples/simple-poller/app/models/public/.keep +0 -0
- data/examples/simple-poller/app/models/public/application_record.rb +3 -0
- data/examples/simple-poller/app/models/public/word.rb +2 -0
- data/examples/simple-poller/app/policies/application_policy.rb +5 -0
- data/examples/simple-poller/app/views/components.rb +18 -0
- data/examples/simple-poller/app/views/components/.keep +0 -0
- data/examples/simple-poller/app/views/components/app.rb +40 -0
- data/examples/simple-poller/app/views/layouts/application.html.erb +14 -0
- data/examples/simple-poller/app/views/layouts/mailer.html.erb +13 -0
- data/examples/simple-poller/app/views/layouts/mailer.text.erb +1 -0
- data/examples/simple-poller/bin/bundle +3 -0
- data/examples/simple-poller/bin/rails +9 -0
- data/examples/simple-poller/bin/rake +9 -0
- data/examples/simple-poller/bin/setup +34 -0
- data/examples/simple-poller/bin/spring +16 -0
- data/examples/simple-poller/bin/update +29 -0
- data/examples/simple-poller/config.ru +5 -0
- data/examples/simple-poller/config/application.rb +20 -0
- data/examples/simple-poller/config/boot.rb +3 -0
- data/examples/simple-poller/config/cable.yml +9 -0
- data/examples/simple-poller/config/database.yml +25 -0
- data/examples/simple-poller/config/environment.rb +5 -0
- data/examples/simple-poller/config/environments/development.rb +44 -0
- data/examples/simple-poller/config/environments/production.rb +86 -0
- data/examples/simple-poller/config/environments/test.rb +42 -0
- data/examples/simple-poller/config/initializers/application_controller_renderer.rb +6 -0
- data/examples/simple-poller/config/initializers/assets.rb +11 -0
- data/examples/simple-poller/config/initializers/backtrace_silencers.rb +7 -0
- data/examples/simple-poller/config/initializers/cookies_serializer.rb +5 -0
- data/examples/simple-poller/config/initializers/filter_parameter_logging.rb +4 -0
- data/examples/simple-poller/config/initializers/inflections.rb +16 -0
- data/examples/simple-poller/config/initializers/mime_types.rb +4 -0
- data/examples/simple-poller/config/initializers/new_framework_defaults.rb +24 -0
- data/examples/simple-poller/config/initializers/session_store.rb +3 -0
- data/examples/simple-poller/config/initializers/synchromesh.rb +15 -0
- data/examples/simple-poller/config/initializers/wrap_parameters.rb +14 -0
- data/examples/simple-poller/config/locales/en.yml +23 -0
- data/examples/simple-poller/config/puma.rb +47 -0
- data/examples/simple-poller/config/routes.rb +5 -0
- data/examples/simple-poller/config/secrets.yml +22 -0
- data/examples/simple-poller/config/spring.rb +6 -0
- data/examples/simple-poller/db/migrate/20161013220135_create_words.rb +9 -0
- data/examples/simple-poller/db/schema.rb +21 -0
- data/examples/simple-poller/db/seeds.rb +7 -0
- data/examples/simple-poller/lib/assets/.keep +0 -0
- data/examples/simple-poller/lib/tasks/.keep +0 -0
- data/examples/simple-poller/log/.keep +0 -0
- data/examples/simple-poller/public/404.html +67 -0
- data/examples/simple-poller/public/422.html +67 -0
- data/examples/simple-poller/public/500.html +66 -0
- data/examples/simple-poller/public/apple-touch-icon-precomposed.png +0 -0
- data/examples/simple-poller/public/apple-touch-icon.png +0 -0
- data/examples/simple-poller/public/favicon.ico +0 -0
- data/examples/simple-poller/public/robots.txt +5 -0
- data/examples/simple-poller/test/controllers/.keep +0 -0
- data/examples/simple-poller/test/fixtures/.keep +0 -0
- data/examples/simple-poller/test/fixtures/files/.keep +0 -0
- data/examples/simple-poller/test/fixtures/words.yml +7 -0
- data/examples/simple-poller/test/helpers/.keep +0 -0
- data/examples/simple-poller/test/integration/.keep +0 -0
- data/examples/simple-poller/test/mailers/.keep +0 -0
- data/examples/simple-poller/test/models/.keep +0 -0
- data/examples/simple-poller/test/models/word_test.rb +7 -0
- data/examples/simple-poller/test/test_helper.rb +10 -0
- data/examples/simple-poller/tmp/.keep +0 -0
- data/examples/simple-poller/vendor/assets/javascripts/.keep +0 -0
- data/examples/simple-poller/vendor/assets/stylesheets/.keep +0 -0
- data/examples/words/.gitignore +21 -0
- data/examples/words/Gemfile +58 -0
- data/examples/words/Gemfile.lock +247 -0
- data/examples/words/README.md +24 -0
- data/examples/words/Rakefile +6 -0
- data/examples/words/app/assets/config/manifest.js +3 -0
- data/examples/words/app/assets/javascripts/application.js +18 -0
- data/examples/words/app/assets/stylesheets/application.css +15 -0
- data/examples/words/app/controllers/application_controller.rb +3 -0
- data/examples/words/app/controllers/test_controller.rb +6 -0
- data/examples/words/app/models/models.rb +2 -0
- data/examples/words/app/models/public/application_record.rb +3 -0
- data/examples/words/app/models/public/word.rb +10 -0
- data/examples/words/app/policies/application_policy.rb +6 -0
- data/examples/words/app/views/components.rb +16 -0
- data/examples/words/app/views/components/app.rb +31 -0
- data/examples/words/app/views/layouts/application.html.erb +14 -0
- data/examples/words/app/views/layouts/mailer.html.erb +13 -0
- data/examples/words/app/views/layouts/mailer.text.erb +1 -0
- data/examples/words/bin/bundle +3 -0
- data/examples/words/bin/rails +9 -0
- data/examples/words/bin/rake +9 -0
- data/examples/words/bin/setup +34 -0
- data/examples/words/bin/spring +15 -0
- data/examples/words/bin/update +29 -0
- data/examples/words/config.ru +5 -0
- data/examples/words/config/application.rb +30 -0
- data/examples/words/config/boot.rb +3 -0
- data/examples/words/config/cable.yml +9 -0
- data/examples/words/config/database.yml +25 -0
- data/examples/words/config/environment.rb +5 -0
- data/examples/words/config/environments/development.rb +45 -0
- data/examples/words/config/environments/production.rb +86 -0
- data/examples/words/config/environments/test.rb +42 -0
- data/examples/words/config/initializers/application_controller_renderer.rb +6 -0
- data/examples/words/config/initializers/assets.rb +11 -0
- data/examples/words/config/initializers/backtrace_silencers.rb +7 -0
- data/examples/words/config/initializers/cookies_serializer.rb +5 -0
- data/examples/words/config/initializers/filter_parameter_logging.rb +4 -0
- data/examples/words/config/initializers/inflections.rb +16 -0
- data/examples/words/config/initializers/mime_types.rb +4 -0
- data/examples/words/config/initializers/new_framework_defaults.rb +24 -0
- data/examples/words/config/initializers/session_store.rb +3 -0
- data/examples/words/config/initializers/synchromesh.rb +5 -0
- data/examples/words/config/initializers/wrap_parameters.rb +14 -0
- data/examples/words/config/locales/en.yml +23 -0
- data/examples/words/config/puma.rb +47 -0
- data/examples/words/config/routes.rb +5 -0
- data/examples/words/config/secrets.yml +22 -0
- data/examples/words/config/spring.rb +6 -0
- data/examples/words/db/migrate/20160921223808_create_words.rb +9 -0
- data/examples/words/db/schema.rb +28 -0
- data/examples/words/log/.keep +0 -0
- data/examples/words/public/404.html +67 -0
- data/examples/words/public/422.html +67 -0
- data/examples/words/public/500.html +66 -0
- data/examples/words/public/apple-touch-icon-precomposed.png +0 -0
- data/examples/words/public/apple-touch-icon.png +0 -0
- data/examples/words/public/favicon.ico +0 -0
- data/examples/words/public/robots.txt +5 -0
- data/examples/words/tmp/.keep +0 -0
- data/examples/words/vendor/assets/javascripts/.keep +0 -0
- data/examples/words/vendor/assets/stylesheets/.keep +0 -0
- data/hyper-mesh.gemspec +82 -0
- data/lib/active_record_base.rb +152 -0
- data/lib/enumerable/pluck.rb +6 -0
- data/lib/hyper-mesh.rb +62 -0
- data/lib/hypermesh/version.rb +3 -0
- data/lib/opal/equality_patches.rb +15 -0
- data/lib/opal/parse_patch.rb +14 -0
- data/lib/opal/set_patches.rb +8 -0
- data/lib/reactive_record/active_record/aggregations.rb +69 -0
- data/lib/reactive_record/active_record/associations.rb +111 -0
- data/lib/reactive_record/active_record/base.rb +9 -0
- data/lib/reactive_record/active_record/class_methods.rb +177 -0
- data/lib/reactive_record/active_record/error.rb +26 -0
- data/lib/reactive_record/active_record/instance_methods.rb +129 -0
- data/lib/reactive_record/active_record/public_columns_hash.rb +19 -0
- data/lib/reactive_record/active_record/reactive_record/base.rb +520 -0
- data/lib/reactive_record/active_record/reactive_record/collection.rb +517 -0
- data/lib/reactive_record/active_record/reactive_record/column_types.rb +67 -0
- data/lib/reactive_record/active_record/reactive_record/dummy_value.rb +218 -0
- data/lib/reactive_record/active_record/reactive_record/isomorphic_base.rb +532 -0
- data/lib/reactive_record/active_record/reactive_record/reactive_set_relationship_helpers.rb +189 -0
- data/lib/reactive_record/active_record/reactive_record/scoped_collection.rb +62 -0
- data/lib/reactive_record/active_record/reactive_record/unscoped_collection.rb +16 -0
- data/lib/reactive_record/active_record/reactive_record/while_loading.rb +299 -0
- data/lib/reactive_record/engine.rb +13 -0
- data/lib/reactive_record/interval.rb +190 -0
- data/lib/reactive_record/permissions.rb +102 -0
- data/lib/reactive_record/pry.rb +13 -0
- data/lib/reactive_record/reactive_scope.rb +18 -0
- data/lib/reactive_record/scope_description.rb +108 -0
- data/lib/reactive_record/serializers.rb +7 -0
- data/lib/reactive_record/server_data_cache.rb +347 -0
- data/lib/reactive_record/version.rb +3 -0
- data/lib/sources/hyper-mesh/pusher.js +98 -0
- data/lib/synchromesh/action_cable.rb +39 -0
- data/lib/synchromesh/client_drivers.rb +357 -0
- data/lib/synchromesh/configuration.rb +40 -0
- data/lib/synchromesh/connection.rb +144 -0
- data/lib/synchromesh/policy.rb +504 -0
- data/lib/synchromesh/reactive_record/permission_patches.rb +43 -0
- data/lib/synchromesh/synchromesh.rb +155 -0
- data/lib/synchromesh/synchromesh_controller.rb +154 -0
- data/logo.jpg +0 -0
- data/path_release_steps.md +0 -0
- data/reactive_record_test_app/Gemfile +15 -0
- data/reactive_record_test_app/Gemfile.lock +209 -0
- data/reactive_record_test_app/README.rdoc +261 -0
- data/reactive_record_test_app/Rakefile +7 -0
- data/reactive_record_test_app/app/assets/javascripts/application.rb +5 -0
- data/reactive_record_test_app/app/assets/javascripts/components/another_component.rb +24 -0
- data/reactive_record_test_app/app/assets/javascripts/components/empty_component.rb +6 -0
- data/reactive_record_test_app/app/assets/javascripts/components/todo_item_component.js.rb +16 -0
- data/reactive_record_test_app/app/assets/javascripts/components/todos_component.js.rb +42 -0
- data/reactive_record_test_app/app/assets/javascripts/components/todos_main_component.rb +49 -0
- data/reactive_record_test_app/app/assets/javascripts/react_js_test_only.js +21618 -0
- data/reactive_record_test_app/app/assets/javascripts/reactive_record_config.js +2 -0
- data/reactive_record_test_app/app/assets/javascripts/spec/reactive_record_xspec.js.rb +42 -0
- data/reactive_record_test_app/app/assets/stylesheets/application.css +13 -0
- data/reactive_record_test_app/app/controllers/application_controller.rb +8 -0
- data/reactive_record_test_app/app/controllers/home_controller.rb +7 -0
- data/reactive_record_test_app/app/controllers/test_controller.rb +7 -0
- data/reactive_record_test_app/app/helpers/application_helper.rb +2 -0
- data/reactive_record_test_app/app/mailers/.gitkeep +0 -0
- data/reactive_record_test_app/app/models/.gitkeep +0 -0
- data/reactive_record_test_app/app/policies/application_policy.rb +5 -0
- data/reactive_record_test_app/app/views/components.rb +4 -0
- data/reactive_record_test_app/app/views/components/test.rb +18 -0
- data/reactive_record_test_app/app/views/home/index.html.erb +1 -0
- data/reactive_record_test_app/app/views/layouts/application.html.erb +17 -0
- data/reactive_record_test_app/app/views/models.rb +1 -0
- data/reactive_record_test_app/app/views/models/address.rb +13 -0
- data/reactive_record_test_app/app/views/models/comment.rb +19 -0
- data/reactive_record_test_app/app/views/models/todo_item.rb +36 -0
- data/reactive_record_test_app/app/views/models/user.rb +78 -0
- data/reactive_record_test_app/config.ru +33 -0
- data/reactive_record_test_app/config/application.rb +73 -0
- data/reactive_record_test_app/config/boot.rb +10 -0
- data/reactive_record_test_app/config/database.yml +25 -0
- data/reactive_record_test_app/config/environment.rb +5 -0
- data/reactive_record_test_app/config/environments/development.rb +43 -0
- data/reactive_record_test_app/config/environments/production.rb +70 -0
- data/reactive_record_test_app/config/environments/test.rb +41 -0
- data/reactive_record_test_app/config/initializers/backtrace_silencers.rb +7 -0
- data/reactive_record_test_app/config/initializers/inflections.rb +15 -0
- data/reactive_record_test_app/config/initializers/mime_types.rb +5 -0
- data/reactive_record_test_app/config/initializers/secret_token.rb +7 -0
- data/reactive_record_test_app/config/initializers/session_store.rb +8 -0
- data/reactive_record_test_app/config/initializers/wrap_parameters.rb +14 -0
- data/reactive_record_test_app/config/locales/en.yml +5 -0
- data/reactive_record_test_app/config/routes.rb +7 -0
- data/reactive_record_test_app/db/migrate/20150617002932_create_todo_items.rb +11 -0
- data/reactive_record_test_app/db/migrate/20150617134028_create_users.rb +14 -0
- data/reactive_record_test_app/db/migrate/20150729195556_add_address_to_user.rb +20 -0
- data/reactive_record_test_app/db/migrate/20150826142045_create_comments.rb +10 -0
- data/reactive_record_test_app/db/migrate/20150828172008_add_single_comment_to_todo_item.rb +5 -0
- data/reactive_record_test_app/db/migrate/20150908184118_add_address_id_to_user.rb +5 -0
- data/reactive_record_test_app/db/migrate/20150917220236_add_second_address_to_user.rb +10 -0
- data/reactive_record_test_app/db/migrate/20151009000111_add_test_data_attributes_to_user.rb +6 -0
- data/reactive_record_test_app/db/migrate/20160129182544_add_test_enum_to_user.rb +5 -0
- data/reactive_record_test_app/db/schema.rb +63 -0
- data/reactive_record_test_app/db/seeds.rb +60 -0
- data/reactive_record_test_app/public/404.html +26 -0
- data/reactive_record_test_app/public/422.html +26 -0
- data/reactive_record_test_app/public/500.html +25 -0
- data/reactive_record_test_app/public/favicon.ico +0 -0
- data/reactive_record_test_app/script/rails +6 -0
- data/reactive_record_test_app/spec-opal/active-record/aggregations_spec.rb +41 -0
- data/reactive_record_test_app/spec-opal/active-record/associations_spec.rb +75 -0
- data/reactive_record_test_app/spec-opal/active-record/base_spec.rb +126 -0
- data/reactive_record_test_app/spec-opal/active-record/dummy_value_spec.rb +27 -0
- data/reactive_record_test_app/spec-opal/active-record/edge_cases_spec.rb +116 -0
- data/reactive_record_test_app/spec-opal/active-record/enum_spec.rb +43 -0
- data/reactive_record_test_app/spec-opal/active-record/instance_methods_spec.rb +53 -0
- data/reactive_record_test_app/spec-opal/active-record/non_ar_aggregations_spec.rb +74 -0
- data/reactive_record_test_app/spec-opal/active-record/permissions_spec.rb +170 -0
- data/reactive_record_test_app/spec-opal/active-record/prerendering_spec.rb +49 -0
- data/reactive_record_test_app/spec-opal/active-record/reactive_record_load_spec.rb +23 -0
- data/reactive_record_test_app/spec-opal/active-record/rendering_spec.rb +221 -0
- data/reactive_record_test_app/spec-opal/active-record/save_spec.rb +125 -0
- data/reactive_record_test_app/spec-opal/active-record/scope_spec.rb +85 -0
- data/reactive_record_test_app/spec-opal/active-record/update_aggregations_spec.rb +76 -0
- data/reactive_record_test_app/spec-opal/active-record/update_attributes_spec.rb +186 -0
- data/reactive_record_test_app/spec-opal/active-record/virtual_methods_spec.rb +71 -0
- data/reactive_record_test_app/spec-opal/index.html.erb +11 -0
- data/reactive_record_test_app/spec-opal/spec_helper.js.rb +268 -0
- data/reactive_record_test_app/spec-opal/vendor/es5-shim.min.js +6 -0
- data/reactive_record_test_app/spec_dont_run/README.md +26 -0
- data/reactive_record_test_app/spec_dont_run/moved_to_main_spec_dir/zzzmany_to_many_spec_moved_to_main_suite.rb +30 -0
- data/reactive_record_test_app/spec_dont_run/moved_to_main_spec_dir/zzzrevert_record_spec_moved.rb +78 -0
- data/reactive_record_test_app/spec_dont_run/moved_to_main_spec_dir/zzzupdate_associations_spec_moved.rb +142 -0
- data/reactive_record_test_app/spec_dont_run/moved_to_main_spec_dir/zzzupdate_scopes_movedspec.rb +48 -0
- data/remote.md +115 -0
- data/spec/bin/firebug-2.0.13-fx.xpi +0 -0
- data/spec/component_helpers_xspec.rb +49 -0
- data/spec/factories/child_model.rb +5 -0
- data/spec/factories/comment.rb +5 -0
- data/spec/factories/test_models.rb +5 -0
- data/spec/factories/todo.rb +5 -0
- data/spec/factories/user.rb +5 -0
- data/spec/reactive_record/edge_cases_spec.rb +31 -0
- data/spec/reactive_record/factory.rb +62 -0
- data/spec/reactive_record/many_to_many_spec.rb +50 -0
- data/spec/reactive_record/play.rb +64 -0
- data/spec/reactive_record/pry_rescue_xspec.rb +48 -0
- data/spec/reactive_record/revert_spec.rb +112 -0
- data/spec/reactive_record/update_associations_spec.rb +189 -0
- data/spec/reactive_record/update_scopes_spec.rb +53 -0
- data/spec/spec_helper.rb +366 -0
- data/spec/support/component_helpers.rb +351 -0
- data/spec/synchromesh/column_types/column_type_spec.rb +302 -0
- data/spec/synchromesh/connection_spec.rb +144 -0
- data/spec/synchromesh/crud_access_regulation/broadcast_controls_access_spec.rb +105 -0
- data/spec/synchromesh/crud_access_regulation/model_policies_spec.rb +131 -0
- data/spec/synchromesh/examples/dictionary.rb +239 -0
- data/spec/synchromesh/examples/dictionary_with_client_scopes.rb +196 -0
- data/spec/synchromesh/examples/random_examples.rb +100 -0
- data/spec/synchromesh/examples/scoped_todos_spec.rb +167 -0
- data/spec/synchromesh/integration/authorization_spec.rb +111 -0
- data/spec/synchromesh/integration/default_scope_spec.rb +121 -0
- data/spec/synchromesh/integration/has_many_through_spec.rb +173 -0
- data/spec/synchromesh/integration/relationships_spec.rb +263 -0
- data/spec/synchromesh/integration/scope_spec.rb +553 -0
- data/spec/synchromesh/integration/synchromesh_spec.rb +80 -0
- data/spec/synchromesh/integration/test_components.rb +18 -0
- data/spec/synchromesh/integration/transports_spec.rb +308 -0
- data/spec/synchromesh/policies/auto_connect_spec.rb +60 -0
- data/spec/synchromesh/policies/auto_loader_spec.rb +34 -0
- data/spec/synchromesh/policies/policy_methods_spec.rb +85 -0
- data/spec/synchromesh/policies/regulate_all_broadcasts_spec.rb +315 -0
- data/spec/synchromesh/policies/regulate_broadcast_spec.rb +370 -0
- data/spec/synchromesh/policies/regulate_class_connection_spec.rb +50 -0
- data/spec/synchromesh/policies/regulate_instance_connection_spec.rb +66 -0
- data/spec/test_app/Gemfile +61 -0
- data/spec/test_app/Gemfile.lock +253 -0
- data/spec/test_app/Rakefile +6 -0
- data/spec/test_app/app/assets/javascripts/application.js +6 -0
- data/spec/test_app/app/assets/stylesheets/application.css +15 -0
- data/spec/test_app/app/controllers/application_controller.rb +13 -0
- data/spec/test_app/app/controllers/test_controller.rb +5 -0
- data/spec/test_app/app/models/_react_public_models.rb +2 -0
- data/spec/test_app/app/models/public/address.rb +13 -0
- data/spec/test_app/app/models/public/child_model.rb +3 -0
- data/spec/test_app/app/models/public/comment.rb +25 -0
- data/spec/test_app/app/models/public/test_model.rb +5 -0
- data/spec/test_app/app/models/public/todo.rb +6 -0
- data/spec/test_app/app/models/public/todo_item.rb +36 -0
- data/spec/test_app/app/models/public/user.rb +88 -0
- data/spec/test_app/app/policies/auto_loader_test_classa_policy.rb +3 -0
- data/spec/test_app/app/policies/auto_loader_test_classb_policy.rb +3 -0
- data/spec/test_app/app/policies/auto_loader_test_classc_policy.rb +3 -0
- data/spec/test_app/app/policies/auto_loader_test_classd_policy.rb +3 -0
- data/spec/test_app/app/views/components.rb +14 -0
- data/spec/test_app/app/views/components/show.rb +5 -0
- data/spec/test_app/app/views/layouts/application.html.erb +14 -0
- data/spec/test_app/bin/bundle +3 -0
- data/spec/test_app/bin/rails +4 -0
- data/spec/test_app/bin/rake +4 -0
- data/spec/test_app/bin/setup +29 -0
- data/spec/test_app/config.ru +4 -0
- data/spec/test_app/config/application.rb +42 -0
- data/spec/test_app/config/boot.rb +6 -0
- data/spec/test_app/config/cable.yml +10 -0
- data/spec/test_app/config/database.yml +47 -0
- data/spec/test_app/config/environment.rb +5 -0
- data/spec/test_app/config/environments/development.rb +41 -0
- data/spec/test_app/config/environments/production.rb +79 -0
- data/spec/test_app/config/environments/test.rb +42 -0
- data/spec/test_app/config/initializers/assets.rb +11 -0
- data/spec/test_app/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/test_app/config/initializers/cookies_serializer.rb +3 -0
- data/spec/test_app/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/test_app/config/initializers/inflections.rb +16 -0
- data/spec/test_app/config/initializers/mime_types.rb +4 -0
- data/spec/test_app/config/initializers/session_store.rb +3 -0
- data/spec/test_app/config/initializers/synchromesh.rb +11 -0
- data/spec/test_app/config/initializers/wrap_parameters.rb +14 -0
- data/spec/test_app/config/locales/en.yml +23 -0
- data/spec/test_app/config/routes.rb +61 -0
- data/spec/test_app/config/secrets.yml +22 -0
- data/spec/test_app/db/development.sqlite3 +0 -0
- data/spec/test_app/db/migrate/20160731182106_create_test_models.rb +75 -0
- data/spec/test_app/db/schema.rb +88 -0
- data/spec/test_app/db/seeds.rb +7 -0
- data/spec/test_app/lib/assets/.keep +0 -0
- data/spec/test_app/log/.keep +0 -0
- data/spec/test_app/public/404.html +67 -0
- data/spec/test_app/public/422.html +67 -0
- data/spec/test_app/public/500.html +66 -0
- data/spec/test_app/public/favicon.ico +0 -0
- data/spec/vendor/es5-shim.min.js +6 -0
- data/terminal.md +66 -0
- metadata +1175 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'synchromesh/integration/test_components'
|
|
3
|
+
require 'rspec-steps'
|
|
4
|
+
|
|
5
|
+
RSpec::Steps.steps "has_many through relationships", js: true do
|
|
6
|
+
|
|
7
|
+
before(:each) do
|
|
8
|
+
require 'pusher'
|
|
9
|
+
require 'pusher-fake'
|
|
10
|
+
Pusher.app_id = "MY_TEST_ID"
|
|
11
|
+
Pusher.key = "MY_TEST_KEY"
|
|
12
|
+
Pusher.secret = "MY_TEST_SECRET"
|
|
13
|
+
require "pusher-fake/support/base"
|
|
14
|
+
|
|
15
|
+
HyperMesh.configuration do |config|
|
|
16
|
+
config.transport = :pusher
|
|
17
|
+
config.channel_prefix = "synchromesh"
|
|
18
|
+
config.opts = {app_id: Pusher.app_id, key: Pusher.key, secret: Pusher.secret}.merge(PusherFake.configuration.web_options)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class Physician < ActiveRecord::Base
|
|
22
|
+
def self.build_tables
|
|
23
|
+
connection.create_table :physicians, force: true do |t|
|
|
24
|
+
t.string :name
|
|
25
|
+
t.timestamps
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
class Patient < ActiveRecord::Base
|
|
31
|
+
def self.build_tables
|
|
32
|
+
connection.create_table :patients, force: true do |t|
|
|
33
|
+
t.string :name
|
|
34
|
+
t.timestamps
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
class Appointment < ActiveRecord::Base
|
|
40
|
+
def self.build_tables
|
|
41
|
+
connection.create_table :appointments, force: true do |t|
|
|
42
|
+
t.belongs_to :physician, index: true
|
|
43
|
+
t.belongs_to :patient, index: true
|
|
44
|
+
t.datetime :appointment_date
|
|
45
|
+
t.timestamps
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
isomorphic do
|
|
51
|
+
class Physician < ActiveRecord::Base
|
|
52
|
+
has_many :appointments
|
|
53
|
+
has_many :patients, through: :appointments
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
class Appointment < ActiveRecord::Base
|
|
57
|
+
belongs_to :physician
|
|
58
|
+
belongs_to :patient
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
class Patient < ActiveRecord::Base
|
|
62
|
+
has_many :appointments
|
|
63
|
+
has_many :physicians, through: :appointments
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
Physician.build_tables rescue nil
|
|
68
|
+
Appointment.build_tables rescue nil
|
|
69
|
+
Patient.build_tables rescue nil
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
before(:step) do
|
|
73
|
+
|
|
74
|
+
stub_const 'ApplicationPolicy', Class.new
|
|
75
|
+
ApplicationPolicy.class_eval do
|
|
76
|
+
always_allow_connection
|
|
77
|
+
regulate_all_broadcasts { |policy| policy.send_all }
|
|
78
|
+
allow_change(to: :all, on: [:create, :update, :destroy]) { true }
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
size_window(:small, :portrait)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it "will load has_many :through relationships" do
|
|
85
|
+
mount "PhysicianSchedule" do
|
|
86
|
+
class PhysicianSchedule < React::Component::Base
|
|
87
|
+
render(DIV) do
|
|
88
|
+
Physician.all.each do |doc|
|
|
89
|
+
DIV do
|
|
90
|
+
if doc.appointments.any?
|
|
91
|
+
"Dr. #{doc.name} has a total of #{doc.appointments.count} appointments with: #{doc.patients.pluck(:name).join(", ")}"
|
|
92
|
+
else
|
|
93
|
+
"Dr. #{doc.name} has no appointments."
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
Patient.all.each do |patient|
|
|
98
|
+
DIV do
|
|
99
|
+
if patient.physicians.any?
|
|
100
|
+
"#{patient.name} - Doctors: #{patient.physicians.pluck(:name).join(', ')}"
|
|
101
|
+
else
|
|
102
|
+
"#{patient.name} is not seeing any doctors"
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
@ds = Physician.create(name: "Stop")
|
|
110
|
+
@df = Physician.create(name: "Faith")
|
|
111
|
+
@dq = Physician.create(name: "Quack")
|
|
112
|
+
@pc = Patient.create(name: "H. Chrondriac")
|
|
113
|
+
@pl = Patient.create(name: "B. Legg")
|
|
114
|
+
@ph = Patient.create(name: "N. Help")
|
|
115
|
+
@a1 = Appointment.create(appointment_date: Time.now+1.day, physician: @ds, patient: @pc)
|
|
116
|
+
page.should have_content("Dr. Stop has a total of 1 appointments with: H. Chrondriac")
|
|
117
|
+
page.should have_content("Dr. Faith has no appointments.")
|
|
118
|
+
page.should have_content("Dr. Quack has no appointments.")
|
|
119
|
+
page.should have_content("H. Chrondriac - Doctors: Stop")
|
|
120
|
+
page.should have_content("B. Legg is not seeing any doctors")
|
|
121
|
+
page.should have_content("N. Help is not seeing any doctors")
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
it "can add to existing relationships on the client" do
|
|
125
|
+
evaluate_ruby do
|
|
126
|
+
Appointment.create(
|
|
127
|
+
appointment_date: Time.now+1.day,
|
|
128
|
+
physician: Physician.find_by_name('Stop'),
|
|
129
|
+
patient: Patient.find_by_name('B. Legg')
|
|
130
|
+
)
|
|
131
|
+
end
|
|
132
|
+
page.should have_content("Dr. Stop has a total of 2 appointments with: H. Chrondriac, B. Legg")
|
|
133
|
+
page.should have_content("Dr. Faith has no appointments.")
|
|
134
|
+
page.should have_content("Dr. Quack has no appointments.")
|
|
135
|
+
page.should have_content("H. Chrondriac - Doctors: Stop")
|
|
136
|
+
page.should have_content("B. Legg - Doctors: Stop")
|
|
137
|
+
page.should have_content("N. Help is not seeing any doctors")
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
it "can add to existing relationships from the server" do
|
|
141
|
+
@a2 = Appointment.create(appointment_date: Time.now+1.day, physician: @df, patient: @pc)
|
|
142
|
+
page.should have_content("Dr. Stop has a total of 2 appointments with: H. Chrondriac, B. Legg")
|
|
143
|
+
page.should have_content("Dr. Faith has a total of 1 appointments with: H. Chrondriac")
|
|
144
|
+
page.should have_content("Dr. Quack has no appointments.")
|
|
145
|
+
page.should have_content("H. Chrondriac - Doctors: Stop, Faith")
|
|
146
|
+
page.should have_content("B. Legg - Doctors: Stop")
|
|
147
|
+
page.should have_content("N. Help is not seeing any doctors")
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
it "can update an existing relationship from the server" do
|
|
151
|
+
@a2.update(physician: @dq)
|
|
152
|
+
page.should have_content("Dr. Stop has a total of 2 appointments with: H. Chrondriac, B. Legg")
|
|
153
|
+
page.should have_content("Dr. Faith has no appointments.")
|
|
154
|
+
page.should have_content("Dr. Quack has a total of 1 appointments with: H. Chrondriac")
|
|
155
|
+
page.should have_content("H. Chrondriac - Doctors: Stop, Quack")
|
|
156
|
+
page.should have_content("B. Legg - Doctors: Stop")
|
|
157
|
+
page.should have_content("N. Help is not seeing any doctors")
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
it "can destroy an existing relationship from the server" do
|
|
161
|
+
evaluate_ruby do
|
|
162
|
+
PhysicianSchedule.hypertrace instrument: :all
|
|
163
|
+
ReactiveRecord::Base.hypertrace instrument: :all
|
|
164
|
+
end
|
|
165
|
+
@a1.destroy
|
|
166
|
+
page.should have_content("Dr. Stop has a total of 1 appointments with: B. Legg")
|
|
167
|
+
page.should have_content("Dr. Faith has no appointments.")
|
|
168
|
+
page.should have_content("Dr. Quack has a total of 1 appointments with: H. Chrondriac")
|
|
169
|
+
page.should have_content("H. Chrondriac - Doctors: Quack")
|
|
170
|
+
page.should have_content("B. Legg - Doctors: Stop")
|
|
171
|
+
page.should have_content("N. Help is not seeing any doctors")
|
|
172
|
+
end
|
|
173
|
+
end
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'synchromesh/integration/test_components'
|
|
3
|
+
|
|
4
|
+
describe "synchronizing relationships", js: true do
|
|
5
|
+
|
|
6
|
+
before(:all) do
|
|
7
|
+
require 'pusher'
|
|
8
|
+
require 'pusher-fake'
|
|
9
|
+
Pusher.app_id = "MY_TEST_ID"
|
|
10
|
+
Pusher.key = "MY_TEST_KEY"
|
|
11
|
+
Pusher.secret = "MY_TEST_SECRET"
|
|
12
|
+
require "pusher-fake/support/base"
|
|
13
|
+
|
|
14
|
+
HyperMesh.configuration do |config|
|
|
15
|
+
config.transport = :pusher
|
|
16
|
+
config.channel_prefix = "synchromesh"
|
|
17
|
+
config.opts = {app_id: Pusher.app_id, key: Pusher.key, secret: Pusher.secret}.merge(PusherFake.configuration.web_options)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
before(:each) do
|
|
22
|
+
# spec_helper resets the policy system after each test so we have to setup
|
|
23
|
+
# before each test
|
|
24
|
+
stub_const 'TestApplication', Class.new
|
|
25
|
+
stub_const 'TestApplicationPolicy', Class.new
|
|
26
|
+
TestApplicationPolicy.class_eval do
|
|
27
|
+
always_allow_connection
|
|
28
|
+
regulate_all_broadcasts { |policy| policy.send_all }
|
|
29
|
+
allow_change(to: :all, on: [:create, :update, :destroy]) { true }
|
|
30
|
+
end
|
|
31
|
+
size_window(:small, :portrait)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "belongs_to with count" do
|
|
35
|
+
parent = FactoryGirl.create(:test_model)
|
|
36
|
+
mount "TestComponent2", model: parent do
|
|
37
|
+
class TestComponent2 < React::Component::Base
|
|
38
|
+
param :model, type: TestModel
|
|
39
|
+
render(:div) do
|
|
40
|
+
puts "RENDERING! #{params.model.child_models.count} items"
|
|
41
|
+
div { "#{params.model.child_models.count} items" }
|
|
42
|
+
#ul { model.child_models.each { |model| li { model.child_attribute }}}
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
page.should have_content("0 items")
|
|
48
|
+
FactoryGirl.create(:child_model, test_model: parent, child_attribute: "first child")
|
|
49
|
+
page.should have_content("1 items")
|
|
50
|
+
parent.child_models << FactoryGirl.create(:child_model, child_attribute: "second child")
|
|
51
|
+
page.should have_content("2 items")
|
|
52
|
+
parent.child_models.first.destroy
|
|
53
|
+
page.should have_content("1 items")
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it "belongs_to without the associated record" do
|
|
57
|
+
parent = FactoryGirl.create(:test_model)
|
|
58
|
+
mount "TestComponent2" do
|
|
59
|
+
class TestComponent2 < React::Component::Base
|
|
60
|
+
render(:div) do
|
|
61
|
+
div { "#{ChildModel.count} items" }
|
|
62
|
+
ul { ChildModel.each { |model| li { model.child_attribute }}}
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
page.should have_content("0 items")
|
|
67
|
+
FactoryGirl.create(:child_model, test_model: parent, child_attribute: "first child")
|
|
68
|
+
page.should have_content("1 items")
|
|
69
|
+
parent.child_models << FactoryGirl.create(:child_model, child_attribute: "second child")
|
|
70
|
+
page.should have_content("2 items")
|
|
71
|
+
parent.child_models.first.destroy
|
|
72
|
+
page.should have_content("1 items")
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it "adding child to a new model on client" do
|
|
76
|
+
mount "TestComponent2" do
|
|
77
|
+
class TestComponent2 < React::Component::Base
|
|
78
|
+
define_state :foo
|
|
79
|
+
before_mount do
|
|
80
|
+
@parent = TestModel.new
|
|
81
|
+
@child = ChildModel.new
|
|
82
|
+
end
|
|
83
|
+
after_mount do
|
|
84
|
+
after(0) do # simulate external event updating system
|
|
85
|
+
@parent.child_models << @child
|
|
86
|
+
@parent.save
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
render(:div) do
|
|
90
|
+
"parent has #{@parent.child_models.count} children"
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
page.should have_content("parent has 1 children", wait: 1)
|
|
95
|
+
expect(TestModel.first.child_models.count).to eq(1)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it "adding child to a new model on client after render" do
|
|
99
|
+
# HyperMesh.configuration do |config|
|
|
100
|
+
# #config.transport = :none
|
|
101
|
+
# end
|
|
102
|
+
m = FactoryGirl.create(:test_model)
|
|
103
|
+
m.child_models << FactoryGirl.create(:child_model)
|
|
104
|
+
mount "TestComponent2" do
|
|
105
|
+
class TestComponent2 < React::Component::Base
|
|
106
|
+
def self.parent
|
|
107
|
+
@parent ||= TestModel.find(1)
|
|
108
|
+
end
|
|
109
|
+
def self.add_child
|
|
110
|
+
parent.child_models << ChildModel.new
|
|
111
|
+
parent.save
|
|
112
|
+
end
|
|
113
|
+
render(:div) do
|
|
114
|
+
"parent has #{TestComponent2.parent.child_models.count} children".tap { |s| puts s}
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
wait_for_ajax
|
|
119
|
+
expect(TestModel.first.child_models.count).to eq(1)
|
|
120
|
+
m.child_models << FactoryGirl.create(:child_model)
|
|
121
|
+
evaluate_ruby("TestComponent2.add_child")
|
|
122
|
+
page.should have_content("parent has 3 children")
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
it "will re-render the count after an item is added or removed from a model" do
|
|
126
|
+
m1 = FactoryGirl.create(:test_model)
|
|
127
|
+
mount "TestComponent2" do
|
|
128
|
+
class TestComponent2 < React::Component::Base
|
|
129
|
+
render(:div) do
|
|
130
|
+
"Count of TestModel: #{TestModel.count}".span
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
page.should have_content("Count of TestModel: 1")
|
|
135
|
+
m2 = FactoryGirl.create(:test_model)
|
|
136
|
+
page.should have_content("Count of TestModel: 2")
|
|
137
|
+
m1.destroy
|
|
138
|
+
page.should have_content("Count of TestModel: 1")
|
|
139
|
+
m2.destroy
|
|
140
|
+
page.should have_content("Count of TestModel: 0")
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
it "will re-render the model's all scope after an item is added or removed" do
|
|
144
|
+
m1 = FactoryGirl.create(:test_model)
|
|
145
|
+
mount "TestComponent2" do
|
|
146
|
+
class TestComponent2 < React::Component::Base
|
|
147
|
+
render(:div) do
|
|
148
|
+
puts "Count of TestModel: #{TestModel.collect { |i| i.id}.length}"
|
|
149
|
+
"Count of TestModel: #{TestModel.collect { |i| i.id}.length}".span
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
page.should have_content("Count of TestModel: 1")
|
|
154
|
+
m2 = FactoryGirl.create(:test_model)
|
|
155
|
+
page.should have_content("Count of TestModel: 2")
|
|
156
|
+
m1.destroy
|
|
157
|
+
page.should have_content("Count of TestModel: 1")
|
|
158
|
+
m2.destroy
|
|
159
|
+
page.should have_content("Count of TestModel: 0")
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
context "updating a client scoped method when applied to a collection" do
|
|
163
|
+
|
|
164
|
+
before(:each) do
|
|
165
|
+
|
|
166
|
+
isomorphic do
|
|
167
|
+
ChildModel.class_eval do
|
|
168
|
+
scope :boo_ha, -> { all }, client: -> { true }
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
m = FactoryGirl.create(:test_model, test_attribute: 'hello')
|
|
173
|
+
FactoryGirl.create(:child_model, test_model: m)
|
|
174
|
+
|
|
175
|
+
mount "TestComponent3" do
|
|
176
|
+
class TestComponent3 < React::Component::Base
|
|
177
|
+
render(OL) do
|
|
178
|
+
TestModel.all[0].child_models.boo_ha.each do |child|
|
|
179
|
+
LI { "child id = #{child.id} "}
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
page.should have_content('child id = 1')
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
it "will update when sent from the server" do
|
|
188
|
+
ChildModel.create(child_attribute: :foo, test_model: TestModel.find(1))
|
|
189
|
+
page.should have_content('child id = 2')
|
|
190
|
+
ChildModel.find(1).destroy
|
|
191
|
+
sleep 0.1 # necessary for poltergeist to work with pusher faker
|
|
192
|
+
page.should_not have_content('child id = 1', wait: 2)
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
it "will update when sent from the client" do
|
|
196
|
+
evaluate_ruby do
|
|
197
|
+
# ReactiveRecord::Collection.hypertrace instrument: :all
|
|
198
|
+
# ReactiveRecord::Collection.hypertrace :class, instrument: :all
|
|
199
|
+
# ReactiveRecord::Base.hypertrace instrument: :sync_unscoped_collection!
|
|
200
|
+
# ReactiveRecord::ScopeDescription.hypertrace instrument: :all
|
|
201
|
+
|
|
202
|
+
ChildModel.create(child_attribute: :foo, test_model: TestModel.find(1))
|
|
203
|
+
end
|
|
204
|
+
page.should have_content('child id = 2')
|
|
205
|
+
evaluate_ruby do
|
|
206
|
+
ChildModel.find(1).destroy
|
|
207
|
+
end
|
|
208
|
+
sleep 0.1 # necessary for poltergeist to work with pusher faker
|
|
209
|
+
page.should_not have_content('child id = 1', wait: 2)
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
context "updating a has_many relationship" do
|
|
215
|
+
|
|
216
|
+
before(:each) do
|
|
217
|
+
|
|
218
|
+
m = FactoryGirl.create(:test_model, test_attribute: 'hello')
|
|
219
|
+
FactoryGirl.create(:child_model, test_model: m)
|
|
220
|
+
|
|
221
|
+
mount "TestComponent3" do
|
|
222
|
+
class TestComponent3 < React::Component::Base
|
|
223
|
+
render(OL) do
|
|
224
|
+
TestModel.all[0].child_models.each do |child|
|
|
225
|
+
LI { "child id = #{child.id} "}
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
page.should have_content('child id = 1')
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
it "will update when sent from the server" do
|
|
234
|
+
ChildModel.create(child_attribute: :foo, test_model: TestModel.find(1))
|
|
235
|
+
page.should have_content('child id = 2')
|
|
236
|
+
ChildModel.find(1).destroy
|
|
237
|
+
sleep 0.1 # necessary for poltergeist to work with pusher faker
|
|
238
|
+
page.should_not have_content('child id = 1', wait: 2)
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
it "will update when sent from the client" do
|
|
242
|
+
|
|
243
|
+
evaluate_ruby do
|
|
244
|
+
ChildModel.create(child_attribute: :foo, test_model: TestModel.find(1))
|
|
245
|
+
end
|
|
246
|
+
page.should have_content('child id = 2')
|
|
247
|
+
evaluate_ruby do
|
|
248
|
+
# ReactiveRecord::Collection.hypertrace instrument: :all
|
|
249
|
+
# ReactiveRecord::Collection.hypertrace :class, instrument: :all
|
|
250
|
+
# ReactiveRecord::Base.hypertrace instrument: :sync_unscoped_collection!
|
|
251
|
+
# ReactiveRecord::ScopeDescription.hypertrace instrument: :all
|
|
252
|
+
|
|
253
|
+
ChildModel.find(1).destroy
|
|
254
|
+
end
|
|
255
|
+
sleep 0.1 # necessary for poltergeist to work with pusher faker
|
|
256
|
+
page.should_not have_content('child id = 1', wait: 2)
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
it "composed_of"
|
|
262
|
+
|
|
263
|
+
end
|
|
@@ -0,0 +1,553 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'synchromesh/integration/test_components'
|
|
3
|
+
|
|
4
|
+
describe "synchronized scopes", js: true do
|
|
5
|
+
|
|
6
|
+
before(:all) do
|
|
7
|
+
require 'pusher'
|
|
8
|
+
require 'pusher-fake'
|
|
9
|
+
Pusher.app_id = "MY_TEST_ID"
|
|
10
|
+
Pusher.key = "MY_TEST_KEY"
|
|
11
|
+
Pusher.secret = "MY_TEST_SECRET"
|
|
12
|
+
require "pusher-fake/support/base"
|
|
13
|
+
|
|
14
|
+
HyperMesh.configuration do |config|
|
|
15
|
+
config.transport = :pusher
|
|
16
|
+
config.channel_prefix = "synchromesh"
|
|
17
|
+
config.opts = {app_id: Pusher.app_id, key: Pusher.key, secret: Pusher.secret}.merge(PusherFake.configuration.web_options)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
before(:all) do
|
|
22
|
+
TestModel.class_eval do
|
|
23
|
+
class << self
|
|
24
|
+
alias pretest_scope scope
|
|
25
|
+
def scope(name, *args, &block)
|
|
26
|
+
opts = _synchromesh_scope_args_check(args)
|
|
27
|
+
self.class.class_eval do
|
|
28
|
+
attr_reader "#{name}_count".to_sym
|
|
29
|
+
end
|
|
30
|
+
instance_variable_set("@#{name}_count", 0)
|
|
31
|
+
original_proc = opts[:server]
|
|
32
|
+
opts[:server] = lambda do |*args|
|
|
33
|
+
instance_variable_set("@#{name}_count", send("#{name}_count")+1); original_proc.call(*args, &block)
|
|
34
|
+
end
|
|
35
|
+
pretest_scope name, opts, &block
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
before(:each) do
|
|
42
|
+
# spec_helper resets the policy system after each test so we have to setup
|
|
43
|
+
# before each test
|
|
44
|
+
stub_const 'TestApplicationPolicy', Class.new
|
|
45
|
+
TestApplicationPolicy.class_eval do
|
|
46
|
+
always_allow_connection
|
|
47
|
+
regulate_all_broadcasts { |policy| policy.send_all }
|
|
48
|
+
end
|
|
49
|
+
size_window(:small, :portrait)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "can use the all scope" do
|
|
53
|
+
mount "TestComponent2" do
|
|
54
|
+
class TestComponent2 < React::Component::Base
|
|
55
|
+
render do
|
|
56
|
+
"count = #{TestModel.all.count}"
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
page.should have_content("count = 0")
|
|
61
|
+
m = FactoryGirl.create(:test_model)
|
|
62
|
+
page.should have_content("count = 1")
|
|
63
|
+
m.destroy
|
|
64
|
+
page.should have_content("count = 0")
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "will be updated only when needed" do
|
|
68
|
+
isomorphic do
|
|
69
|
+
TestModel.class_eval do
|
|
70
|
+
scope :scope1, -> { where(completed: true) }
|
|
71
|
+
scope :scope2, -> { where(completed: true) }
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
mount "TestComponent2" do
|
|
75
|
+
class TestComponent2 < React::Component::Base
|
|
76
|
+
before_mount do
|
|
77
|
+
@render_count = 1
|
|
78
|
+
end
|
|
79
|
+
before_update do
|
|
80
|
+
@render_count = @render_count + 1
|
|
81
|
+
end
|
|
82
|
+
render(:div) do
|
|
83
|
+
div { "rendered #{@render_count} times"}
|
|
84
|
+
div { "scope1 count = #{TestModel.scope1.count}" }
|
|
85
|
+
div { "scope2 count = #{TestModel.scope2.count}"} if TestModel.scope1.count < 2
|
|
86
|
+
TestModel.scope1.each do |model|
|
|
87
|
+
div { model.test_attribute }
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
page.should have_content('rendered 2 times')
|
|
93
|
+
page.should have_content('scope1 count = 0')
|
|
94
|
+
page.should have_content('scope2 count = 0')
|
|
95
|
+
TestModel.scope1_count.should eq(2) # once for scope1.count and once for scope1.each { .test_attribute }
|
|
96
|
+
TestModel.scope2_count.should eq(1)
|
|
97
|
+
m1 = FactoryGirl.create(:test_model, test_attribute: "model 1", completed: true)
|
|
98
|
+
page.should have_content('rendered 3 times')
|
|
99
|
+
page.should have_content('scope1 count = 1')
|
|
100
|
+
page.should have_content('scope2 count = 1')
|
|
101
|
+
page.should have_content('model 1')
|
|
102
|
+
TestModel.scope1_count.should eq(3)
|
|
103
|
+
TestModel.scope2_count.should eq(2)
|
|
104
|
+
m2 = FactoryGirl.create(:test_model, test_attribute: "model 2", completed: false)
|
|
105
|
+
page.should have_content('rendered 4 times')
|
|
106
|
+
page.should have_content('scope1 count = 1')
|
|
107
|
+
page.should have_content('scope2 count = 1')
|
|
108
|
+
page.should have_content('model 1')
|
|
109
|
+
TestModel.scope1_count.should eq(4)
|
|
110
|
+
TestModel.scope2_count.should eq(3)
|
|
111
|
+
FactoryGirl.create(:test_model, test_attribute: "model 3", completed: true)
|
|
112
|
+
page.should have_content('rendered 5 times')
|
|
113
|
+
page.should have_content('scope1 count = 2')
|
|
114
|
+
page.should_not have_content('scope2', wait: 0)
|
|
115
|
+
page.should have_content('model 1')
|
|
116
|
+
page.should have_content('model 3')
|
|
117
|
+
TestModel.scope1_count.should eq(5)
|
|
118
|
+
TestModel.scope2_count.should eq(4)
|
|
119
|
+
m2.update_attribute(:completed, true)
|
|
120
|
+
page.should have_content('rendered 6 times')
|
|
121
|
+
page.should have_content('scope1 count = 3')
|
|
122
|
+
page.should have_content('model 1')
|
|
123
|
+
page.should have_content('model 2')
|
|
124
|
+
page.should have_content('model 3')
|
|
125
|
+
TestModel.scope1_count.should eq(6)
|
|
126
|
+
TestModel.scope2_count.should eq(4) # will not change because nothing is viewing it
|
|
127
|
+
m2.update_attribute(:completed, false)
|
|
128
|
+
page.should have_content('rendered 7 times')
|
|
129
|
+
TestModel.scope1_count.should eq(7)
|
|
130
|
+
m1.update_attribute(:completed, false)
|
|
131
|
+
page.should have_content('rendered 9 times')
|
|
132
|
+
page.should have_content('scope1 count = 1')
|
|
133
|
+
page.should have_content('scope2 count = 1')
|
|
134
|
+
page.should have_content('model 3')
|
|
135
|
+
TestModel.scope1_count.should eq(8)
|
|
136
|
+
TestModel.scope2_count.should eq(5)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
it "can have params" do
|
|
140
|
+
isomorphic do
|
|
141
|
+
TestModel.class_eval do
|
|
142
|
+
scope :with_args, ->(match, match2) { where(test_attribute: match) }
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
m1 = FactoryGirl.create(:test_model, test_attribute: "123")
|
|
146
|
+
mount "TestComponent2", m: m1 do
|
|
147
|
+
class TestComponent2 < React::Component::Base
|
|
148
|
+
param :m, type: TestModel
|
|
149
|
+
before_mount do
|
|
150
|
+
@render_count = 1
|
|
151
|
+
end
|
|
152
|
+
before_update do
|
|
153
|
+
@render_count = @render_count + 1
|
|
154
|
+
end
|
|
155
|
+
render(:div) do
|
|
156
|
+
div { "rendered #{@render_count} times"}
|
|
157
|
+
div { "with_args('match').count = #{TestModel.with_args(params.m.test_attribute, :foo).count}" }
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
m2 = FactoryGirl.create(:test_model)
|
|
162
|
+
page.should have_content('.count = 1')
|
|
163
|
+
m2.update_attribute(:test_attribute, m1.test_attribute)
|
|
164
|
+
page.should have_content('.count = 2')
|
|
165
|
+
m1.update_attribute(:test_attribute, '456')
|
|
166
|
+
page.should have_content('.count = 1')
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
it "scopes with params can be nested" do
|
|
170
|
+
isomorphic do
|
|
171
|
+
TestModel.class_eval do
|
|
172
|
+
scope :scope1, -> { where(completed: true) }
|
|
173
|
+
scope :with_args, -> (match) { where(test_attribute: match) }
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
mount "TestComponent2" do
|
|
177
|
+
class TestComponent2 < React::Component::Base
|
|
178
|
+
render(:div) do
|
|
179
|
+
div { "scope1.scope2.count = #{TestModel.scope1.with_args(:foo).count}" }
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
page.should have_content('scope1.scope2.count = 0')
|
|
184
|
+
FactoryGirl.create(:test_model, test_attribute: "foo", completed: true)
|
|
185
|
+
page.should have_content('scope1.scope2.count = 1')
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
context 'basic joins' do
|
|
189
|
+
|
|
190
|
+
it 'will not update a joined scope without a joins option' do
|
|
191
|
+
isomorphic do
|
|
192
|
+
TestModel.class_eval do
|
|
193
|
+
scope :joined,
|
|
194
|
+
-> { joins(:child_models).where("child_attribute = 'WHAAA'") }
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
mount 'TestComponent2' do
|
|
198
|
+
class TestComponent2 < React::Component::Base
|
|
199
|
+
render { "TestModel.joined.count = #{TestModel.joined.count}" }
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
parent = FactoryGirl.create(:test_model)
|
|
203
|
+
child = FactoryGirl.create(:child_model, test_model: parent )
|
|
204
|
+
page.should have_content('.count = 0')
|
|
205
|
+
child.update_attribute(:child_attribute, 'WHAAA')
|
|
206
|
+
page.should have_content('.count = 0')
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
it 'can have a joins option' do
|
|
210
|
+
isomorphic do
|
|
211
|
+
TestModel.class_eval do
|
|
212
|
+
scope :joined,
|
|
213
|
+
-> { joins(:child_models).where("child_attribute = 'WHAAA'") },
|
|
214
|
+
joins: 'child_models'
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
mount 'TestComponent2' do
|
|
218
|
+
class TestComponent2 < React::Component::Base
|
|
219
|
+
render { "TestModel.joined.count = #{TestModel.joined.count}" }
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
parent = FactoryGirl.create(:test_model)
|
|
223
|
+
child = FactoryGirl.create(:child_model, test_model: parent )
|
|
224
|
+
page.should have_content('.count = 0')
|
|
225
|
+
child.update_attribute(:child_attribute, 'WHAAA')
|
|
226
|
+
page.should have_content('.count = 1')
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
it 'can have a client filter method' do
|
|
231
|
+
|
|
232
|
+
isomorphic do
|
|
233
|
+
TestModel.class_eval do
|
|
234
|
+
scope :quicker, -> { where(completed: true) }, client: -> { completed }
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
mount 'TestComponent2' do
|
|
239
|
+
class TestComponent2 < React::Component::Base
|
|
240
|
+
before_mount do
|
|
241
|
+
@render_count = 1
|
|
242
|
+
end
|
|
243
|
+
before_update do
|
|
244
|
+
@render_count = @render_count + 1
|
|
245
|
+
end
|
|
246
|
+
render(:div) do
|
|
247
|
+
div { "rendered #{@render_count} times"}
|
|
248
|
+
div { "quicker.count = #{TestModel.quicker.count}" }
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
m1 = FactoryGirl.create(:test_model)
|
|
253
|
+
page.should have_content('.count = 0')
|
|
254
|
+
page.should have_content('rendered 2 times')
|
|
255
|
+
TestModel.quicker_count.should eq(1)
|
|
256
|
+
m1.update_attribute(:test_attribute, 'new_value')
|
|
257
|
+
wait_for_ajax
|
|
258
|
+
page.should have_content('.count = 0')
|
|
259
|
+
page.should have_content('rendered 2 times')
|
|
260
|
+
TestModel.quicker_count.should eq(1)
|
|
261
|
+
m1.update_attribute(:completed, true)
|
|
262
|
+
page.should have_content('.count = 1')
|
|
263
|
+
page.should have_content('rendered 3 times')
|
|
264
|
+
TestModel.quicker_count.should eq(1)
|
|
265
|
+
m2 = FactoryGirl.create(:test_model, completed: true)
|
|
266
|
+
page.should have_content('.count = 2')
|
|
267
|
+
page.should have_content('rendered 4 times')
|
|
268
|
+
TestModel.quicker_count.should eq(1)
|
|
269
|
+
m1.destroy
|
|
270
|
+
page.should have_content('.count = 1')
|
|
271
|
+
page.should have_content('rendered 5 times')
|
|
272
|
+
TestModel.quicker_count.should eq(1)
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
it 'can have a client collector method' do
|
|
276
|
+
|
|
277
|
+
isomorphic do
|
|
278
|
+
TestModel.class_eval do
|
|
279
|
+
def <=>(other); self.test_attribute <=> other.test_attribute; end
|
|
280
|
+
scope :filter_and_sort, -> { where(completed: true).order('test_attribute ASC') },
|
|
281
|
+
select: -> { select { |r| r.completed }.sort }
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
mount 'TestComponent2' do
|
|
286
|
+
class TestComponent2 < React::Component::Base
|
|
287
|
+
before_mount do
|
|
288
|
+
@render_count = 1
|
|
289
|
+
end
|
|
290
|
+
before_update do
|
|
291
|
+
@render_count = @render_count + 1
|
|
292
|
+
end
|
|
293
|
+
render(:div) do
|
|
294
|
+
div { "rendered #{@render_count} times"}
|
|
295
|
+
div { "filter_and_sort.count = #{TestModel.filter_and_sort.count}" }
|
|
296
|
+
if TestModel.filter_and_sort.any?
|
|
297
|
+
div { "test attributes: #{TestModel.filter_and_sort.collect { |r| r.test_attribute }.join(', ')}" }
|
|
298
|
+
else
|
|
299
|
+
div { "no test attributes" }
|
|
300
|
+
end
|
|
301
|
+
end
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
TestModel.filter_and_sort_count.should eq(2)
|
|
305
|
+
m1 = FactoryGirl.create(:test_model)
|
|
306
|
+
page.should have_content('.count = 0')
|
|
307
|
+
page.should have_content('rendered 2 times')
|
|
308
|
+
page.should have_content('no test attributes')
|
|
309
|
+
TestModel.filter_and_sort_count.should eq(2)
|
|
310
|
+
m1.update_attribute(:test_attribute, 'N')
|
|
311
|
+
wait_for_ajax
|
|
312
|
+
page.should have_content('.count = 0')
|
|
313
|
+
page.should have_content('rendered 2 times')
|
|
314
|
+
page.should have_content('no test attributes')
|
|
315
|
+
TestModel.filter_and_sort_count.should eq(2)
|
|
316
|
+
m1.update_attribute(:completed, true)
|
|
317
|
+
page.should have_content('.count = 1')
|
|
318
|
+
page.should have_content('rendered 3 times')
|
|
319
|
+
page.should have_content('test attributes: N')
|
|
320
|
+
TestModel.filter_and_sort_count.should eq(2)
|
|
321
|
+
m2 = FactoryGirl.create(:test_model, test_attribute: 'A', completed: true)
|
|
322
|
+
page.should have_content('.count = 2')
|
|
323
|
+
page.should have_content('rendered 4 times')
|
|
324
|
+
page.should have_content('test attributes: A, N')
|
|
325
|
+
TestModel.filter_and_sort_count.should eq(2)
|
|
326
|
+
m3 = FactoryGirl.create(:test_model, test_attribute: 'Z', completed: true)
|
|
327
|
+
page.should have_content('.count = 3')
|
|
328
|
+
page.should have_content('rendered 5 times')
|
|
329
|
+
page.should have_content('test attributes: A, N, Z')
|
|
330
|
+
TestModel.filter_and_sort_count.should eq(2)
|
|
331
|
+
m1.destroy
|
|
332
|
+
page.should have_content('.count = 2')
|
|
333
|
+
page.should have_content('rendered 6 times')
|
|
334
|
+
page.should have_content('test attributes: A, Z')
|
|
335
|
+
TestModel.filter_and_sort_count.should eq(2)
|
|
336
|
+
m3.update_attribute(:completed, false)
|
|
337
|
+
page.should have_content('.count = 1')
|
|
338
|
+
page.should have_content('rendered 7 times')
|
|
339
|
+
page.should have_content('test attributes: A')
|
|
340
|
+
TestModel.filter_and_sort_count.should eq(2)
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
it 'client side scoping methods can take args' do
|
|
344
|
+
|
|
345
|
+
isomorphic do
|
|
346
|
+
TestModel.class_eval do
|
|
347
|
+
def to_s
|
|
348
|
+
"<TestModel id: #{id} test_attribute: #{test_attribute}>"
|
|
349
|
+
end
|
|
350
|
+
def <=>(other)
|
|
351
|
+
(test_attribute || '') <=> (other.test_attribute || '')
|
|
352
|
+
end
|
|
353
|
+
scope :matches, -> (s) { where(['test_attribute LIKE ?', "%#{s}%"])},
|
|
354
|
+
client: -> (s) { puts "test_attribute =~ /#{s}/ is #{!!(test_attribute =~ /#{s}/)}"; test_attribute =~ /#{s}/ }
|
|
355
|
+
scope :sorted, -> (dir) { order("test_attribute #{dir==:asc ? 'ASC' : 'DESC'}") },
|
|
356
|
+
select: -> (dir) { sort { |a, b| dir == :asc ? a <=> b : b <=> a }.tap {|r| puts "sorted(#{dir==:asc}) as [#{r}]"} }
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
mount 'TestComponent2' do
|
|
361
|
+
class TestComponent2 < React::Component::Base
|
|
362
|
+
export_state pat: :foo
|
|
363
|
+
export_state dir: :asc
|
|
364
|
+
before_mount do
|
|
365
|
+
@render_count = 1
|
|
366
|
+
end
|
|
367
|
+
before_update do
|
|
368
|
+
@render_count = @render_count + 1
|
|
369
|
+
end
|
|
370
|
+
def scoped
|
|
371
|
+
puts "scoping: #{TestComponent2.pat}, #{TestComponent2.dir}"
|
|
372
|
+
TestModel.matches(TestComponent2.pat).sorted(TestComponent2.dir)
|
|
373
|
+
end
|
|
374
|
+
render(:div) do
|
|
375
|
+
div { "rendered #{@render_count} times"}
|
|
376
|
+
div { "matches(#{TestComponent2.pat}).count = #{TestModel.matches(TestComponent2.pat).count}" }
|
|
377
|
+
if scoped.any?
|
|
378
|
+
div { "test attributes: #{scoped.collect { |r| r.test_attribute[0] }.join(', ')}" }
|
|
379
|
+
else
|
|
380
|
+
div { "no test attributes" }
|
|
381
|
+
end
|
|
382
|
+
end
|
|
383
|
+
end
|
|
384
|
+
end
|
|
385
|
+
starting_fetch_time = evaluate_ruby("ReactiveRecord::Base.last_fetch_at")
|
|
386
|
+
m1 = FactoryGirl.create(:test_model)
|
|
387
|
+
page.should have_content('.count = 0')
|
|
388
|
+
page.should have_content('rendered 2 times')
|
|
389
|
+
page.should have_content('no test attributes')
|
|
390
|
+
m1.update_attribute(:test_attribute, 'N')
|
|
391
|
+
page.should have_content('rendered 2 times')
|
|
392
|
+
page.should have_content('.count = 0')
|
|
393
|
+
page.should have_content('no test attributes')
|
|
394
|
+
m1.update_attribute(:test_attribute, 'N - foobar')
|
|
395
|
+
page.should have_content('.count = 1')
|
|
396
|
+
page.should have_content('rendered 3 times')
|
|
397
|
+
page.should have_content('test attributes: N')
|
|
398
|
+
m2 = FactoryGirl.create(:test_model, test_attribute: 'A - is a foo')
|
|
399
|
+
page.should have_content('.count = 2')
|
|
400
|
+
page.should have_content('rendered 4 times')
|
|
401
|
+
page.should have_content('test attributes: A, N')
|
|
402
|
+
m3 = FactoryGirl.create(:test_model, test_attribute: 'Z - is also a foo')
|
|
403
|
+
page.should have_content('.count = 3')
|
|
404
|
+
page.should have_content('rendered 5 times')
|
|
405
|
+
page.should have_content('test attributes: A, N, Z')
|
|
406
|
+
evaluate_ruby("ReactiveRecord::Base.last_fetch_at").should eq(starting_fetch_time)
|
|
407
|
+
evaluate_ruby("TestComponent2.dir! :desc")
|
|
408
|
+
page.should have_content('test attributes: Z, N, A')
|
|
409
|
+
page.should have_content('rendered 7 times')
|
|
410
|
+
starting_fetch_time = evaluate_ruby("ReactiveRecord::Base.last_fetch_at")
|
|
411
|
+
m1.destroy
|
|
412
|
+
page.should have_content('.count = 2')
|
|
413
|
+
page.should have_content('rendered 8 times')
|
|
414
|
+
page.should have_content('test attributes: Z, A')
|
|
415
|
+
m3.update_attribute(:test_attribute, 'Z - is a bar')
|
|
416
|
+
page.should have_content('.count = 1')
|
|
417
|
+
page.should have_content('rendered 9 times')
|
|
418
|
+
page.should have_content('test attributes: A')
|
|
419
|
+
evaluate_ruby("ReactiveRecord::Base.last_fetch_at").should eq(starting_fetch_time)
|
|
420
|
+
evaluate_ruby('TestComponent2.pat! :bar')
|
|
421
|
+
page.should have_content('.count = 1')
|
|
422
|
+
page.should have_content('test attributes: Z')
|
|
423
|
+
page.should have_content('rendered 11 times')
|
|
424
|
+
starting_fetch_time = evaluate_ruby("ReactiveRecord::Base.last_fetch_at")
|
|
425
|
+
m2.update_attribute(:test_attribute, 'A is also a bar')
|
|
426
|
+
page.should have_content('.count = 2')
|
|
427
|
+
page.should have_content('rendered 12 times')
|
|
428
|
+
page.should have_content('test attributes: Z, A')
|
|
429
|
+
evaluate_ruby("ReactiveRecord::Base.last_fetch_at").should eq(starting_fetch_time)
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
it 'the joins array can be combined with the client proc' do
|
|
433
|
+
isomorphic do
|
|
434
|
+
TestModel.class_eval do
|
|
435
|
+
scope :has_children,
|
|
436
|
+
joins: 'child_models',
|
|
437
|
+
server: -> { joins(:child_models).distinct },
|
|
438
|
+
client: -> { child_models.count > 0 }
|
|
439
|
+
end
|
|
440
|
+
end
|
|
441
|
+
mount 'TestComponent2' do
|
|
442
|
+
class TestComponent2 < React::Component::Base
|
|
443
|
+
render { "TestModel.has_children.count = #{TestModel.has_children.count}" }
|
|
444
|
+
end
|
|
445
|
+
end
|
|
446
|
+
TestModel.has_children_count.should eq(1)
|
|
447
|
+
parent = FactoryGirl.create(:test_model)
|
|
448
|
+
page.should have_content('.count = 0')
|
|
449
|
+
child = FactoryGirl.create(:child_model)
|
|
450
|
+
page.should have_content('.count = 0')
|
|
451
|
+
child.update_attribute(:test_model, parent)
|
|
452
|
+
page.should have_content('.count = 1')
|
|
453
|
+
child.update_attribute(:child_attribute, 'WHAAA')
|
|
454
|
+
page.should have_content('.count = 1')
|
|
455
|
+
child.update_attribute(:test_model, nil)
|
|
456
|
+
page.should have_content('.count = 0')
|
|
457
|
+
child.update_attribute(:test_model, parent)
|
|
458
|
+
page.should have_content('.count = 1')
|
|
459
|
+
child.destroy
|
|
460
|
+
page.should have_content('.count = 0')
|
|
461
|
+
parent.destroy
|
|
462
|
+
page.should have_content('.count = 0')
|
|
463
|
+
TestModel.has_children_count.should eq(1)
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
it 'the joins option can join with all or no models' do
|
|
467
|
+
isomorphic do
|
|
468
|
+
TestModel.class_eval do
|
|
469
|
+
scope :has_children_joins_all,
|
|
470
|
+
joins: :all,
|
|
471
|
+
server: -> { joins(:child_models).distinct }
|
|
472
|
+
scope :has_children_no_joins,
|
|
473
|
+
joins: [],
|
|
474
|
+
server: -> { joins(:child_models).distinct }
|
|
475
|
+
end
|
|
476
|
+
end
|
|
477
|
+
mount 'TestComponent2' do
|
|
478
|
+
class TestComponent2 < React::Component::Base
|
|
479
|
+
render(DIV) do
|
|
480
|
+
DIV { "TestModel.has_children_joins_all.count = #{TestModel.has_children_joins_all.count}" }
|
|
481
|
+
DIV { "TestModel.has_children_no_joins.count = #{TestModel.has_children_no_joins.count}" }
|
|
482
|
+
end
|
|
483
|
+
end
|
|
484
|
+
end
|
|
485
|
+
TestModel.has_children_joins_all_count.should eq(1)
|
|
486
|
+
TestModel.has_children_no_joins_count.should eq(1)
|
|
487
|
+
parent = FactoryGirl.create(:test_model)
|
|
488
|
+
wait_for_ajax
|
|
489
|
+
TestModel.has_children_no_joins_count.should eq(1)
|
|
490
|
+
wait_for { TestModel.has_children_joins_all_count }.to eq(2)
|
|
491
|
+
child = FactoryGirl.create(:child_model)
|
|
492
|
+
wait_for { TestModel.has_children_joins_all_count }.to eq(3)
|
|
493
|
+
parent.child_models << child
|
|
494
|
+
wait_for { TestModel.has_children_joins_all_count }.to eq(4)
|
|
495
|
+
TestModel.has_children_no_joins_count.should eq(1)
|
|
496
|
+
page.should have_content('all.count = 1')
|
|
497
|
+
page.should have_content('joins.count = 0')
|
|
498
|
+
parent.update_attribute(:test_attribute, 'hello')
|
|
499
|
+
page.should have_content('joins.count = 0')
|
|
500
|
+
TestModel.has_children_no_joins_count.should eq(1)
|
|
501
|
+
end
|
|
502
|
+
|
|
503
|
+
it 'server side scopes can be procs returning arrays of elements' do
|
|
504
|
+
isomorphic do
|
|
505
|
+
TestModel.class_eval do
|
|
506
|
+
scope :rev,
|
|
507
|
+
server: -> { all.reverse }
|
|
508
|
+
end
|
|
509
|
+
end
|
|
510
|
+
mount 'TestComponent2' do
|
|
511
|
+
class TestComponent2 < React::Component::Base
|
|
512
|
+
render do
|
|
513
|
+
"test attributes: #{TestModel.rev.collect { |r| r.test_attribute }.join(', ')}"
|
|
514
|
+
end
|
|
515
|
+
end
|
|
516
|
+
end
|
|
517
|
+
FactoryGirl.create(:test_model, test_attribute: 1)
|
|
518
|
+
page.should have_content('test attributes: 1')
|
|
519
|
+
FactoryGirl.create(:test_model, test_attribute: 2)
|
|
520
|
+
page.should have_content('test attributes: 2, 1')
|
|
521
|
+
end
|
|
522
|
+
|
|
523
|
+
it 'can force reload using the ! suffix' do
|
|
524
|
+
isomorphic do
|
|
525
|
+
TestModel.class_eval do
|
|
526
|
+
scope :rev,
|
|
527
|
+
joins: [],
|
|
528
|
+
server: -> { all.reverse }
|
|
529
|
+
end
|
|
530
|
+
end
|
|
531
|
+
mount 'TestComponent2' do
|
|
532
|
+
|
|
533
|
+
class TestComponent2 < React::Component::Base
|
|
534
|
+
before_mount do
|
|
535
|
+
@reverse_collection = []
|
|
536
|
+
end
|
|
537
|
+
render do
|
|
538
|
+
if @current_count != TestModel.all.count # this forces a rerender...
|
|
539
|
+
puts "asking for reverse collection"
|
|
540
|
+
@reverse_collection = TestModel.rev!
|
|
541
|
+
@current_count = TestModel.all.count
|
|
542
|
+
end
|
|
543
|
+
puts "rendering #{@reverse_collection}"
|
|
544
|
+
"test attributes: #{@reverse_collection.collect { |r| r.test_attribute }.join(', ')}"
|
|
545
|
+
end
|
|
546
|
+
end
|
|
547
|
+
end
|
|
548
|
+
FactoryGirl.create(:test_model, test_attribute: 1)
|
|
549
|
+
page.should have_content('test attributes: 1')
|
|
550
|
+
FactoryGirl.create(:test_model, test_attribute: 2)
|
|
551
|
+
page.should have_content('test attributes: 2, 1')
|
|
552
|
+
end
|
|
553
|
+
end
|