--------------------------------------------------------------------------------
/app_screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canriquez/rails_capstone_lessons_lab/3e563c5ac1855a0a88c95fc3c79f039db2a89061/app_screenshot.png
--------------------------------------------------------------------------------
/bin/bundle:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 |
4 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
5 | load Gem.bin_path('bundler', 'bundle')
6 |
--------------------------------------------------------------------------------
/bin/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 |
4 | begin
5 | load File.expand_path('spring', __dir__)
6 | rescue LoadError => e
7 | raise unless e.message.include?('spring')
8 | end
9 | APP_PATH = File.expand_path('../config/application', __dir__)
10 | require_relative '../config/boot'
11 | require 'rails/commands'
12 |
--------------------------------------------------------------------------------
/bin/rake:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 |
4 | begin
5 | load File.expand_path('spring', __dir__)
6 | rescue LoadError => e
7 | raise unless e.message.include?('spring')
8 | end
9 | require_relative '../config/boot'
10 | require 'rake'
11 | Rake.application.run
12 |
--------------------------------------------------------------------------------
/bin/rspec:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 |
4 | begin
5 | load File.expand_path('spring', __dir__)
6 | rescue LoadError => e
7 | raise unless e.message.include?('spring')
8 | end
9 | require 'bundler/setup'
10 | load Gem.bin_path('rspec-core', 'rspec')
11 |
--------------------------------------------------------------------------------
/bin/setup:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 |
4 | require 'fileutils'
5 | include FileUtils
6 |
7 | # path to your application root.
8 | APP_ROOT = File.expand_path('..', __dir__)
9 |
10 | def system!(*args)
11 | system(*args) || abort("\n== Command #{args} failed ==")
12 | end
13 |
14 | chdir APP_ROOT do
15 | # This script is a starting point to setup your application.
16 | # Add necessary setup steps to this file.
17 |
18 | puts '== Installing dependencies =='
19 | system! 'gem install bundler --conservative'
20 | system('bundle check') || system!('bundle install')
21 |
22 | # Install JavaScript dependencies if using Yarn
23 | # system('bin/yarn')
24 |
25 | # puts "\n== Copying sample files =="
26 | # unless File.exist?('config/database.yml')
27 | # cp 'config/database.yml.sample', 'config/database.yml'
28 | # end
29 |
30 | puts "\n== Preparing database =="
31 | system! 'bin/rails db:setup'
32 |
33 | puts "\n== Removing old logs and tempfiles =="
34 | system! 'bin/rails log:clear tmp:clear'
35 |
36 | puts "\n== Restarting application server =="
37 | system! 'bin/rails restart'
38 | end
39 |
--------------------------------------------------------------------------------
/bin/spring:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 |
4 | # This file loads Spring without using Bundler, in order to be fast.
5 | # It gets overwritten when you run the `spring binstub` command.
6 |
7 | unless defined?(Spring)
8 | require 'rubygems'
9 | require 'bundler'
10 |
11 | lockfile = Bundler::LockfileParser.new(Bundler.default_lockfile.read)
12 | spring = lockfile.specs.detect { |spec| spec.name == 'spring' }
13 | if spring
14 | Gem.use_paths Gem.dir, Bundler.bundle_path.to_s, *Gem.path
15 | gem 'spring', spring.version
16 | require 'spring/binstub'
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/bin/update:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 |
4 | require 'fileutils'
5 | include FileUtils
6 |
7 | # path to your application root.
8 | APP_ROOT = File.expand_path('..', __dir__)
9 |
10 | def system!(*args)
11 | system(*args) || abort("\n== Command #{args} failed ==")
12 | end
13 |
14 | chdir APP_ROOT do
15 | # This script is a way to update your development environment automatically.
16 | # Add necessary update steps to this file.
17 |
18 | puts '== Installing dependencies =='
19 | system! 'gem install bundler --conservative'
20 | system('bundle check') || system!('bundle install')
21 |
22 | # Install JavaScript dependencies if using Yarn
23 | # system('bin/yarn')
24 |
25 | puts "\n== Updating database =="
26 | system! 'bin/rails db:migrate'
27 |
28 | puts "\n== Removing old logs and tempfiles =="
29 | system! 'bin/rails log:clear tmp:clear'
30 |
31 | puts "\n== Restarting application server =="
32 | system! 'bin/rails restart'
33 | end
34 |
--------------------------------------------------------------------------------
/bin/yarn:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 |
4 | APP_ROOT = File.expand_path('..', __dir__)
5 | Dir.chdir(APP_ROOT) do
6 | exec 'yarnpkg', *ARGV
7 | rescue Errno::ENOENT
8 | warn 'Yarn executable was not detected in the system.'
9 | warn 'Download Yarn at https://yarnpkg.com/en/docs/install'
10 | exit 1
11 | end
12 |
--------------------------------------------------------------------------------
/config.ru:
--------------------------------------------------------------------------------
1 | # This file is used by Rack-based servers to start the application.
2 |
3 | require_relative 'config/environment'
4 |
5 | run Rails.application
6 |
--------------------------------------------------------------------------------
/config/application.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require_relative 'boot'
4 |
5 | require 'rails'
6 | # Pick the frameworks you want:
7 | require 'active_model/railtie'
8 | require 'active_job/railtie'
9 | require 'active_record/railtie'
10 | require 'active_storage/engine'
11 | require 'action_controller/railtie'
12 | require 'action_mailer/railtie'
13 | require 'action_view/railtie'
14 | require 'action_cable/engine'
15 | require 'sprockets/railtie'
16 | # require "rails/test_unit/railtie"
17 |
18 | # Require the gems listed in Gemfile, including any gems
19 | # you've limited to :test, :development, or :production.
20 | Bundler.require(*Rails.groups)
21 |
22 | module RailsCapstoneLessonsLab
23 | class Application < Rails::Application
24 | # Initialize configuration defaults for originally generated Rails version.
25 | config.load_defaults 5.2
26 |
27 | # Settings in config/environments/* take precedence over those specified here.
28 | # Application configuration can go into files in config/initializers
29 | # -- all .rb files in that directory are automatically loaded after loading
30 | # the framework and any gems in your application.
31 |
32 | # Don't generate system test files.
33 | config.generators.system_tests = nil
34 |
35 | #added for custom fonts
36 | config.assets.paths << Rails.root.join("app","assets","fonts")
37 |
38 | #adding svg icons font into the assets pipeline (for Heroku)
39 | config.assets.paths << Rails.root.join('assets','images','icons')
40 |
41 | #Precompile additional assets (for heroku)
42 | config.assets.precompile += %w( .svg .eot .woff .ttf .png .jpg .gif )
43 | end
44 | end
45 |
--------------------------------------------------------------------------------
/config/boot.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
4 |
5 | require 'bundler/setup' # Set up gems listed in the Gemfile.
6 | require 'bootsnap/setup' # Speed up boot time by caching expensive operations.
7 |
--------------------------------------------------------------------------------
/config/cable.yml:
--------------------------------------------------------------------------------
1 | development:
2 | adapter: async
3 |
4 | test:
5 | adapter: async
6 |
7 | production:
8 | adapter: redis
9 | url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
10 | channel_prefix: rails_capstone_lessons_lab_production
11 |
--------------------------------------------------------------------------------
/config/credentials.yml.enc:
--------------------------------------------------------------------------------
1 | uv0ho6HFNvE8ou68cmXccA8EoN3AqBrGXuQzcHelaBO05ZQIIL3glFZOH2+MiSrciPpQMWo4p5Vp9BsWAiSnPSGGL2OW699/R2K+iqRd2V7F1vI4crXHSHaPYnVkWTTP4QcJG2SY1iLioU8mniyy/pBD1j0B48B6QQ1MozfWUgyRwhWz2almkhk/DJnj8vZiEjyj28prYfXjo3iCKKer/zTErbcmukNQeIK0lvIDVW//H8EEemldBuJVkG3CoFPoHlFlyIhnvujWtHTdDRpDcwf9TrzVopKWuDkA9LsKRmLrESBPvtG+vRA9c1mBNL7yTBhTQEBoB9I04T2cdeeMDZR+uZGVYcr7x1qh8IIZbJaWLHAbh7anAOnSXyRfKsiVQtDbPg4TPuTTaPoNEsNm9odrowwIvdJAzYUW--VKQxE85cvbYgguHV--nsyDgBthUngZTEVbjqzsww==
--------------------------------------------------------------------------------
/config/database.yml:
--------------------------------------------------------------------------------
1 | # SQLite version 3.x
2 | # gem install sqlite3
3 | #
4 | # Ensure the SQLite 3 gem is defined in your Gemfile
5 | # gem 'sqlite3'
6 | #
7 | default: &default
8 | adapter: sqlite3
9 | pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
10 | timeout: 5000
11 |
12 | development:
13 | <<: *default
14 | database: db/development.sqlite3
15 |
16 | # Warning: The database defined as "test" will be erased and
17 | # re-generated from your development database when you run "rake".
18 | # Do not set this db to the same as development or production.
19 | test:
20 | <<: *default
21 | database: db/test.sqlite3
22 |
23 | production:
24 | <<: *default
25 | database: db/production.sqlite3
26 |
--------------------------------------------------------------------------------
/config/environment.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Load the Rails application.
4 | require_relative 'application'
5 |
6 | # Initialize the Rails application.
7 | Rails.application.initialize!
8 |
--------------------------------------------------------------------------------
/config/environments/development.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | Rails.application.configure do
4 | # Settings specified here will take precedence over those in config/application.rb.
5 |
6 | # In the development environment your application's code is reloaded on
7 | # every request. This slows down response time but is perfect for development
8 | # since you don't have to restart the web server when you make code changes.
9 | config.cache_classes = false
10 |
11 | # Do not eager load code on boot.
12 | config.eager_load = false
13 |
14 | # Show full error reports.
15 | config.consider_all_requests_local = true
16 |
17 | # Enable/disable caching. By default caching is disabled.
18 | # Run rails dev:cache to toggle caching.
19 | if Rails.root.join('tmp', 'caching-dev.txt').exist?
20 | config.action_controller.perform_caching = true
21 |
22 | config.cache_store = :memory_store
23 | config.public_file_server.headers = {
24 | 'Cache-Control' => "public, max-age=#{2.days.to_i}"
25 | }
26 | else
27 | config.action_controller.perform_caching = false
28 |
29 | config.cache_store = :null_store
30 | end
31 |
32 | # Store uploaded files on the local file system (see config/storage.yml for options)
33 | config.active_storage.service = :local
34 |
35 | # Don't care if the mailer can't send.
36 | config.action_mailer.raise_delivery_errors = false
37 |
38 | config.action_mailer.perform_caching = false
39 |
40 | # Print deprecation notices to the Rails logger.
41 | config.active_support.deprecation = :log
42 |
43 | # Raise an error on page load if there are pending migrations.
44 | config.active_record.migration_error = :page_load
45 |
46 | # Highlight code that triggered database queries in logs.
47 | config.active_record.verbose_query_logs = true
48 |
49 | # Debug mode disables concatenation and preprocessing of assets.
50 | # This option may cause significant delays in view rendering with a large
51 | # number of complex assets.
52 | config.assets.debug = true
53 |
54 | # Suppress logger output for asset requests.
55 | config.assets.quiet = true
56 |
57 | # Raises error for missing translations
58 | # config.action_view.raise_on_missing_translations = true
59 |
60 | # Use an evented file watcher to asynchronously detect changes in source code,
61 | # routes, locales, etc. This feature depends on the listen gem.
62 | config.file_watcher = ActiveSupport::EventedFileUpdateChecker
63 |
64 | #Devise configuration
65 | config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
66 |
67 | end
68 |
--------------------------------------------------------------------------------
/config/environments/production.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | Rails.application.configure do
4 | # Settings specified here will take precedence over those in config/application.rb.
5 |
6 | # Code is not reloaded between requests.
7 | config.cache_classes = true
8 |
9 | # Eager load code on boot. This eager loads most of Rails and
10 | # your application in memory, allowing both threaded web servers
11 | # and those relying on copy on write to perform better.
12 | # Rake tasks automatically ignore this option for performance.
13 | config.eager_load = true
14 |
15 | # Full error reports are disabled and caching is turned on.
16 | config.consider_all_requests_local = false
17 | config.action_controller.perform_caching = true
18 |
19 | # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"]
20 | # or in config/master.key. This key is used to decrypt credentials (and other encrypted files).
21 | # config.require_master_key = true
22 |
23 | # Disable serving static files from the `/public` folder by default since
24 | # Apache or NGINX already handles this.
25 | config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
26 |
27 | # Compress JavaScripts and CSS.
28 | config.assets.js_compressor = :uglifier
29 | # config.assets.css_compressor = :sass
30 |
31 | # Do not fallback to assets pipeline if a precompiled asset is missed.
32 | config.assets.compile = false
33 |
34 | # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb
35 |
36 | # Enable serving of images, stylesheets, and JavaScripts from an asset server.
37 | # config.action_controller.asset_host = 'http://assets.example.com'
38 |
39 | # Specifies the header that your server uses for sending files.
40 | # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
41 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
42 |
43 | # Store uploaded files on the local file system (see config/storage.yml for options)
44 | config.active_storage.service = :local
45 |
46 | # Mount Action Cable outside main process or domain
47 | # config.action_cable.mount_path = nil
48 | # config.action_cable.url = 'wss://example.com/cable'
49 | # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ]
50 |
51 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
52 | # config.force_ssl = true
53 |
54 | # Use the lowest log level to ensure availability of diagnostic information
55 | # when problems arise.
56 | config.log_level = :debug
57 |
58 | # Prepend all log lines with the following tags.
59 | config.log_tags = [:request_id]
60 |
61 | # Use a different cache store in production.
62 | # config.cache_store = :mem_cache_store
63 |
64 | # Use a real queuing backend for Active Job (and separate queues per environment)
65 | # config.active_job.queue_adapter = :resque
66 | # config.active_job.queue_name_prefix = "rails_capstone_lessons_lab_#{Rails.env}"
67 |
68 | config.action_mailer.perform_caching = false
69 |
70 | # Ignore bad email addresses and do not raise email delivery errors.
71 | # Set this to true and configure the email server for immediate delivery to raise delivery errors.
72 | # config.action_mailer.raise_delivery_errors = false
73 |
74 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
75 | # the I18n.default_locale when a translation cannot be found).
76 | config.i18n.fallbacks = true
77 |
78 | # Send deprecation notices to registered listeners.
79 | config.active_support.deprecation = :notify
80 |
81 | # Use default logging formatter so that PID and timestamp are not suppressed.
82 | config.log_formatter = ::Logger::Formatter.new
83 |
84 | # Use a different logger for distributed setups.
85 | # require 'syslog/logger'
86 | # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')
87 |
88 | if ENV['RAILS_LOG_TO_STDOUT'].present?
89 | logger = ActiveSupport::Logger.new(STDOUT)
90 | logger.formatter = config.log_formatter
91 | config.logger = ActiveSupport::TaggedLogging.new(logger)
92 | end
93 |
94 | # Do not dump schema after migrations.
95 | config.active_record.dump_schema_after_migration = false
96 |
97 | # Must include to get inline SVGs to work in deploy
98 | config.assets.css_compressor = :scss
99 |
100 | #Fix to enable img usage @ heroku
101 | config.assets.compile = true
102 | config.assets.digest = true
103 |
104 | #adding svg icons font into the assets pipeline (for Heroku)
105 | config.assets.paths << Rails.root.join('assets', 'images','icons')
106 |
107 | #Precompile additional assets (for heroku)
108 | config.assets.precompile += %w( .svg .eot .woff .ttf )
109 |
110 | end
111 |
--------------------------------------------------------------------------------
/config/environments/test.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | Rails.application.configure do
4 | # Settings specified here will take precedence over those in config/application.rb.
5 |
6 | # The test environment is used exclusively to run your application's
7 | # test suite. You never need to work with it otherwise. Remember that
8 | # your test database is "scratch space" for the test suite and is wiped
9 | # and recreated between test runs. Don't rely on the data there!
10 | config.cache_classes = true
11 |
12 | # Do not eager load code on boot. This avoids loading your whole application
13 | # just for the purpose of running a single test. If you are using a tool that
14 | # preloads Rails for running tests, you may have to set it to true.
15 | config.eager_load = false
16 |
17 | # Configure public file server for tests with Cache-Control for performance.
18 | config.public_file_server.enabled = true
19 | config.public_file_server.headers = {
20 | 'Cache-Control' => "public, max-age=#{1.hour.to_i}"
21 | }
22 |
23 | # Show full error reports and disable caching.
24 | config.consider_all_requests_local = true
25 | config.action_controller.perform_caching = false
26 |
27 | # Raise exceptions instead of rendering exception templates.
28 | config.action_dispatch.show_exceptions = false
29 |
30 | # Disable request forgery protection in test environment.
31 | config.action_controller.allow_forgery_protection = false
32 |
33 | # Store uploaded files on the local file system in a temporary directory
34 | config.active_storage.service = :test
35 |
36 | config.action_mailer.perform_caching = false
37 |
38 | # Tell Action Mailer not to deliver emails to the real world.
39 | # The :test delivery method accumulates sent emails in the
40 | # ActionMailer::Base.deliveries array.
41 | config.action_mailer.delivery_method = :test
42 |
43 | # Print deprecation notices to the stderr.
44 | config.active_support.deprecation = :stderr
45 |
46 | # Raises error for missing translations
47 | # config.action_view.raise_on_missing_translations = true
48 |
49 | #devise configuration
50 | config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
51 |
52 | end
53 |
--------------------------------------------------------------------------------
/config/initializers/application_controller_renderer.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # Be sure to restart your server when you modify this file.
3 |
4 | # ActiveSupport::Reloader.to_prepare do
5 | # ApplicationController.renderer.defaults.merge!(
6 | # http_host: 'example.org',
7 | # https: false
8 | # )
9 | # end
10 |
--------------------------------------------------------------------------------
/config/initializers/assets.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Be sure to restart your server when you modify this file.
4 |
5 | # Version of your assets, change this if you want to expire all your assets.
6 | Rails.application.config.assets.version = '1.0'
7 |
8 | # Add additional assets to the asset load path.
9 | # Rails.application.config.assets.paths << Emoji.images_path
10 | # Add Yarn node_modules folder to the asset load path.
11 | Rails.application.config.assets.paths << Rails.root.join('node_modules')
12 | Rails.application.config.assets.paths << Rails.root.join('assets', 'images','icons')
13 |
14 | # Precompile additional assets.
15 | # application.js, application.css, and all non-JS/CSS in the app/assets
16 | # folder are already added.
17 | # Rails.application.config.assets.precompile += %w( admin.js admin.css )
18 |
19 | Rails.application.config.assets.precompile += %w( '.png' )
20 | Rails.application.config.assets.precompile += %w( '.svg' )
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/config/initializers/backtrace_silencers.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # Be sure to restart your server when you modify this file.
3 |
4 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
5 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
6 |
7 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
8 | # Rails.backtrace_cleaner.remove_silencers!
9 |
--------------------------------------------------------------------------------
/config/initializers/content_security_policy.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # Be sure to restart your server when you modify this file.
3 |
4 | # Define an application-wide content security policy
5 | # For further information see the following documentation
6 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
7 |
8 | # Rails.application.config.content_security_policy do |policy|
9 | # policy.default_src :self, :https
10 | # policy.font_src :self, :https, :data
11 | # policy.img_src :self, :https, :data
12 | # policy.object_src :none
13 | # policy.script_src :self, :https
14 | # policy.style_src :self, :https
15 |
16 | # # Specify URI for violation reports
17 | # # policy.report_uri "/csp-violation-report-endpoint"
18 | # end
19 |
20 | # If you are using UJS then enable automatic nonce generation
21 | # Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) }
22 |
23 | # Report CSP violations to a specified URI
24 | # For further information see the following documentation:
25 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only
26 | # Rails.application.config.content_security_policy_report_only = true
27 |
--------------------------------------------------------------------------------
/config/initializers/cookies_serializer.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Be sure to restart your server when you modify this file.
4 |
5 | # Specify a serializer for the signed and encrypted cookie jars.
6 | # Valid options are :json, :marshal, and :hybrid.
7 | Rails.application.config.action_dispatch.cookies_serializer = :json
8 |
--------------------------------------------------------------------------------
/config/initializers/filter_parameter_logging.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Be sure to restart your server when you modify this file.
4 |
5 | # Configure sensitive parameters which will be filtered from the log file.
6 | Rails.application.config.filter_parameters += [:password]
7 |
--------------------------------------------------------------------------------
/config/initializers/inflections.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # Be sure to restart your server when you modify this file.
3 |
4 | # Add new inflection rules using the following format. Inflections
5 | # are locale specific, and you may define rules for as many different
6 | # locales as you wish. All of these examples are active by default:
7 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
8 | # inflect.plural /^(ox)$/i, '\1en'
9 | # inflect.singular /^(ox)en/i, '\1'
10 | # inflect.irregular 'person', 'people'
11 | # inflect.uncountable %w( fish sheep )
12 | # end
13 |
14 | # These inflection rules are supported but not enabled by default:
15 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
16 | # inflect.acronym 'RESTful'
17 | # end
18 |
--------------------------------------------------------------------------------
/config/initializers/mime_types.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # Be sure to restart your server when you modify this file.
3 |
4 | # Add new mime types for use in respond_to blocks:
5 | # Mime::Type.register "text/richtext", :rtf
6 |
--------------------------------------------------------------------------------
/config/initializers/simple_form.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | #
4 | # Uncomment this and change the path if necessary to include your own
5 | # components.
6 | # See https://github.com/heartcombo/simple_form#custom-components to know
7 | # more about custom components.
8 | # Dir[Rails.root.join('lib/components/**/*.rb')].each { |f| require f }
9 | #
10 | # Use this setup block to configure all options available in SimpleForm.
11 | SimpleForm.setup do |config|
12 | # Wrappers are used by the form builder to generate a
13 | # complete input. You can remove any component from the
14 | # wrapper, change the order or even add your own to the
15 | # stack. The options given below are used to wrap the
16 | # whole input.
17 | config.wrappers :default, class: :input,
18 | hint_class: :field_with_hint, error_class: :field_with_errors, valid_class: :field_without_errors do |b|
19 | ## Extensions enabled by default
20 | # Any of these extensions can be disabled for a
21 | # given input by passing: `f.input EXTENSION_NAME => false`.
22 | # You can make any of these extensions optional by
23 | # renaming `b.use` to `b.optional`.
24 |
25 | # Determines whether to use HTML5 (:email, :url, ...)
26 | # and required attributes
27 | b.use :html5
28 |
29 | # Calculates placeholders automatically from I18n
30 | # You can also pass a string as f.input placeholder: "Placeholder"
31 | b.use :placeholder
32 |
33 | ## Optional extensions
34 | # They are disabled unless you pass `f.input EXTENSION_NAME => true`
35 | # to the input. If so, they will retrieve the values from the model
36 | # if any exists. If you want to enable any of those
37 | # extensions by default, you can change `b.optional` to `b.use`.
38 |
39 | # Calculates maxlength from length validations for string inputs
40 | # and/or database column lengths
41 | b.optional :maxlength
42 |
43 | # Calculate minlength from length validations for string inputs
44 | b.optional :minlength
45 |
46 | # Calculates pattern from format validations for string inputs
47 | b.optional :pattern
48 |
49 | # Calculates min and max from length validations for numeric inputs
50 | b.optional :min_max
51 |
52 | # Calculates readonly automatically from readonly attributes
53 | b.optional :readonly
54 |
55 | ## Inputs
56 | # b.use :input, class: 'input', error_class: 'is-invalid', valid_class: 'is-valid'
57 | b.use :label_input
58 | b.use :hint, wrap_with: { tag: :span, class: :hint }
59 | b.use :error, wrap_with: { tag: :span, class: :error }
60 |
61 | ## full_messages_for
62 | # If you want to display the full error message for the attribute, you can
63 | # use the component :full_error, like:
64 | #
65 | # b.use :full_error, wrap_with: { tag: :span, class: :error }
66 | end
67 |
68 | # The default wrapper to be used by the FormBuilder.
69 | config.default_wrapper = :default
70 |
71 | # Define the way to render check boxes / radio buttons with labels.
72 | # Defaults to :nested for bootstrap config.
73 | # inline: input + label
74 | # nested: label > input
75 | config.boolean_style = :nested
76 |
77 | # Default class for buttons
78 | config.button_class = 'btn'
79 |
80 | # Method used to tidy up errors. Specify any Rails Array method.
81 | # :first lists the first message for each field.
82 | # Use :to_sentence to list all errors for each field.
83 | # config.error_method = :first
84 |
85 | # Default tag used for error notification helper.
86 | config.error_notification_tag = :div
87 |
88 | # CSS class to add for error notification helper.
89 | config.error_notification_class = 'error_notification'
90 |
91 | # Series of attempts to detect a default label method for collection.
92 | # config.collection_label_methods = [ :to_label, :name, :title, :to_s ]
93 |
94 | # Series of attempts to detect a default value method for collection.
95 | # config.collection_value_methods = [ :id, :to_s ]
96 |
97 | # You can wrap a collection of radio/check boxes in a pre-defined tag, defaulting to none.
98 | # config.collection_wrapper_tag = nil
99 |
100 | # You can define the class to use on all collection wrappers. Defaulting to none.
101 | # config.collection_wrapper_class = nil
102 |
103 | # You can wrap each item in a collection of radio/check boxes with a tag,
104 | # defaulting to :span.
105 | # config.item_wrapper_tag = :span
106 |
107 | # You can define a class to use in all item wrappers. Defaulting to none.
108 | # config.item_wrapper_class = nil
109 |
110 | # How the label text should be generated altogether with the required text.
111 | # config.label_text = lambda { |label, required, explicit_label| "#{required} #{label}" }
112 |
113 | # You can define the class to use on all labels. Default is nil.
114 | # config.label_class = nil
115 |
116 | # You can define the default class to be used on forms. Can be overriden
117 | # with `html: { :class }`. Defaulting to none.
118 | # config.default_form_class = nil
119 |
120 | # You can define which elements should obtain additional classes
121 | # config.generate_additional_classes_for = [:wrapper, :label, :input]
122 |
123 | # Whether attributes are required by default (or not). Default is true.
124 | # config.required_by_default = true
125 |
126 | # Tell browsers whether to use the native HTML5 validations (novalidate form option).
127 | # These validations are enabled in SimpleForm's internal config but disabled by default
128 | # in this configuration, which is recommended due to some quirks from different browsers.
129 | # To stop SimpleForm from generating the novalidate option, enabling the HTML5 validations,
130 | # change this configuration to true.
131 | config.browser_validations = false
132 |
133 | # Custom mappings for input types. This should be a hash containing a regexp
134 | # to match as key, and the input type that will be used when the field name
135 | # matches the regexp as value.
136 | # config.input_mappings = { /count/ => :integer }
137 |
138 | # Custom wrappers for input types. This should be a hash containing an input
139 | # type as key and the wrapper that will be used for all inputs with specified type.
140 | # config.wrapper_mappings = { string: :prepend }
141 |
142 | # Namespaces where SimpleForm should look for custom input classes that
143 | # override default inputs.
144 | # config.custom_inputs_namespaces << "CustomInputs"
145 |
146 | # Default priority for time_zone inputs.
147 | # config.time_zone_priority = nil
148 |
149 | # Default priority for country inputs.
150 | # config.country_priority = nil
151 |
152 | # When false, do not use translations for labels.
153 | # config.translate_labels = true
154 |
155 | # Automatically discover new inputs in Rails' autoload path.
156 | # config.inputs_discovery = true
157 |
158 | # Cache SimpleForm inputs discovery
159 | # config.cache_discovery = !Rails.env.development?
160 |
161 | # Default class for inputs
162 | # config.input_class = nil
163 |
164 | # Define the default class of the input wrapper of the boolean input.
165 | config.boolean_label_class = 'checkbox'
166 |
167 | # Defines if the default input wrapper class should be included in radio
168 | # collection wrappers.
169 | # config.include_default_input_wrapper_class = true
170 |
171 | # Defines which i18n scope will be used in Simple Form.
172 | # config.i18n_scope = 'simple_form'
173 |
174 | # Defines validation classes to the input_field. By default it's nil.
175 | # config.input_field_valid_class = 'is-valid'
176 | # config.input_field_error_class = 'is-invalid'
177 | end
178 |
--------------------------------------------------------------------------------
/config/initializers/wrap_parameters.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Be sure to restart your server when you modify this file.
4 |
5 | # This file contains settings for ActionController::ParamsWrapper which
6 | # is enabled by default.
7 |
8 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
9 | ActiveSupport.on_load(:action_controller) do
10 | wrap_parameters format: [:json]
11 | end
12 |
13 | # To enable root element in JSON for ActiveRecord objects.
14 | # ActiveSupport.on_load(:active_record) do
15 | # self.include_root_in_json = true
16 | # end
17 |
--------------------------------------------------------------------------------
/config/locales/devise.en.yml:
--------------------------------------------------------------------------------
1 | # Additional translations at https://github.com/plataformatec/devise/wiki/I18n
2 |
3 | en:
4 | devise:
5 | confirmations:
6 | confirmed: "Your email address has been successfully confirmed."
7 | send_instructions: "You will receive an email with instructions for how to confirm your email address in a few minutes."
8 | send_paranoid_instructions: "If your email address exists in our database, you will receive an email with instructions for how to confirm your email address in a few minutes."
9 | failure:
10 | already_authenticated: "You are already signed in."
11 | inactive: "Your account is not activated yet."
12 | invalid: "Invalid %{authentication_keys} or password."
13 | locked: "Your account is locked."
14 | last_attempt: "You have one more attempt before your account is locked."
15 | not_found_in_database: "Invalid %{authentication_keys} or password."
16 | timeout: "Your session expired. Please sign in again to continue."
17 | unauthenticated: "You need to sign in or sign up before continuing."
18 | unconfirmed: "You have to confirm your email address before continuing."
19 | mailer:
20 | confirmation_instructions:
21 | subject: "Confirmation instructions"
22 | reset_password_instructions:
23 | subject: "Reset password instructions"
24 | unlock_instructions:
25 | subject: "Unlock instructions"
26 | email_changed:
27 | subject: "Email Changed"
28 | password_change:
29 | subject: "Password Changed"
30 | omniauth_callbacks:
31 | failure: "Could not authenticate you from %{kind} because \"%{reason}\"."
32 | success: "Successfully authenticated from %{kind} account."
33 | passwords:
34 | no_token: "You can't access this page without coming from a password reset email. If you do come from a password reset email, please make sure you used the full URL provided."
35 | send_instructions: "You will receive an email with instructions on how to reset your password in a few minutes."
36 | send_paranoid_instructions: "If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes."
37 | updated: "Your password has been changed successfully. You are now signed in."
38 | updated_not_active: "Your password has been changed successfully."
39 | registrations:
40 | destroyed: "Bye! Your account has been successfully cancelled. We hope to see you again soon."
41 | signed_up: "Welcome! You have signed up successfully."
42 | signed_up_but_inactive: "You have signed up successfully. However, we could not sign you in because your account is not yet activated."
43 | signed_up_but_locked: "You have signed up successfully. However, we could not sign you in because your account is locked."
44 | signed_up_but_unconfirmed: "A message with a confirmation link has been sent to your email address. Please follow the link to activate your account."
45 | update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and follow the confirmation link to confirm your new email address."
46 | updated: "Your account has been updated successfully."
47 | updated_but_not_signed_in: "Your account has been updated successfully, but since your password was changed, you need to sign in again"
48 | sessions:
49 | signed_in: "Signed in successfully."
50 | signed_out: "Signed out successfully."
51 | already_signed_out: "Signed out successfully."
52 | unlocks:
53 | send_instructions: "You will receive an email with instructions for how to unlock your account in a few minutes."
54 | send_paranoid_instructions: "If your account exists, you will receive an email with instructions for how to unlock it in a few minutes."
55 | unlocked: "Your account has been unlocked successfully. Please sign in to continue."
56 | errors:
57 | messages:
58 | already_confirmed: "was already confirmed, please try signing in"
59 | confirmation_period_expired: "needs to be confirmed within %{period}, please request a new one"
60 | expired: "has expired, please request a new one"
61 | not_found: "not found"
62 | not_locked: "was not locked"
63 | not_saved:
64 | one: "1 error prohibited this %{resource} from being saved:"
65 | other: "%{count} errors prohibited this %{resource} from being saved:"
66 |
--------------------------------------------------------------------------------
/config/locales/en.yml:
--------------------------------------------------------------------------------
1 | # Files in the config/locales directory are used for internationalization
2 | # and are automatically loaded by Rails. If you want to use locales other
3 | # than English, add the necessary files in this directory.
4 | #
5 | # To use the locales, use `I18n.t`:
6 | #
7 | # I18n.t 'hello'
8 | #
9 | # In views, this is aliased to just `t`:
10 | #
11 | # <%= t('hello') %>
12 | #
13 | # To use a different locale, set it with `I18n.locale`:
14 | #
15 | # I18n.locale = :es
16 | #
17 | # This would use the information in config/locales/es.yml.
18 | #
19 | # The following keys must be escaped otherwise they will not be retrieved by
20 | # the default I18n backend:
21 | #
22 | # true, false, on, off, yes, no
23 | #
24 | # Instead, surround them with single quotes.
25 | #
26 | # en:
27 | # 'true': 'foo'
28 | #
29 | # To learn more, please read the Rails Internationalization guide
30 | # available at http://guides.rubyonrails.org/i18n.html.
31 |
32 | en:
33 | hello: "Hello world"
34 |
--------------------------------------------------------------------------------
/config/locales/simple_form.en.yml:
--------------------------------------------------------------------------------
1 | en:
2 | simple_form:
3 | "yes": 'Yes'
4 | "no": 'No'
5 | required:
6 | text: 'required'
7 | mark: '*'
8 | # You can uncomment the line below if you need to overwrite the whole required html.
9 | # When using html, text and mark won't be used.
10 | # html: '*'
11 | error_notification:
12 | default_message: "Please review the problems below:"
13 | # Examples
14 | # labels:
15 | # defaults:
16 | # password: 'Password'
17 | # user:
18 | # new:
19 | # email: 'E-mail to sign in.'
20 | # edit:
21 | # email: 'E-mail.'
22 | # hints:
23 | # defaults:
24 | # username: 'User name to sign in.'
25 | # password: 'No special characters, please.'
26 | # include_blanks:
27 | # defaults:
28 | # age: 'Rather not say'
29 | # prompts:
30 | # defaults:
31 | # age: 'Select your age'
32 |
--------------------------------------------------------------------------------
/config/puma.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Puma can serve each request in a thread from an internal thread pool.
4 | # The `threads` method setting takes two numbers: a minimum and maximum.
5 | # Any libraries that use thread pools should be configured to match
6 | # the maximum value specified for Puma. Default is set to 5 threads for minimum
7 | # and maximum; this matches the default thread size of Active Record.
8 | #
9 | threads_count = ENV.fetch('RAILS_MAX_THREADS') { 5 }
10 | threads threads_count, threads_count
11 |
12 | # Specifies the `port` that Puma will listen on to receive requests; default is 3000.
13 | #
14 | port ENV.fetch('PORT') { 3000 }
15 |
16 | # Specifies the `environment` that Puma will run in.
17 | #
18 | environment ENV.fetch('RAILS_ENV') { 'development' }
19 |
20 | # Specifies the `pidfile` that Puma will use.
21 | pidfile ENV.fetch('PIDFILE') { 'tmp/pids/server.pid' }
22 |
23 | # Specifies the number of `workers` to boot in clustered mode.
24 | # Workers are forked webserver processes. If using threads and workers together
25 | # the concurrency of the application would be max `threads` * `workers`.
26 | # Workers do not work on JRuby or Windows (both of which do not support
27 | # processes).
28 | #
29 | # workers ENV.fetch("WEB_CONCURRENCY") { 2 }
30 |
31 | # Use the `preload_app!` method when specifying a `workers` number.
32 | # This directive tells Puma to first boot the application and load code
33 | # before forking the application. This takes advantage of Copy On Write
34 | # process behavior so workers use less memory.
35 | #
36 | # preload_app!
37 |
38 | # Allow puma to be restarted by `rails restart` command.
39 | plugin :tmp_restart
40 |
--------------------------------------------------------------------------------
/config/routes.rb:
--------------------------------------------------------------------------------
1 |
2 | Rails.application.routes.draw do
3 |
4 | root to: 'welcome#index'
5 |
6 | devise_for :users, :controllers => { registrations: 'users/registrations' }
7 | resources :transactions, only: [ :index, :new, :create, :edit, :delete, :destroy ]
8 |
9 |
10 | get 'enrolled/:id', to: 'enrolled#enrolled'
11 |
12 |
13 | resources :enrolls, only: [ :create, :show ]
14 |
15 | get 'enrolar/:id', to: 'enrolled#enrolar'
16 | resources :transactions do
17 | member do
18 | get 'confirm_destroy'
19 | get 'enrolled'
20 | end
21 | end
22 |
23 | resources :groups # here we create the resource course(group)
24 | resources :groups do
25 | member do
26 | get 'confirm_destroy'
27 | end
28 | end
29 |
30 |
31 | end
32 |
--------------------------------------------------------------------------------
/config/spring.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | %w[
4 | .ruby-version
5 | .rbenv-vars
6 | tmp/restart.txt
7 | tmp/caching-dev.txt
8 | ].each { |path| Spring.watch(path) }
9 |
--------------------------------------------------------------------------------
/config/storage.yml:
--------------------------------------------------------------------------------
1 | test:
2 | service: Disk
3 | root: <%= Rails.root.join("tmp/storage") %>
4 |
5 | local:
6 | service: Disk
7 | root: <%= Rails.root.join("storage") %>
8 |
9 | # Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key)
10 | # amazon:
11 | # service: S3
12 | # access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>
13 | # secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
14 | # region: us-east-1
15 | # bucket: your_own_bucket
16 |
17 | # Remember not to checkin your GCS keyfile to a repository
18 | # google:
19 | # service: GCS
20 | # project: your_project
21 | # credentials: <%= Rails.root.join("path/to/gcs.keyfile") %>
22 | # bucket: your_own_bucket
23 |
24 | # Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key)
25 | # microsoft:
26 | # service: AzureStorage
27 | # storage_account_name: your_account_name
28 | # storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %>
29 | # container: your_container_name
30 |
31 | # mirror:
32 | # service: Mirror
33 | # primary: local
34 | # mirrors: [ amazon, google, microsoft ]
35 |
--------------------------------------------------------------------------------
/db/migrate/20200509222956_create_groups.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class CreateGroups < ActiveRecord::Migration[5.2]
4 | def change
5 | create_table :groups do |t|
6 | t.string :name
7 | t.text :description
8 | t.integer :duration
9 | t.decimal :price, precision: 8, scale: 2
10 | t.boolean :online
11 | t.boolean :presencial
12 | t.string :starting
13 | t.boolean :enabled
14 | t.string :cover_image
15 |
16 | t.timestamps
17 | end
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/db/migrate/20200512194136_devise_create_users.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class DeviseCreateUsers < ActiveRecord::Migration[5.2]
4 | def change
5 | create_table :users do |t|
6 | ## Database authenticatable
7 | t.string :name, null: false, default: ""
8 | t.string :email, null: false, default: ""
9 | t.integer :role, null: false
10 | t.string :encrypted_password, null: false, default: ""
11 |
12 | ## Recoverable
13 | t.string :reset_password_token
14 | t.datetime :reset_password_sent_at
15 |
16 | ## Rememberable
17 | t.datetime :remember_created_at
18 |
19 | ## Trackable
20 | # t.integer :sign_in_count, default: 0, null: false
21 | # t.datetime :current_sign_in_at
22 | # t.datetime :last_sign_in_at
23 | # t.string :current_sign_in_ip
24 | # t.string :last_sign_in_ip
25 |
26 | ## Confirmable
27 | # t.string :confirmation_token
28 | # t.datetime :confirmed_at
29 | # t.datetime :confirmation_sent_at
30 | # t.string :unconfirmed_email # Only if using reconfirmable
31 |
32 | ## Lockable
33 | # t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
34 | # t.string :unlock_token # Only if unlock strategy is :email or :both
35 | # t.datetime :locked_at
36 |
37 |
38 | t.timestamps null: false
39 | end
40 |
41 | add_index :users, :email, unique: true
42 | add_index :users, :reset_password_token, unique: true
43 | # add_index :users, :confirmation_token, unique: true
44 | # add_index :users, :unlock_token, unique: true
45 | end
46 | end
47 |
--------------------------------------------------------------------------------
/db/migrate/20200512214438_add_user_to_groups_course.rb:
--------------------------------------------------------------------------------
1 | class AddUserToGroupsCourse < ActiveRecord::Migration[5.2]
2 | def change
3 | add_column :groups, :author_id, :integer
4 | add_foreign_key :groups, :users, column: :author_id, primary_key: "id"
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/db/migrate/20200513110914_create_enrolls.rb:
--------------------------------------------------------------------------------
1 | class CreateEnrolls < ActiveRecord::Migration[5.2]
2 | def change
3 | create_table :enrolls do |t|
4 | t.integer :student_id
5 | t.integer :course_id
6 | t.timestamps
7 | end
8 | add_foreign_key :enrolls, :users, column: :student_id, primary_key: "id"
9 | add_foreign_key :enrolls, :groups, column: :course_id, primary_key: "id"
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/db/migrate/20200513133240_create_transactions.rb:
--------------------------------------------------------------------------------
1 | class CreateTransactions < ActiveRecord::Migration[5.2]
2 | def change
3 | create_table :transactions do |t|
4 | t.integer :teacher_id
5 | t.integer :status
6 | t.integer :booking_type
7 | t.integer :minutes
8 | t.date :accdate
9 | t.integer :sitting_student_id, null: true, foreign_key: true
10 | t.integer :course_taught_id, null: true, foreign_key: true
11 |
12 | t.timestamps
13 | end
14 |
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/db/schema.rb:
--------------------------------------------------------------------------------
1 | # This file is auto-generated from the current state of the database. Instead
2 | # of editing this file, please use the migrations feature of Active Record to
3 | # incrementally modify your database, and then regenerate this schema definition.
4 | #
5 | # Note that this schema.rb definition is the authoritative source for your
6 | # database schema. If you need to create the application database on another
7 | # system, you should be using db:schema:load, not running all the migrations
8 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations
9 | # you'll amass, the slower it'll run and the greater likelihood for issues).
10 | #
11 | # It's strongly recommended that you check this file into your version control system.
12 |
13 | ActiveRecord::Schema.define(version: 2020_05_13_133240) do
14 |
15 | create_table "enrolls", force: :cascade do |t|
16 | t.integer "student_id"
17 | t.integer "course_id"
18 | t.datetime "created_at", null: false
19 | t.datetime "updated_at", null: false
20 | end
21 |
22 | create_table "groups", force: :cascade do |t|
23 | t.string "name"
24 | t.text "description"
25 | t.integer "duration"
26 | t.decimal "price", precision: 8, scale: 2
27 | t.boolean "online"
28 | t.boolean "presencial"
29 | t.string "starting"
30 | t.boolean "enabled"
31 | t.string "cover_image"
32 | t.datetime "created_at", null: false
33 | t.datetime "updated_at", null: false
34 | t.integer "author_id"
35 | end
36 |
37 | create_table "transactions", force: :cascade do |t|
38 | t.integer "teacher_id"
39 | t.integer "status"
40 | t.integer "booking_type"
41 | t.integer "minutes"
42 | t.date "accdate"
43 | t.integer "sitting_student_id"
44 | t.integer "course_taught_id"
45 | t.datetime "created_at", null: false
46 | t.datetime "updated_at", null: false
47 | end
48 |
49 | create_table "users", force: :cascade do |t|
50 | t.string "name", default: "", null: false
51 | t.string "email", default: "", null: false
52 | t.integer "role", null: false
53 | t.string "encrypted_password", default: "", null: false
54 | t.string "reset_password_token"
55 | t.datetime "reset_password_sent_at"
56 | t.datetime "remember_created_at"
57 | t.datetime "created_at", null: false
58 | t.datetime "updated_at", null: false
59 | t.index ["email"], name: "index_users_on_email", unique: true
60 | t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
61 | end
62 |
63 | end
64 |
--------------------------------------------------------------------------------
/db/seeds.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # This file should contain all the record creation needed to seed the database with its default values.
3 | # The data can then be loaded with the rails db:seed command (or created alongside the database with db:setup).
4 | #
5 | # Examples:
6 | #
7 | # movies = Movie.create([{ name: 'Star Wars' }, { name: 'Lord of the Rings' }])
8 | # Character.create(name: 'Luke', movie: movies.first)
9 |
--------------------------------------------------------------------------------
/erd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canriquez/rails_capstone_lessons_lab/3e563c5ac1855a0a88c95fc3c79f039db2a89061/erd.png
--------------------------------------------------------------------------------
/lib/assets/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canriquez/rails_capstone_lessons_lab/3e563c5ac1855a0a88c95fc3c79f039db2a89061/lib/assets/.keep
--------------------------------------------------------------------------------
/lib/tasks/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canriquez/rails_capstone_lessons_lab/3e563c5ac1855a0a88c95fc3c79f039db2a89061/lib/tasks/.keep
--------------------------------------------------------------------------------
/lib/templates/erb/scaffold/_form.html.erb:
--------------------------------------------------------------------------------
1 | <%# frozen_string_literal: true %>
2 | <%%= simple_form_for(@<%= singular_table_name %>) do |f| %>
3 | <%%= f.error_notification %>
4 | <%%= f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present? %>
5 |
6 |
If you are the application owner check the logs for more information.
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/public/apple-touch-icon-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canriquez/rails_capstone_lessons_lab/3e563c5ac1855a0a88c95fc3c79f039db2a89061/public/apple-touch-icon-precomposed.png
--------------------------------------------------------------------------------
/public/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canriquez/rails_capstone_lessons_lab/3e563c5ac1855a0a88c95fc3c79f039db2a89061/public/apple-touch-icon.png
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canriquez/rails_capstone_lessons_lab/3e563c5ac1855a0a88c95fc3c79f039db2a89061/public/favicon.ico
--------------------------------------------------------------------------------
/public/mam.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canriquez/rails_capstone_lessons_lab/3e563c5ac1855a0a88c95fc3c79f039db2a89061/public/mam.png
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
2 |
--------------------------------------------------------------------------------
/spec/controllers/enrolls_controller_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | describe EnrollsController do
4 | describe 'Teacher User' do
5 | context 'logged in and course owner' do
6 | describe 'POST enrolls (create)' do
7 | # one teacher, one student, one course. Test: one enrollment.
8 | let(:t1) { FactoryBot.create(:teacher_user) }
9 | before do
10 | sign_in(t1)
11 | end
12 | let(:s1) { FactoryBot.create(:student_user) }
13 | let(:c1) { FactoryBot.create(:group_enabled, author: t1) }
14 |
15 | it 'creates the enroll and redirect to success controller' do
16 | expect do
17 | post :create, params: { student: s1, course: c1 }
18 | expect(response).to redirect_to(notices_path)
19 | end
20 | end
21 |
22 | it 'creates the enroll and updates de DB' do
23 | expect do
24 | post :create, params: { student_id: s1, course_id: c1 }
25 | end.to change(Enroll, :count).by(1)
26 | end
27 | end
28 | end
29 |
30 | context 'logged in not course owner' do
31 | describe 'POST enrolls create' do
32 | # one teacher, one student, one course. Test: one enrollment.
33 | let(:t1) { FactoryBot.create(:teacher_user) }
34 | let(:t2) { FactoryBot.create(:teacher_user) }
35 |
36 | before do
37 | sign_in(t2)
38 | end
39 | let(:s1) { FactoryBot.create(:student_user) }
40 | let(:c1) { FactoryBot.create(:group_enabled, author: t1) }
41 |
42 | it 'fails to enroll and redirect to course index page' do
43 | expect do
44 | post :create, params: { student: s1, course: c1 }
45 | expect(response).to redirect_to(groups_path)
46 | end
47 | end
48 |
49 | it 'creates the enroll and updates de DB' do
50 | expect do
51 | post :create, params: { student: s1, course: c1 }
52 | end.to change(Enroll, :count).by(0)
53 | end
54 | end
55 |
56 | describe 'DELETE request to destroy a course enrollment'
57 | end
58 | end
59 |
60 | describe 'Student User' do
61 | context 'logged in not course owner' do
62 | describe 'POST enrolls create' do
63 | # one teacher, one student, one course. Test: one enrollment.
64 | let(:t1) { FactoryBot.create(:teacher_user) }
65 | let(:s1) { FactoryBot.create(:student_user) }
66 |
67 | before do
68 | sign_in(s1)
69 | end
70 |
71 | let(:c1) { FactoryBot.create(:group_enabled, author: t1) }
72 |
73 | it 'fails to enroll and redirect to course index page' do
74 | expect do
75 | post :create, params: { student: s1, course: c1 }
76 | expect(response).to redirect_to(groups_path)
77 | end
78 | end
79 |
80 | it 'creates the enroll and updates de DB' do
81 | expect do
82 | post :create, params: { student: s1, course: c1 }
83 | end.to change(Enroll, :count).by(0)
84 | end
85 | end
86 | end
87 | end
88 | end
89 |
90 | # rubocop:enable
91 |
--------------------------------------------------------------------------------
/spec/controllers/groups_controller_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | # rubocop:disable Metrics/BlockLength,Layout/LineLength,Lint/UselessAssignment,Naming/VariableNumber
4 |
5 | describe GroupsController do
6 | describe 'Student User ' do
7 | # we create student, course and login as student
8 | let(:teacher_1) { FactoryBot.create(:teacher_user) }
9 | let(:student_1) { FactoryBot.create(:student_user) }
10 | let(:other_student) { FactoryBot.create(:student_user) }
11 |
12 | let(:other_student_enrolled_course_1) { FactoryBot.create(:enroll, student: student_1, course: course_1) }
13 | before do
14 | sign_in(student_1)
15 | end
16 |
17 | describe 'GET course index list' do
18 | it 'renders :index template' do
19 | get :index
20 | expect(response).to render_template(:index)
21 | end
22 | it "selects only 'enrolled' courses for the student to show on index" do
23 | course_1 = FactoryBot.create(:group_enabled, author: teacher_1)
24 | FactoryBot.create(:enroll, student: student_1, course: course_1)
25 |
26 | get :index
27 | expect(assigns(:group)).to match_array([course_1])
28 | end
29 | end
30 |
31 | describe 'GET show course' do
32 | it 'renders :show template only if user is enrolled in the course' do
33 | course_1 = FactoryBot.create(:group_enabled, author: teacher_1)
34 | FactoryBot.create(:enroll, student: student_1, course: course_1)
35 | get :show, params: { id: course_1 }
36 | expect(response).to render_template(:show)
37 | end
38 | it 'assigns requested course to the @student_course variable for the loged_in student' do
39 | course_1 = FactoryBot.create(:group_enabled, author: teacher_1)
40 | FactoryBot.create(:enroll, student: student_1, course: course_1)
41 | get :show, params: { id: course_1 }
42 | expect(assigns(:group)).to eq(course_1)
43 | #:group is the variable defined in the groups_controller.rb file for eny course.
44 | end
45 | end
46 |
47 | # A student cannot create a new course
48 | describe 'GET new course' do
49 | it 'fails to render the new course form and redirects to login page' do
50 | get :new
51 | expect(response).to redirect_to(groups_path)
52 | end
53 | end
54 |
55 | describe 'POST course create' do
56 | let(:course_1) { FactoryBot.create(:group_enabled, author: teacher_1) }
57 | it 'fails and redirects to login page instead as student cannot create courses' do
58 | post :create, params: { group: course_1 }
59 | expect(response).to redirect_to(groups_path)
60 | end
61 | end
62 |
63 | describe 'GET course for edit' do
64 | let(:course_1) { FactoryBot.create(:group_enabled, author: teacher_1) }
65 | it 'fails to render :edit template as students are not allowed to edit courses' do
66 | get :edit, params: { id: course_1 }
67 | expect(response).to redirect_to(groups_path)
68 | end
69 | end
70 |
71 | describe 'PUT request to update course' do
72 | let(:course_1) { FactoryBot.create(:group_enabled, author: teacher_1) }
73 | let(:valid_course_data_change) { FactoryBot.attributes_for(:group_enabled, name: 'Course name update') }
74 | it 'fails to PUT a change on the course record' do
75 | put :update, params: { id: course_1, group: valid_course_data_change }
76 | expect(response).to redirect_to(groups_path)
77 | end
78 | end
79 |
80 | describe 'DELETE request to destroy a course record' do
81 | let(:course_1) { FactoryBot.create(:group_enabled, author: teacher_1) }
82 | it 'fails to destroy a course record' do
83 | delete :destroy, params: { id: course_1 }
84 | expect(response).to redirect_to(groups_path)
85 | end
86 | end
87 | end
88 |
89 | describe 'Teacher User' do
90 | let(:teacher_1) { FactoryBot.create(:teacher_user) }
91 | let(:teacher_2) { FactoryBot.create(:teacher_user) }
92 |
93 | before do
94 | sign_in(teacher_1)
95 | end
96 |
97 | describe 'GET course index' do
98 | it 'renders :index template' do
99 | get :index
100 | expect(response).to render_template(:index)
101 | end
102 | it 'selects only coursed where teacher is the author' do
103 | course_1 = FactoryBot.create(:group_enabled, name: 'teacher 1 course', author: teacher_1)
104 | course_2 = FactoryBot.create(:group_enabled, name: 'teacher 2 course', author: teacher_2)
105 | get :index
106 | expect(assigns(:group)).to match_array([course_1])
107 | end
108 | end
109 |
110 | describe 'GET show course' do
111 | it 'renders :show template and is able to edit authored courses' do
112 | course_1 = FactoryBot.create(:group_enabled, name: 'teacher 1 course', author: teacher_1)
113 | get :show, params: { id: course_1 }
114 | expect(response).to render_template(:show)
115 | end
116 | it 'assigns the authored course to the @group instance variable (for edition)' do
117 | course_1 = FactoryBot.create(:group_enabled, name: 'teacher 1 course', author: teacher_1)
118 | get :show, params: { id: course_1 }
119 | expect(assigns(:group)).to eq(course_1)
120 | #:group is the variable defined in the groups_controller.rb file
121 | end
122 | end
123 |
124 | describe 'GET new for teacher' do
125 | it 'renders :new template to create a new course' do
126 | get :new
127 | expect(response).to render_template(:new)
128 | end
129 | it 'assigns new Group to @group instance variable' do
130 | get :new
131 | expect(assigns(:group)).to be_a_new(Group)
132 | end
133 | end
134 |
135 | describe 'POST create' do
136 | let(:valid_course_data) { FactoryBot.attributes_for(:group, name: 'teacher-1 course', author: teacher_1.id) }
137 | let(:invalid_course_data) { FactoryBot.attributes_for(:group, name: nil, author: teacher_1.id) }
138 |
139 | context 'with valid data' do
140 | it 'redirects to show the course index in goups#index' do
141 | post :create, params: { group: valid_course_data }
142 | expect(response).to redirect_to(groups_path)
143 | end
144 | it 'creates a new group/course in the database' do
145 | expect do
146 | post :create, params: { group: valid_course_data }
147 | end.to change(Group, :count).by(1)
148 | end
149 | end
150 |
151 | context 'with invalid data' do
152 | it 'redirects to :new and shows :error notice' do
153 | post :create, params: { group: invalid_course_data }
154 | expect(response).to render_template(:new)
155 | # expect(response).to have_content("can't be blank")
156 | end
157 | it 'does not create a new :group in the database' do
158 | expect do
159 | post :create, params: { group: invalid_course_data }
160 | end.not_to change(Group, :count)
161 | end
162 | end
163 | end
164 |
165 | context 'and teacher is not the owner of the course' do
166 | let(:course_2) { FactoryBot.create(:group_enabled, name: 'teacher 2 course', author: teacher_2) }
167 | let(:valid_course_change) { FactoryBot.attributes_for(:group_enabled, name: 'teacher 1 edit', author: teacher_1) }
168 |
169 | describe 'GET course edit' do
170 | it 'fails to render :edit template as teacher 1 is not the owner of the current course redirects to course index' do
171 | get :edit, params: { id: course_2 }
172 | expect(response).to redirect_to(groups_path)
173 | end
174 | end
175 |
176 | describe 'PUT request to update course' do
177 | it 'fails to PUT a change on the course record redirects to course index' do
178 | put :update, params: { id: course_2, group: valid_course_change }
179 | expect(response).to redirect_to(groups_path)
180 | end
181 | end
182 |
183 | describe 'DELETE request to destroy a course record' do
184 | it 'fails to destroy a course record redirects to course index' do
185 | delete :destroy, params: { id: course_2 }
186 | expect(response).to redirect_to(groups_path)
187 | end
188 | end
189 | end
190 |
191 | context 'teacher is the owner of the course' do
192 | let(:valid_course_data) { FactoryBot.create(:group_enabled, author: teacher_1) }
193 |
194 | describe 'GET edit' do
195 | it 'renders :edit template to valid course author' do
196 | get :edit, params: { id: valid_course_data }
197 | expect(response).to render_template(:edit)
198 | end
199 | it 'assigns the requested group/course to the view' do
200 | get :edit, params: { id: valid_course_data }
201 | expect(assigns(:group)).to eq(valid_course_data)
202 | end
203 | end
204 |
205 | describe 'PUT update action with ' do
206 | # we first create the group/course we will test by updating with valid and invalid data.
207 | let(:valid_course) { FactoryBot.create(:group, name: 'teacher-1 course', author: teacher_1) }
208 | let(:invalid_course_data_change) do
209 | FactoryBot.attributes_for(:group,
210 | name: nil, author: teacher_1)
211 | end
212 | let(:valid_course_data_change) do
213 | FactoryBot.attributes_for(:group,
214 | name: 'best teacher-1 course', author: teacher_1)
215 | end
216 |
217 | context 'valid data for enabled group/course' do
218 | it 'redirects to groups#show action' do
219 | put :update, params: { id: valid_course, group: valid_course_data_change }
220 | expect(response).to redirect_to(groups_path)
221 | end
222 | it 'updates group/course changes in the database' do
223 | put :update, params: { id: valid_course, group: valid_course_data_change }
224 | valid_course.reload # I reload DB record to fetch new object changes
225 | expect(valid_course.name).to eq('best teacher-1 course') # I check directly in the DB (integration test)
226 | end
227 | end
228 |
229 | context 'invalid data change with enabled group/course' do
230 | it 'renders :edit view template' do
231 | put :update, params: { id: valid_course, group: invalid_course_data_change }
232 | expect(response).to render_template(:edit)
233 | end
234 | it 'fails to update the group/course changes in the DB' do
235 | put :update, params: { id: valid_course, group: invalid_course_data_change }
236 | valid_course.reload # I reload DB record to fetch new object changes
237 | expect(valid_course.name).not_to eq('best teacher-1 course')
238 | # I check directly in the DB (integration test)
239 | end
240 | end
241 | end
242 |
243 | describe 'DELETE action to destroy' do
244 | # we first create the grou/course we will test by destroying.
245 | it 'not to redirect to groups/courses index as AJAX is in use' do
246 | delete :destroy, params: { id: valid_course_data }
247 | expect(response).to redirect_to(groups_path)
248 | end
249 | it 'deletes group/course from database' do
250 | delete :destroy, params: { id: valid_course_data }
251 | expect(Group.exists?(valid_course_data.id)).to be_falsy
252 | end
253 | end
254 | end
255 | end
256 | end
257 |
258 | # rubocop:enable Metrics/BlockLength,Layout/LineLength,Lint/UselessAssignment,Naming/VariableNumber
259 |
--------------------------------------------------------------------------------
/spec/factories/enrolls.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :enroll do
3 | student { 1 }
4 | course { 1 }
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/spec/factories/groups.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :group do
3 | sequence(:name) { |n| "course #{n}" }
4 | description { 'yes this is a course description' }
5 | duration { 30 }
6 | price { '9.99' }
7 | starting { '22/2/22' }
8 | cover_image { 'my file' }
9 | online { true }
10 | presencial { true }
11 | enabled { true }
12 | author_id { 1 }
13 |
14 | factory :group_enabled do
15 | enabled { true }
16 | end
17 |
18 | factory :group_disabled do
19 | enabled { false }
20 | end
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/spec/factories/transactions.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :transaction do
3 | teacher_id { 1 }
4 |
5 | factory :billable do
6 | sitting_student_id { 1 }
7 | course_taught_id { 1 }
8 | minutes { 15 }
9 | status { 0 }
10 | booking_type { 0 }
11 | end
12 |
13 | factory :non_billable do
14 | minutes { 15 }
15 | booking_type { 1 }
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/spec/factories/users.rb:
--------------------------------------------------------------------------------
1 | FactoryBot.define do
2 | factory :user do
3 | sequence(:email) { |n| "email#{n}@email.com" }
4 | password { 'password' }
5 | sequence(:name) { |n| "#{n}-User" }
6 |
7 | factory :student_user do
8 | role { :student }
9 | end
10 |
11 | factory :teacher_user do
12 | role { :teacher }
13 | end
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/spec/features/create_course_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 | require_relative '../support/login_form'
3 | require_relative '../support/course_page'
4 | require_relative '../support/new_course_form'
5 |
6 | feature 'create new group/course' do
7 | let(:t1) { FactoryBot.create(:teacher_user) }
8 | let(:s1) { FactoryBot.create(:student_user) }
9 | let(:login_form) { LoginForm.new }
10 | let(:manage_my_course_page) { MyCoursePage.new }
11 | let(:new_course_form) { CourseForm.new }
12 |
13 | scenario 'authenticated and authorised user (Teacher) create course with valid data' do
14 | login_form.visit_page.login_as(t1).submit
15 |
16 | puts t1.email
17 | puts t1.password
18 | puts t1.role
19 | # expect(page).to have_content('teacher')
20 |
21 | manage_my_course_page.visit_page.new_course
22 |
23 | new_course_form.fill_form.submit
24 |
25 | expect(page).to have_content('IELTS')
26 | expect(page).to have_css('span#test-course', text: '1')
27 | expect(Group.last.enabled).to eq(true)
28 | end
29 |
30 | scenario 'Student fails to create a new course' do
31 | login_form.visit_page.login_as(s1).submit
32 |
33 | puts s1.email
34 | puts s1.password
35 | puts s1.role
36 |
37 | manage_my_course_page.student_hack_into_new_group_page
38 |
39 | # new_course_form.fill_form.submit
40 |
41 | expect(page).to have_content('you are not authorised for this action')
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/spec/features/home_page_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | feature 'home page' do
4 | scenario 'welcome message' do
5 | visit('/')
6 | expect(page).to have_content('Lessons Lab')
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/spec/fixtures/ielts_cover_image.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canriquez/rails_capstone_lessons_lab/3e563c5ac1855a0a88c95fc3c79f039db2a89061/spec/fixtures/ielts_cover_image.jpeg
--------------------------------------------------------------------------------
/spec/models/enroll_spec.rb:
--------------------------------------------------------------------------------
1 | # rubocop:disable Lint/UselessAssignment
2 | require 'rails_helper'
3 |
4 | RSpec.describe Enroll, type: :model do
5 | describe 'validations' do
6 | it 'requires student' do
7 | t1 = FactoryBot.create(:teacher_user)
8 | s1 = FactoryBot.create(:student_user)
9 | c1 = FactoryBot.create(:group_enabled, author: t1)
10 | enroll = Enroll.new(student: nil, course: c1)
11 | enroll.valid?
12 | expect(enroll.valid?).to be_falsy
13 | end
14 |
15 | it 'requires course' do
16 | t1 = FactoryBot.create(:teacher_user)
17 | s1 = FactoryBot.create(:student_user)
18 | c1 = FactoryBot.create(:group_enabled, author: t1)
19 | enroll = Enroll.new(student: s1, course: nil)
20 | enroll.valid?
21 | expect(enroll.valid?).to be_falsy
22 | end
23 | end
24 |
25 | describe 'test associations' do
26 | # testing associations with shoulda matchers
27 | it { should belong_to(:student) } # against User
28 | it { should belong_to(:course) } # against Group
29 | end
30 |
31 | describe 'test instance methods' do
32 | it 'fech current enroll count for student/course pair' do
33 | t1 = FactoryBot.create(:teacher_user)
34 | s1 = FactoryBot.create(:student_user)
35 | c1 = FactoryBot.create(:group_enabled, author: t1)
36 | e1 = FactoryBot.create(:enroll, student: s1, course: c1)
37 | total = Enroll.already_enrolled(s1, c1)
38 | expect(total).to eq(1)
39 | end
40 |
41 | it 'fech current missing enroll for student/course pair' do
42 | t1 = FactoryBot.create(:teacher_user)
43 | s1 = FactoryBot.create(:student_user)
44 | c1 = FactoryBot.create(:group_enabled, author: t1)
45 | total = Enroll.already_enrolled(s1, c1)
46 | expect(total).to eq(0)
47 | end
48 | end
49 | end
50 |
51 | # rubocop:enable Lint/UselessAssignment
52 |
--------------------------------------------------------------------------------
/spec/models/group_spec.rb:
--------------------------------------------------------------------------------
1 | # rubocop:disable Lint/UselessAssignment
2 | require 'rails_helper'
3 | RSpec.describe Group, type: :model do
4 | describe 'testing validations' do
5 | it 'requires name' do
6 | group = Group.new(name: '')
7 | group.valid?
8 | expect(group.valid?).to be_falsy
9 | end
10 |
11 | it 'requires description' do
12 | group = Group.new(description: '')
13 | group.valid?
14 | expect(group.valid?).to be_falsy
15 | end
16 |
17 | it 'requires duration' do
18 | group = Group.new(duration: '')
19 | group.valid?
20 | expect(group.valid?).to be_falsy
21 | end
22 |
23 | it 'requires price' do
24 | group = Group.new(price: '')
25 | group.valid?
26 | expect(group.valid?).to be_falsy
27 | end
28 |
29 | it 'requires starting' do
30 | group = Group.new(starting: '')
31 | group.valid?
32 | expect(group.valid?).to be_falsy
33 | end
34 |
35 | it 'requires cover_image' do
36 | group = Group.new(cover_image: '')
37 | group.valid?
38 | expect(group.valid?).to be_falsy
39 | end
40 | end
41 |
42 | describe 'testing association ' do
43 | it { should belong_to(:author) } # against User
44 | it { should have_many(:booked_sessions) } # against Transaction
45 | it { should have_many(:enrolled) } # through Transaction against Users (enrolled_students)
46 | it { should have_many(:enrollments) } # against Enroll
47 | end
48 |
49 | describe 'testing instance scopes' do
50 | it 'it provides the list enabled courses' do
51 | t1 = FactoryBot.create(:teacher_user)
52 | c1 = FactoryBot.create(:group_enabled, author: t1)
53 | total = Group.enabled.to_a
54 | expect(total.count).to eq(1)
55 | end
56 |
57 | it 'it provides the list enabled courses' do
58 | t1 = FactoryBot.create(:teacher_user)
59 | c1 = FactoryBot.create(:group_disabled, author: t1)
60 | total = Group.enabled.to_a
61 | expect(total.count).to_not eq(1)
62 | end
63 |
64 | it 'returns users within the enrolled scope in groups (courses) ' do
65 | t1 = FactoryBot.create(:teacher_user)
66 | s1 = FactoryBot.create(:student_user)
67 | c1 = FactoryBot.create(:group_enabled, author: t1)
68 | e1 = FactoryBot.create(:enroll, student: s1, course: c1)
69 | total = Group.enrolled_courses(s1).to_a
70 | expect(total.count).to eq(1)
71 | end
72 |
73 | it 'returns users within the author scope with group authored (group/courses) ' do
74 | t1 = FactoryBot.create(:teacher_user)
75 | t2 = FactoryBot.create(:teacher_user)
76 | c1 = FactoryBot.create(:group_enabled, author: t1)
77 | c1 = FactoryBot.create(:group_enabled, author: t2)
78 | total = Group.authored_courses(t1).to_a
79 | expect(total.count).to eq(1)
80 | end
81 | end
82 | end
83 | # rubocop:enable Lint/UselessAssignment
84 |
--------------------------------------------------------------------------------
/spec/models/transaction_spec.rb:
--------------------------------------------------------------------------------
1 | # rubocop:disable Lint/UselessAssignment,Layout/LineLength
2 | require 'rails_helper'
3 |
4 | RSpec.describe Transaction, type: :model do
5 | describe 'testing validations' do
6 | it 'requires booking_type' do
7 | b = Transaction.new(booking_type: '')
8 | b.valid?
9 | expect(b.valid?).to be_falsy
10 | end
11 |
12 | it 'requires minutes' do
13 | b = Transaction.new(minutes: '')
14 | b.valid?
15 | expect(b.valid?).to be_falsy
16 | end
17 |
18 | it 'requires status' do
19 | b = Transaction.new(status: '')
20 | b.valid?
21 | expect(b.valid?).to be_falsy
22 | end
23 |
24 | it 'validates presence for billable course / billable student' do
25 | t = FactoryBot.create(:teacher_user)
26 | c = FactoryBot.create(:group_enabled, author: t)
27 |
28 | b = Transaction.new(teacher_id: t, sitting_student_id: '', course_taught_id: '', minutes: 15, status: 0, booking_type: 0)
29 | b.valid?
30 | expect(b.valid?).to be_falsy
31 | end
32 | end
33 |
34 | describe 'test associations' do
35 | # testing associations with shoulda matchers
36 | it { should belong_to(:teacher) } # against User
37 |
38 | # since course_taught and Sitting_student are optional:true
39 | # association validation will fail. This is compensated by the
40 | # special presence validation on course_taught and Sitting_student
41 | # in the validation describe.
42 | end
43 |
44 | describe 'testing model scopes' do
45 | it 'it fetches not_billable transactions' do
46 | t = FactoryBot.create(:teacher_user)
47 | s = FactoryBot.create(:student_user)
48 | c = FactoryBot.create(:group_enabled, author: t)
49 | e = FactoryBot.create(:enroll, student: s, course: c)
50 | b = FactoryBot.create(:non_billable, sitting_student_id: s.id, course_taught_id: c.id)
51 | total = Transaction.not_billable.to_a
52 | expect(total.count).to eq(1)
53 | end
54 |
55 | it 'it fetches transactions order by most recent' do
56 | t = FactoryBot.create(:teacher_user)
57 | s = FactoryBot.create(:student_user)
58 | c = FactoryBot.create(:group_enabled, author: t)
59 | e = FactoryBot.create(:enroll, student: s, course: c)
60 | b1 = FactoryBot.create(:non_billable, sitting_student_id: s.id, course_taught_id: c.id)
61 | b2 = FactoryBot.create(:non_billable, sitting_student_id: s.id, course_taught_id: c.id, minutes: 99)
62 |
63 | total = Transaction.not_billable.last
64 | expect(total.minutes).to eq(99)
65 | end
66 | end
67 |
68 | describe 'testing model instance methods' do
69 | it 'fetches the list of billable transactions (bookings) for a teacher' do
70 | t1 = FactoryBot.create(:teacher_user)
71 | s1 = FactoryBot.create(:student_user)
72 | c1 = FactoryBot.create(:group_enabled, author: t1)
73 | e1 = FactoryBot.create(:enroll, student: s1, course: c1)
74 | b1 = FactoryBot.create(:billable, sitting_student_id: s1.id, course_taught_id: c1.id)
75 | b1 = FactoryBot.create(:billable, sitting_student_id: s1.id, course_taught_id: c1.id)
76 | b1 = FactoryBot.create(:billable, sitting_student_id: s1.id, course_taught_id: c1.id)
77 | total = Transaction.billable(t1).to_a
78 | expect(total.count).to eq(3)
79 | end
80 |
81 | it 'fetches the list of billable transactions (bookings) for a student' do
82 | t1 = FactoryBot.create(:teacher_user)
83 | s1 = FactoryBot.create(:student_user)
84 | s2 = FactoryBot.create(:student_user)
85 | c1 = FactoryBot.create(:group_enabled, author: t1)
86 | e1 = FactoryBot.create(:enroll, student: s1, course: c1)
87 | e1 = FactoryBot.create(:enroll, student: s2, course: c1)
88 | b1 = FactoryBot.create(:billable, sitting_student_id: s1.id, course_taught_id: c1.id)
89 | b2 = FactoryBot.create(:billable, sitting_student_id: s1.id, course_taught_id: c1.id)
90 | b3 = FactoryBot.create(:billable, sitting_student_id: s2.id, course_taught_id: c1.id)
91 | total = Transaction.student_billable(s1).to_a
92 | expect(total.count).to eq(2)
93 | end
94 | end
95 | end
96 |
97 | # rubocop:enable Lint/UselessAssignment,Layout/LineLength
98 |
--------------------------------------------------------------------------------
/spec/models/user_spec.rb:
--------------------------------------------------------------------------------
1 | # rubocop:disable Lint/UselessAssignment
2 | require 'rails_helper'
3 |
4 | RSpec.describe User, type: :model do
5 | describe 'validations' do
6 | it 'requires name' do
7 | user = User.new(name: '')
8 | user.valid?
9 | expect(user.valid?).to be_falsy
10 | end
11 |
12 | it 'requires role' do
13 | user = User.new(role: '')
14 | user.valid?
15 | expect(user.valid?).to be_falsy
16 | end
17 |
18 | it 'requires email' do
19 | user = User.new(email: '')
20 | user.valid?
21 | expect(user.valid?).to be_falsy
22 | end
23 |
24 | it 'requires valid email' do
25 | user = User.new(email: 'dasdasd')
26 | user.valid?
27 | expect(user.valid?).to be_falsy
28 | end
29 |
30 | it 'has many enrolled courses' do
31 | t1 = FactoryBot.create(:teacher_user)
32 | s1 = FactoryBot.create(:student_user)
33 | c1 = FactoryBot.create(:group_enabled, author: t1)
34 | c2 = FactoryBot.create(:group_enabled, author: t1)
35 | e1 = FactoryBot.create(:enroll, student: s1, course: c1)
36 | e2 = FactoryBot.create(:enroll, student: s1, course: c2)
37 | expect(e2.valid?).to_not be_falsy
38 | end
39 |
40 | it 'has many authored groups (courses)' do
41 | t1 = FactoryBot.create(:teacher_user)
42 | c1 = FactoryBot.create(:group_enabled, author: t1)
43 | c2 = FactoryBot.create(:group_enabled, author: t1)
44 | expect(c2.valid?).to_not be_falsy
45 | end
46 |
47 | it 'has many transactions ( taught sessions - bookings)' do
48 | t1 = FactoryBot.create(:teacher_user)
49 | s1 = FactoryBot.create(:student_user)
50 | c1 = FactoryBot.create(:group_enabled, author: t1)
51 | e1 = FactoryBot.create(:enroll, student: s1, course: c1)
52 |
53 | b1 = FactoryBot.create(:billable, sitting_student: s1, course_taught: c1, teacher: t1)
54 | b2 = FactoryBot.create(:billable, sitting_student: s1, course_taught: c1, teacher: t1)
55 | expect(b2.valid?).to_not be_falsy
56 | end
57 | end
58 |
59 | describe 'testing associations using shoulda-matchers' do
60 | # testing associations with shoulda matchers
61 | it { should have_many(:authored_courses) } # against Group
62 | it { should have_many(:taught_sessions) } # against Transactions
63 | it { should have_many(:enrolled_courses) } # against Enroll
64 | it { should have_many(:my_courses) } # against Transactions
65 | end
66 |
67 | describe 'testing model instance enum and methods ' do
68 | it 'it provides the list of users role: teacher' do
69 | t1 = FactoryBot.create(:teacher_user)
70 | total = User.teacher.to_a
71 | expect(total.count).to eq(1)
72 | end
73 |
74 | it 'it provides the list of users role: student' do
75 | t1 = FactoryBot.create(:student_user)
76 | total = User.teacher.to_a
77 | expect(total.count).to_not eq(1)
78 | end
79 |
80 | it 'capitlizes names before saving' do
81 | t1 = FactoryBot.create(:teacher_user, name: 'pedro')
82 | puts t1.name
83 | expect(t1.name).to eq('Pedro')
84 | end
85 |
86 | it 'responds true if user enrolled in a course' do
87 | t1 = FactoryBot.create(:teacher_user)
88 | s1 = FactoryBot.create(:student_user)
89 | c1 = FactoryBot.create(:group_enabled, author: t1)
90 | e1 = FactoryBot.create(:enroll, student: s1, course: c1)
91 |
92 | expect(s1.enrolled(c1)).to be_truthy
93 | end
94 |
95 | it 'fetches the list of users enrolled in one course' do
96 | t1 = FactoryBot.create(:teacher_user)
97 | s1 = FactoryBot.create(:student_user)
98 | s2 = FactoryBot.create(:student_user)
99 | c1 = FactoryBot.create(:group_enabled, author: t1)
100 | c2 = FactoryBot.create(:group_enabled, author: t1)
101 | e1 = FactoryBot.create(:enroll, student: s1, course: c1)
102 | e2 = FactoryBot.create(:enroll, student: s2, course: c1)
103 | total = User.enrolled_list(c1).to_a
104 | expect(total.count).to eq(2)
105 | end
106 |
107 | it 'fetches the list of users available for enroll to a couese' do
108 | t1 = FactoryBot.create(:teacher_user)
109 | s1 = FactoryBot.create(:student_user)
110 | s2 = FactoryBot.create(:student_user)
111 | s3 = FactoryBot.create(:student_user)
112 | c1 = FactoryBot.create(:group_enabled, author: t1)
113 | e1 = FactoryBot.create(:enroll, student: s1, course: c1)
114 | total = User.to_enroll(c1).to_a
115 | total.each { |x| puts x.id }
116 | enroll_list = Enroll.all.to_a
117 | enroll_list.each { |x| puts x.student_id }
118 | expect(total.count).to eq(2)
119 | end
120 | end
121 | end
122 |
123 | # rubocop:enable Lint/UselessAssignment
124 |
--------------------------------------------------------------------------------
/spec/rails_helper.rb:
--------------------------------------------------------------------------------
1 | # This file is copied to spec/ when you run 'rails generate rspec:install'
2 | require 'spec_helper'
3 | ENV['RAILS_ENV'] ||= 'test'
4 | require File.expand_path('../config/environment', __dir__)
5 | # Prevent database truncation if the environment is production
6 | abort('The Rails environment is running in production mode!') if Rails.env.production?
7 | require 'rspec/rails'
8 | require 'shoulda/matchers'
9 | require 'capybara'
10 | require 'devise'
11 | # Add additional requires below this line. Rails is not loaded until this point!
12 |
13 | require 'support/database_cleaner'
14 |
15 | # Requires supporting ruby files with custom matchers and macros, etc, in
16 | # spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
17 | # run as spec files by default. This means that files in spec/support that end
18 | # in _spec.rb will both be required and run as specs, causing the specs to be
19 | # run twice. It is recommended that you do not name files matching this glob to
20 | # end with _spec.rb. You can configure this pattern with the --pattern
21 | # option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
22 | #
23 | # The following line is provided for convenience purposes. It has the downside
24 | # of increasing the boot-up time by auto-requiring all files in the support
25 | # directory. Alternatively, in the individual `*_spec.rb` files, manually
26 | # require only the support files necessary.
27 | #
28 | # Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f }
29 |
30 | # Checks for pending migrations and applies them before tests are run.
31 | # If you are not using ActiveRecord, you can remove these lines.
32 | begin
33 | ActiveRecord::Migration.maintain_test_schema!
34 | rescue ActiveRecord::PendingMigrationError => e
35 | puts e.to_s.strip
36 | exit 1
37 | end
38 | RSpec.configure do |config|
39 | # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
40 | config.fixture_path = "#{::Rails.root}/spec/fixtures"
41 |
42 | # If you're not using ActiveRecord, or you'd prefer not to run each of your
43 | # examples within a transaction, remove the following line or assign false
44 | # instead of true.
45 | config.use_transactional_fixtures = false
46 |
47 | # You can uncomment this line to turn off ActiveRecord support entirely.
48 | # config.use_active_record = false
49 |
50 | Capybara.javascript_driver = :webkit
51 | # RSpec Rails can automatically mix in different behaviours to your tests
52 | # based on their file location, for example enabling you to call `get` and
53 | # `post` in specs under `spec/controllers`.
54 | #
55 | # You can disable this behaviour by removing the line below, and instead
56 | # explicitly tag your specs with their type, e.g.:
57 | #
58 | # RSpec.describe UsersController, type: :controller do
59 | # # ...
60 | # end
61 | #
62 | # The different available types are documented in the features, such as in
63 | # https://relishapp.com/rspec/rspec-rails/docs
64 | config.infer_spec_type_from_file_location!
65 |
66 | # Filter lines from Rails gems in backtraces.
67 | config.filter_rails_from_backtrace!
68 | # arbitrary gems may also be filtered via:
69 | # config.filter_gems_from_backtrace("gem name")
70 |
71 | config.include Devise::Test::IntegrationHelpers, type: :feature # this is used for acceptance tests
72 | config.include Devise::Test::ControllerHelpers, type: :controller
73 | config.include Devise::Test::ControllerHelpers, type: :view
74 |
75 | Shoulda::Matchers.configure do |conf|
76 | conf.integrate do |with|
77 | with.test_framework :rspec
78 | with.library :rails
79 | end
80 | end
81 |
82 | def wait_for_page_load(title)
83 | find('div.rspec_eyes_only', text: title)
84 | end
85 | end
86 |
--------------------------------------------------------------------------------
/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | # This file was generated by the `rails generate rspec:install` command. Conventionally, all
2 | # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3 | # The generated `.rspec` file contains `--require spec_helper` which will cause
4 | # this file to always be loaded, without a need to explicitly require it in any
5 | # files.
6 | #
7 | # Given that it is always loaded, you are encouraged to keep this file as
8 | # light-weight as possible. Requiring heavyweight dependencies from this file
9 | # will add to the boot time of your test suite on EVERY test run, even for an
10 | # individual file that may not need all of that loaded. Instead, consider making
11 | # a separate helper file that requires the additional dependencies and performs
12 | # the additional setup, and require it from the spec files that actually need
13 | # it.
14 | #
15 | # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
16 | RSpec.configure do |config|
17 | # rspec-expectations config goes here. You can use an alternate
18 | # assertion/expectation library such as wrong or the stdlib/minitest
19 | # assertions if you prefer.
20 | config.expect_with :rspec do |expectations|
21 | # This option will default to `true` in RSpec 4. It makes the `description`
22 | # and `failure_message` of custom matchers include text for helper methods
23 | # defined using `chain`, e.g.:
24 | # be_bigger_than(2).and_smaller_than(4).description
25 | # # => "be bigger than 2 and smaller than 4"
26 | # ...rather than:
27 | # # => "be bigger than 2"
28 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true
29 | end
30 |
31 | # rspec-mocks config goes here. You can use an alternate test double
32 | # library (such as bogus or mocha) by changing the `mock_with` option here.
33 | config.mock_with :rspec do |mocks|
34 | # Prevents you from mocking or stubbing a method that does not exist on
35 | # a real object. This is generally recommended, and will default to
36 | # `true` in RSpec 4.
37 | mocks.verify_partial_doubles = true
38 | end
39 |
40 | # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
41 | # have no way to turn it off -- the option exists only for backwards
42 | # compatibility in RSpec 3). It causes shared context metadata to be
43 | # inherited by the metadata hash of host groups and examples, rather than
44 | # triggering implicit auto-inclusion in groups with matching metadata.
45 | config.shared_context_metadata_behavior = :apply_to_host_groups
46 |
47 | # The settings below are suggested to provide a good initial experience
48 | # with RSpec, but feel free to customize to your heart's content.
49 | # # This allows you to limit a spec run to individual examples or groups
50 | # # you care about by tagging them with `:focus` metadata. When nothing
51 | # # is tagged with `:focus`, all examples get run. RSpec also provides
52 | # # aliases for `it`, `describe`, and `context` that include `:focus`
53 | # # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
54 | # config.filter_run_when_matching :focus
55 | #
56 | # # Allows RSpec to persist some state between runs in order to support
57 | # # the `--only-failures` and `--next-failure` CLI options. We recommend
58 | # # you configure your source control system to ignore this file.
59 | # config.example_status_persistence_file_path = "spec/examples.txt"
60 | #
61 | # # Limits the available syntax to the non-monkey patched syntax that is
62 | # # recommended. For more details, see:
63 | # # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
64 | # # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
65 | # # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
66 | # config.disable_monkey_patching!
67 | #
68 | # # Many RSpec users commonly either run the entire suite or an individual
69 | # # file, and it's useful to allow more verbose output when running an
70 | # # individual spec file.
71 | # if config.files_to_run.one?
72 | # # Use the documentation formatter for detailed output,
73 | # # unless a formatter has already been configured
74 | # # (e.g. via a command-line flag).
75 | # config.default_formatter = "doc"
76 | # end
77 | #
78 | # # Print the 10 slowest examples and example groups at the
79 | # # end of the spec run, to help surface which specs are running
80 | # # particularly slow.
81 | # config.profile_examples = 10
82 | #
83 | # # Run specs in random order to surface order dependencies. If you find an
84 | # # order dependency and want to debug it, you can fix the order by providing
85 | # # the seed, which is printed after each run.
86 | # # --seed 1234
87 | # config.order = :random
88 | #
89 | # # Seed global randomization in this process using the `--seed` CLI option.
90 | # # Setting this allows you to use `--seed` to deterministically reproduce
91 | # # test failures related to randomization by passing the same `--seed` value
92 | # # as the one that triggered the failure.
93 | # Kernel.srand config.seed
94 | end
95 |
--------------------------------------------------------------------------------
/spec/support/course_page.rb:
--------------------------------------------------------------------------------
1 | class MyCoursePage
2 | include Capybara::DSL
3 |
4 | def visit_page
5 | visit('/groups')
6 | self
7 | end
8 |
9 | def new_course
10 | click_on('Add New Course')
11 | self
12 | end
13 |
14 | def edit_course
15 | find(:css, '.edit-test').click
16 | self
17 | end
18 |
19 | def student_hack_into_new_group_page
20 | visit('/groups/new')
21 | self
22 | end
23 |
24 | def select_student_to_enroll
25 | find('.custom-select').trigger(:click)
26 | all(:css, '.enroll')[0].select('student-99')
27 | click_on('edit')
28 | self
29 | end
30 | end
31 |
--------------------------------------------------------------------------------
/spec/support/database_cleaner.rb:
--------------------------------------------------------------------------------
1 | RSpec.configure do |config|
2 | config.before(:suite) do
3 | DatabaseCleaner.clean_with :truncation, except: %w[ar_internal_metadata]
4 | end
5 |
6 | config.before(:each) do
7 | DatabaseCleaner.strategy = :transaction
8 | end
9 |
10 | config.before(:each) do
11 | DatabaseCleaner.start
12 | end
13 |
14 | config.after(:each) do
15 | DatabaseCleaner.clean
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/spec/support/login_form.rb:
--------------------------------------------------------------------------------
1 | class LoginForm
2 | include Capybara::DSL
3 |
4 | def visit_page
5 | visit('/users/sign_in')
6 | self
7 | end
8 |
9 | def login_as(user)
10 | fill_in('Email', with: user.email)
11 | fill_in('Password', with: user.password)
12 | self
13 | end
14 |
15 | def submit
16 | click_on('Log in')
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/spec/support/new_course_form.rb:
--------------------------------------------------------------------------------
1 | class CourseForm
2 | include Capybara::DSL
3 |
4 | def fill_form(_attrs = {})
5 | fill_in('Course Name', with: 'IELTS')
6 | fill_in('Description', with: 'this is a dummy description for testing purposes only')
7 | select('45', from: 'Duration')
8 | fill_in('Price', with: 'Price')
9 | check('Online Session')
10 | check('Presencial Session')
11 | check('Enable Course')
12 | fill_in('Starting from', with: '05/08/2020')
13 | attach_file('Course Image', "#{Rails.root}/spec/fixtures/ielts_cover_image.jpeg")
14 | self
15 | end
16 |
17 | def fill_form_edit(name)
18 | fill_in('Course Name', with: name)
19 | fill_in('Description', with: 'this is a dummy description for testing purposes only')
20 | select('45', from: 'Duration')
21 | fill_in('Price', with: 'Price')
22 | check('Online Session')
23 | check('Presencial Session')
24 | check('Enable Course')
25 | fill_in('Starting from', with: '05/08/2020')
26 | attach_file('Course Image', "#{Rails.root}/spec/fixtures/ielts_cover_image.jpeg")
27 | self
28 | end
29 |
30 | def submit
31 | click_on('Save Course')
32 | end
33 | end
34 |
--------------------------------------------------------------------------------
/storage/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canriquez/rails_capstone_lessons_lab/3e563c5ac1855a0a88c95fc3c79f039db2a89061/storage/.keep
--------------------------------------------------------------------------------
/tmp/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canriquez/rails_capstone_lessons_lab/3e563c5ac1855a0a88c95fc3c79f039db2a89061/tmp/.keep
--------------------------------------------------------------------------------
/vendor/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canriquez/rails_capstone_lessons_lab/3e563c5ac1855a0a88c95fc3c79f039db2a89061/vendor/.keep
--------------------------------------------------------------------------------