+ <% @tasks.pending.each do |task| %>
+ <%= render "tasks/task", task: task %>
+ <% end %>
+
+
+
+
+
+
+
+ Completed
+
+
+ <% @tasks.complete.each do |task| %>
+ <%= render "tasks/task", task: task %>
+ <% end %>
+
+
+
+
diff --git a/app/views/tasks/index.json.jbuilder b/app/views/tasks/index.json.jbuilder
new file mode 100644
index 0000000..7481994
--- /dev/null
+++ b/app/views/tasks/index.json.jbuilder
@@ -0,0 +1 @@
+json.array! @tasks, partial: "tasks/task", as: :task
diff --git a/app/views/tasks/move.js.erb b/app/views/tasks/move.js.erb
new file mode 100644
index 0000000..96ac7d9
--- /dev/null
+++ b/app/views/tasks/move.js.erb
@@ -0,0 +1,3 @@
+$("#<%= dom_id @task %>").remove();
+var moved_task = $("<%= j(render @task) %>");
+$("#<%= @task.status%>_list").prepend(moved_task);
diff --git a/app/views/tasks/show.json.jbuilder b/app/views/tasks/show.json.jbuilder
new file mode 100644
index 0000000..fd8232f
--- /dev/null
+++ b/app/views/tasks/show.json.jbuilder
@@ -0,0 +1 @@
+json.partial! "tasks/task", task: @task
diff --git a/app/views/tasks/update.js.erb b/app/views/tasks/update.js.erb
new file mode 100644
index 0000000..c613862
--- /dev/null
+++ b/app/views/tasks/update.js.erb
@@ -0,0 +1 @@
+$("#<%= dom_id @task, :form %>").replaceWith("<%= j(render @task)%>");
diff --git a/config/environments/development.rb b/config/environments/development.rb
index a711738..5956d1e 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -1,11 +1,12 @@
require "active_support/core_ext/integer/time"
Rails.application.configure do
+ config.action_mailer.default_url_options = { host: "localhost", port: 3000 }
# Settings specified here will take precedence over those in config/application.rb.
config.hosts.clear
# Allow all Gitpod IPs to render the BetterErrors page
- config.web_console.whitelisted_ips = '0.0.0.0/0.0.0.0'
- BetterErrors::Middleware.allow_ip! '0.0.0.0/0.0.0.0'
+ config.web_console.whitelisted_ips = "0.0.0.0/0.0.0.0"
+ BetterErrors::Middleware.allow_ip! "0.0.0.0/0.0.0.0"
# In the development environment your application's code is reloaded any time
# it changes. This slows down response time but is perfect for development
# since you don't have to restart the web server when you make code changes.
@@ -19,13 +20,13 @@
# Enable/disable caching. By default caching is disabled.
# Run rails dev:cache to toggle caching.
- if Rails.root.join('tmp', 'caching-dev.txt').exist?
+ if Rails.root.join("tmp", "caching-dev.txt").exist?
config.action_controller.perform_caching = true
config.action_controller.enable_fragment_cache_logging = true
config.cache_store = :memory_store
config.public_file_server.headers = {
- 'Cache-Control' => "public, max-age=#{2.days.to_i}"
+ "Cache-Control" => "public, max-age=#{2.days.to_i}",
}
else
config.action_controller.perform_caching = false
diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb
new file mode 100644
index 0000000..2ed5596
--- /dev/null
+++ b/config/initializers/devise.rb
@@ -0,0 +1,311 @@
+# frozen_string_literal: true
+
+# Assuming you have not yet modified this file, each configuration option below
+# is set to its default value. Note that some are commented out while others
+# are not: uncommented lines are intended to protect your configuration from
+# breaking changes in upgrades (i.e., in the event that future versions of
+# Devise change the default values for those options).
+#
+# Use this hook to configure devise mailer, warden hooks and so forth.
+# Many of these configuration options can be set straight in your model.
+Devise.setup do |config|
+ # The secret key used by Devise. Devise uses this key to generate
+ # random tokens. Changing this key will render invalid all existing
+ # confirmation, reset password and unlock tokens in the database.
+ # Devise will use the `secret_key_base` as its `secret_key`
+ # by default. You can change it below and use your own secret key.
+ # config.secret_key = 'd747a8fe0f5da3761acb7a78b71232f16bc0d22196ec268865c427d972dd3926d17d5d85a40d6191c8de1e093f142041d32f070514a7240197380aa734037af9'
+
+ # ==> Controller configuration
+ # Configure the parent class to the devise controllers.
+ # config.parent_controller = 'DeviseController'
+
+ # ==> Mailer Configuration
+ # Configure the e-mail address which will be shown in Devise::Mailer,
+ # note that it will be overwritten if you use your own mailer class
+ # with default "from" parameter.
+ config.mailer_sender = 'please-change-me-at-config-initializers-devise@example.com'
+
+ # Configure the class responsible to send e-mails.
+ # config.mailer = 'Devise::Mailer'
+
+ # Configure the parent class responsible to send e-mails.
+ # config.parent_mailer = 'ActionMailer::Base'
+
+ # ==> ORM configuration
+ # Load and configure the ORM. Supports :active_record (default) and
+ # :mongoid (bson_ext recommended) by default. Other ORMs may be
+ # available as additional gems.
+ require 'devise/orm/active_record'
+
+ # ==> Configuration for any authentication mechanism
+ # Configure which keys are used when authenticating a user. The default is
+ # just :email. You can configure it to use [:username, :subdomain], so for
+ # authenticating a user, both parameters are required. Remember that those
+ # parameters are used only when authenticating and not when retrieving from
+ # session. If you need permissions, you should implement that in a before filter.
+ # You can also supply a hash where the value is a boolean determining whether
+ # or not authentication should be aborted when the value is not present.
+ # config.authentication_keys = [:email]
+
+ # Configure parameters from the request object used for authentication. Each entry
+ # given should be a request method and it will automatically be passed to the
+ # find_for_authentication method and considered in your model lookup. For instance,
+ # if you set :request_keys to [:subdomain], :subdomain will be used on authentication.
+ # The same considerations mentioned for authentication_keys also apply to request_keys.
+ # config.request_keys = []
+
+ # Configure which authentication keys should be case-insensitive.
+ # These keys will be downcased upon creating or modifying a user and when used
+ # to authenticate or find a user. Default is :email.
+ config.case_insensitive_keys = [:email]
+
+ # Configure which authentication keys should have whitespace stripped.
+ # These keys will have whitespace before and after removed upon creating or
+ # modifying a user and when used to authenticate or find a user. Default is :email.
+ config.strip_whitespace_keys = [:email]
+
+ # Tell if authentication through request.params is enabled. True by default.
+ # It can be set to an array that will enable params authentication only for the
+ # given strategies, for example, `config.params_authenticatable = [:database]` will
+ # enable it only for database (email + password) authentication.
+ # config.params_authenticatable = true
+
+ # Tell if authentication through HTTP Auth is enabled. False by default.
+ # It can be set to an array that will enable http authentication only for the
+ # given strategies, for example, `config.http_authenticatable = [:database]` will
+ # enable it only for database authentication.
+ # For API-only applications to support authentication "out-of-the-box", you will likely want to
+ # enable this with :database unless you are using a custom strategy.
+ # The supported strategies are:
+ # :database = Support basic authentication with authentication key + password
+ # config.http_authenticatable = false
+
+ # If 401 status code should be returned for AJAX requests. True by default.
+ # config.http_authenticatable_on_xhr = true
+
+ # The realm used in Http Basic Authentication. 'Application' by default.
+ # config.http_authentication_realm = 'Application'
+
+ # It will change confirmation, password recovery and other workflows
+ # to behave the same regardless if the e-mail provided was right or wrong.
+ # Does not affect registerable.
+ # config.paranoid = true
+
+ # By default Devise will store the user in session. You can skip storage for
+ # particular strategies by setting this option.
+ # Notice that if you are skipping storage for all authentication paths, you
+ # may want to disable generating routes to Devise's sessions controller by
+ # passing skip: :sessions to `devise_for` in your config/routes.rb
+ config.skip_session_storage = [:http_auth]
+
+ # By default, Devise cleans up the CSRF token on authentication to
+ # avoid CSRF token fixation attacks. This means that, when using AJAX
+ # requests for sign in and sign up, you need to get a new CSRF token
+ # from the server. You can disable this option at your own risk.
+ # config.clean_up_csrf_token_on_authentication = true
+
+ # When false, Devise will not attempt to reload routes on eager load.
+ # This can reduce the time taken to boot the app but if your application
+ # requires the Devise mappings to be loaded during boot time the application
+ # won't boot properly.
+ # config.reload_routes = true
+
+ # ==> Configuration for :database_authenticatable
+ # For bcrypt, this is the cost for hashing the password and defaults to 12. If
+ # using other algorithms, it sets how many times you want the password to be hashed.
+ # The number of stretches used for generating the hashed password are stored
+ # with the hashed password. This allows you to change the stretches without
+ # invalidating existing passwords.
+ #
+ # Limiting the stretches to just one in testing will increase the performance of
+ # your test suite dramatically. However, it is STRONGLY RECOMMENDED to not use
+ # a value less than 10 in other environments. Note that, for bcrypt (the default
+ # algorithm), the cost increases exponentially with the number of stretches (e.g.
+ # a value of 20 is already extremely slow: approx. 60 seconds for 1 calculation).
+ config.stretches = Rails.env.test? ? 1 : 12
+
+ # Set up a pepper to generate the hashed password.
+ # config.pepper = 'ca40c7426d591addd65575d5fa4100750b5d0d2a98d3f9a35056b358c1327c3650ba9d3732c827841fe4df00c59117627663a0e8237682c7050e458092a69ee8'
+
+ # Send a notification to the original email when the user's email is changed.
+ # config.send_email_changed_notification = false
+
+ # Send a notification email when the user's password is changed.
+ # config.send_password_change_notification = false
+
+ # ==> Configuration for :confirmable
+ # A period that the user is allowed to access the website even without
+ # confirming their account. For instance, if set to 2.days, the user will be
+ # able to access the website for two days without confirming their account,
+ # access will be blocked just in the third day.
+ # You can also set it to nil, which will allow the user to access the website
+ # without confirming their account.
+ # Default is 0.days, meaning the user cannot access the website without
+ # confirming their account.
+ # config.allow_unconfirmed_access_for = 2.days
+
+ # A period that the user is allowed to confirm their account before their
+ # token becomes invalid. For example, if set to 3.days, the user can confirm
+ # their account within 3 days after the mail was sent, but on the fourth day
+ # their account can't be confirmed with the token any more.
+ # Default is nil, meaning there is no restriction on how long a user can take
+ # before confirming their account.
+ # config.confirm_within = 3.days
+
+ # If true, requires any email changes to be confirmed (exactly the same way as
+ # initial account confirmation) to be applied. Requires additional unconfirmed_email
+ # db field (see migrations). Until confirmed, new email is stored in
+ # unconfirmed_email column, and copied to email column on successful confirmation.
+ config.reconfirmable = true
+
+ # Defines which key will be used when confirming an account
+ # config.confirmation_keys = [:email]
+
+ # ==> Configuration for :rememberable
+ # The time the user will be remembered without asking for credentials again.
+ # config.remember_for = 2.weeks
+
+ # Invalidates all the remember me tokens when the user signs out.
+ config.expire_all_remember_me_on_sign_out = true
+
+ # If true, extends the user's remember period when remembered via cookie.
+ # config.extend_remember_period = false
+
+ # Options to be passed to the created cookie. For instance, you can set
+ # secure: true in order to force SSL only cookies.
+ # config.rememberable_options = {}
+
+ # ==> Configuration for :validatable
+ # Range for password length.
+ config.password_length = 6..128
+
+ # Email regex used to validate email formats. It simply asserts that
+ # one (and only one) @ exists in the given string. This is mainly
+ # to give user feedback and not to assert the e-mail validity.
+ config.email_regexp = /\A[^@\s]+@[^@\s]+\z/
+
+ # ==> Configuration for :timeoutable
+ # The time you want to timeout the user session without activity. After this
+ # time the user will be asked for credentials again. Default is 30 minutes.
+ # config.timeout_in = 30.minutes
+
+ # ==> Configuration for :lockable
+ # Defines which strategy will be used to lock an account.
+ # :failed_attempts = Locks an account after a number of failed attempts to sign in.
+ # :none = No lock strategy. You should handle locking by yourself.
+ # config.lock_strategy = :failed_attempts
+
+ # Defines which key will be used when locking and unlocking an account
+ # config.unlock_keys = [:email]
+
+ # Defines which strategy will be used to unlock an account.
+ # :email = Sends an unlock link to the user email
+ # :time = Re-enables login after a certain amount of time (see :unlock_in below)
+ # :both = Enables both strategies
+ # :none = No unlock strategy. You should handle unlocking by yourself.
+ # config.unlock_strategy = :both
+
+ # Number of authentication tries before locking an account if lock_strategy
+ # is failed attempts.
+ # config.maximum_attempts = 20
+
+ # Time interval to unlock the account if :time is enabled as unlock_strategy.
+ # config.unlock_in = 1.hour
+
+ # Warn on the last attempt before the account is locked.
+ # config.last_attempt_warning = true
+
+ # ==> Configuration for :recoverable
+ #
+ # Defines which key will be used when recovering the password for an account
+ # config.reset_password_keys = [:email]
+
+ # Time interval you can reset your password with a reset password key.
+ # Don't put a too small interval or your users won't have the time to
+ # change their passwords.
+ config.reset_password_within = 6.hours
+
+ # When set to false, does not sign a user in automatically after their password is
+ # reset. Defaults to true, so a user is signed in automatically after a reset.
+ # config.sign_in_after_reset_password = true
+
+ # ==> Configuration for :encryptable
+ # Allow you to use another hashing or encryption algorithm besides bcrypt (default).
+ # You can use :sha1, :sha512 or algorithms from others authentication tools as
+ # :clearance_sha1, :authlogic_sha512 (then you should set stretches above to 20
+ # for default behavior) and :restful_authentication_sha1 (then you should set
+ # stretches to 10, and copy REST_AUTH_SITE_KEY to pepper).
+ #
+ # Require the `devise-encryptable` gem when using anything other than bcrypt
+ # config.encryptor = :sha512
+
+ # ==> Scopes configuration
+ # Turn scoped views on. Before rendering "sessions/new", it will first check for
+ # "users/sessions/new". It's turned off by default because it's slower if you
+ # are using only default views.
+ # config.scoped_views = false
+
+ # Configure the default scope given to Warden. By default it's the first
+ # devise role declared in your routes (usually :user).
+ # config.default_scope = :user
+
+ # Set this configuration to false if you want /users/sign_out to sign out
+ # only the current scope. By default, Devise signs out all scopes.
+ # config.sign_out_all_scopes = true
+
+ # ==> Navigation configuration
+ # Lists the formats that should be treated as navigational. Formats like
+ # :html, should redirect to the sign in page when the user does not have
+ # access, but formats like :xml or :json, should return 401.
+ #
+ # If you have any extra navigational formats, like :iphone or :mobile, you
+ # should add them to the navigational formats lists.
+ #
+ # The "*/*" below is required to match Internet Explorer requests.
+ # config.navigational_formats = ['*/*', :html]
+
+ # The default HTTP method used to sign out a resource. Default is :delete.
+ config.sign_out_via = :delete
+
+ # ==> OmniAuth
+ # Add a new OmniAuth provider. Check the wiki for more information on setting
+ # up on your models and hooks.
+ # config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo'
+
+ # ==> Warden configuration
+ # If you want to use other strategies, that are not supported by Devise, or
+ # change the failure app, you can configure them inside the config.warden block.
+ #
+ # config.warden do |manager|
+ # manager.intercept_401 = false
+ # manager.default_strategies(scope: :user).unshift :some_external_strategy
+ # end
+
+ # ==> Mountable engine configurations
+ # When using Devise inside an engine, let's call it `MyEngine`, and this engine
+ # is mountable, there are some extra configurations to be taken into account.
+ # The following options are available, assuming the engine is mounted as:
+ #
+ # mount MyEngine, at: '/my_engine'
+ #
+ # The router that invoked `devise_for`, in the example above, would be:
+ # config.router_name = :my_engine
+ #
+ # When using OmniAuth, Devise cannot automatically set OmniAuth path,
+ # so you need to do it manually. For the users scope, it would be:
+ # config.omniauth_path_prefix = '/my_engine/users/auth'
+
+ # ==> Turbolinks configuration
+ # If your app is using Turbolinks, Turbolinks::Controller needs to be included to make redirection work correctly:
+ #
+ # ActiveSupport.on_load(:devise_failure_app) do
+ # include Turbolinks::Controller
+ # end
+
+ # ==> Configuration for :registerable
+
+ # When set to false, does not sign a user in automatically after their password is
+ # changed. Defaults to true, so a user is signed in automatically after changing a password.
+ # config.sign_in_after_change_password = true
+end
diff --git a/config/locales/devise.en.yml b/config/locales/devise.en.yml
new file mode 100644
index 0000000..260e1c4
--- /dev/null
+++ b/config/locales/devise.en.yml
@@ -0,0 +1,65 @@
+# Additional translations at https://github.com/heartcombo/devise/wiki/I18n
+
+en:
+ devise:
+ confirmations:
+ confirmed: "Your email address has been successfully confirmed."
+ send_instructions: "You will receive an email with instructions for how to confirm your email address in a few minutes."
+ 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."
+ failure:
+ already_authenticated: "You are already signed in."
+ inactive: "Your account is not activated yet."
+ invalid: "Invalid %{authentication_keys} or password."
+ locked: "Your account is locked."
+ last_attempt: "You have one more attempt before your account is locked."
+ not_found_in_database: "Invalid %{authentication_keys} or password."
+ timeout: "Your session expired. Please sign in again to continue."
+ unauthenticated: "You need to sign in or sign up before continuing."
+ unconfirmed: "You have to confirm your email address before continuing."
+ mailer:
+ confirmation_instructions:
+ subject: "Confirmation instructions"
+ reset_password_instructions:
+ subject: "Reset password instructions"
+ unlock_instructions:
+ subject: "Unlock instructions"
+ email_changed:
+ subject: "Email Changed"
+ password_change:
+ subject: "Password Changed"
+ omniauth_callbacks:
+ failure: "Could not authenticate you from %{kind} because \"%{reason}\"."
+ success: "Successfully authenticated from %{kind} account."
+ passwords:
+ 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."
+ send_instructions: "You will receive an email with instructions on how to reset your password in a few minutes."
+ 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."
+ updated: "Your password has been changed successfully. You are now signed in."
+ updated_not_active: "Your password has been changed successfully."
+ registrations:
+ destroyed: "Bye! Your account has been successfully cancelled. We hope to see you again soon."
+ signed_up: "Welcome! You have signed up successfully."
+ signed_up_but_inactive: "You have signed up successfully. However, we could not sign you in because your account is not yet activated."
+ signed_up_but_locked: "You have signed up successfully. However, we could not sign you in because your account is locked."
+ 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."
+ 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."
+ updated: "Your account has been updated successfully."
+ updated_but_not_signed_in: "Your account has been updated successfully, but since your password was changed, you need to sign in again."
+ sessions:
+ signed_in: "Signed in successfully."
+ signed_out: "Signed out successfully."
+ already_signed_out: "Signed out successfully."
+ unlocks:
+ send_instructions: "You will receive an email with instructions for how to unlock your account in a few minutes."
+ send_paranoid_instructions: "If your account exists, you will receive an email with instructions for how to unlock it in a few minutes."
+ unlocked: "Your account has been unlocked successfully. Please sign in to continue."
+ errors:
+ messages:
+ already_confirmed: "was already confirmed, please try signing in"
+ confirmation_period_expired: "needs to be confirmed within %{period}, please request a new one"
+ expired: "has expired, please request a new one"
+ not_found: "not found"
+ not_locked: "was not locked"
+ not_saved:
+ one: "1 error prohibited this %{resource} from being saved:"
+ other: "%{count} errors prohibited this %{resource} from being saved:"
diff --git a/config/routes.rb b/config/routes.rb
index c06383a..b948579 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -1,3 +1,9 @@
Rails.application.routes.draw do
+ resources :tasks do
+ patch "move", on: :member
+ end
+
+ devise_for :users
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
+ root "tasks#index"
end
diff --git a/db/migrate/20230122014735_devise_create_users.rb b/db/migrate/20230122014735_devise_create_users.rb
new file mode 100644
index 0000000..bd2bb97
--- /dev/null
+++ b/db/migrate/20230122014735_devise_create_users.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+class DeviseCreateUsers < ActiveRecord::Migration[6.1]
+ def change
+ enable_extension("citext")
+ create_table :users do |t|
+ ## Database authenticatable
+ t.string :email, null: false, default: ""
+ t.string :encrypted_password, null: false, default: ""
+
+ ## Recoverable
+ t.string :reset_password_token
+ t.datetime :reset_password_sent_at
+
+ ## Rememberable
+ t.datetime :remember_created_at
+
+ ## Trackable
+ # t.integer :sign_in_count, default: 0, null: false
+ # t.datetime :current_sign_in_at
+ # t.datetime :last_sign_in_at
+ # t.string :current_sign_in_ip
+ # t.string :last_sign_in_ip
+
+ ## Confirmable
+ # t.string :confirmation_token
+ # t.datetime :confirmed_at
+ # t.datetime :confirmation_sent_at
+ # t.string :unconfirmed_email # Only if using reconfirmable
+
+ ## Lockable
+ # t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
+ # t.string :unlock_token # Only if unlock strategy is :email or :both
+ # t.datetime :locked_at
+
+ t.citext :username
+
+ t.timestamps null: false
+ end
+
+ add_index :users, :email, unique: true
+ add_index :users, :reset_password_token, unique: true
+ add_index :users, :username, unique: true
+ # add_index :users, :confirmation_token, unique: true
+ # add_index :users, :unlock_token, unique: true
+ end
+end
diff --git a/db/migrate/20230122015942_create_tasks.rb b/db/migrate/20230122015942_create_tasks.rb
new file mode 100644
index 0000000..89c4ad6
--- /dev/null
+++ b/db/migrate/20230122015942_create_tasks.rb
@@ -0,0 +1,9 @@
+class CreateTasks < ActiveRecord::Migration[6.1]
+ def change
+ create_table :tasks do |t|
+ t.belongs_to :owner, null: false, foreign_key: { to_table: :users }
+ t.text :body
+ t.timestamps
+ end
+ end
+end
diff --git a/db/migrate/20230122022537_add_status_to_tasks.rb b/db/migrate/20230122022537_add_status_to_tasks.rb
new file mode 100644
index 0000000..c695c9e
--- /dev/null
+++ b/db/migrate/20230122022537_add_status_to_tasks.rb
@@ -0,0 +1,5 @@
+class AddStatusToTasks < ActiveRecord::Migration[6.1]
+ def change
+ add_column :tasks, :status, :string
+ end
+end
diff --git a/db/migrate/20230122023948_change_default_status_of_tasks.rb b/db/migrate/20230122023948_change_default_status_of_tasks.rb
new file mode 100644
index 0000000..b42fc30
--- /dev/null
+++ b/db/migrate/20230122023948_change_default_status_of_tasks.rb
@@ -0,0 +1,5 @@
+class ChangeDefaultStatusOfTasks < ActiveRecord::Migration[6.1]
+ def change
+ change_column_default :tasks, :status, "new"
+ end
+end
diff --git a/db/migrate/20230122024241_change_default_status_on_tasks.rb b/db/migrate/20230122024241_change_default_status_on_tasks.rb
new file mode 100644
index 0000000..bbbe4aa
--- /dev/null
+++ b/db/migrate/20230122024241_change_default_status_on_tasks.rb
@@ -0,0 +1,5 @@
+class ChangeDefaultStatusOnTasks < ActiveRecord::Migration[6.1]
+ def change
+ change_column_default :tasks, :status, "notstarted"
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
new file mode 100644
index 0000000..8320154
--- /dev/null
+++ b/db/schema.rb
@@ -0,0 +1,43 @@
+# This file is auto-generated from the current state of the database. Instead
+# of editing this file, please use the migrations feature of Active Record to
+# incrementally modify your database, and then regenerate this schema definition.
+#
+# This file is the source Rails uses to define your schema when running `bin/rails
+# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
+# be faster and is potentially less error prone than running all of your
+# migrations from scratch. Old migrations may fail to apply correctly if those
+# migrations use external dependencies or application code.
+#
+# It's strongly recommended that you check this file into your version control system.
+
+ActiveRecord::Schema.define(version: 2023_01_22_024241) do
+
+ # These are extensions that must be enabled in order to support this database
+ enable_extension "citext"
+ enable_extension "plpgsql"
+
+ create_table "tasks", force: :cascade do |t|
+ t.bigint "owner_id", null: false
+ t.text "body"
+ t.datetime "created_at", precision: 6, null: false
+ t.datetime "updated_at", precision: 6, null: false
+ t.string "status", default: "notstarted"
+ t.index ["owner_id"], name: "index_tasks_on_owner_id"
+ end
+
+ create_table "users", force: :cascade do |t|
+ t.string "email", default: "", null: false
+ t.string "encrypted_password", default: "", null: false
+ t.string "reset_password_token"
+ t.datetime "reset_password_sent_at"
+ t.datetime "remember_created_at"
+ t.citext "username"
+ t.datetime "created_at", precision: 6, null: false
+ t.datetime "updated_at", precision: 6, null: false
+ t.index ["email"], name: "index_users_on_email", unique: true
+ t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
+ t.index ["username"], name: "index_users_on_username", unique: true
+ end
+
+ add_foreign_key "tasks", "users", column: "owner_id"
+end
diff --git a/lib/tasks/auto_annotate_models.rake b/lib/tasks/auto_annotate_models.rake
new file mode 100644
index 0000000..e96283e
--- /dev/null
+++ b/lib/tasks/auto_annotate_models.rake
@@ -0,0 +1,59 @@
+# NOTE: only doing this in development as some production environments (Heroku)
+# NOTE: are sensitive to local FS writes, and besides -- it's just not proper
+# NOTE: to have a dev-mode tool do its thing in production.
+if Rails.env.development?
+ require 'annotate'
+ task :set_annotation_options do
+ # You can override any of these by setting an environment variable of the
+ # same name.
+ Annotate.set_defaults(
+ 'active_admin' => 'false',
+ 'additional_file_patterns' => [],
+ 'routes' => 'false',
+ 'models' => 'true',
+ 'position_in_routes' => 'before',
+ 'position_in_class' => 'before',
+ 'position_in_test' => 'before',
+ 'position_in_fixture' => 'before',
+ 'position_in_factory' => 'before',
+ 'position_in_serializer' => 'before',
+ 'show_foreign_keys' => 'true',
+ 'show_complete_foreign_keys' => 'false',
+ 'show_indexes' => 'true',
+ 'simple_indexes' => 'false',
+ 'model_dir' => 'app/models',
+ 'root_dir' => '',
+ 'include_version' => 'false',
+ 'require' => '',
+ 'exclude_tests' => 'false',
+ 'exclude_fixtures' => 'false',
+ 'exclude_factories' => 'false',
+ 'exclude_serializers' => 'false',
+ 'exclude_scaffolds' => 'true',
+ 'exclude_controllers' => 'true',
+ 'exclude_helpers' => 'true',
+ 'exclude_sti_subclasses' => 'false',
+ 'ignore_model_sub_dir' => 'false',
+ 'ignore_columns' => nil,
+ 'ignore_routes' => nil,
+ 'ignore_unknown_models' => 'false',
+ 'hide_limit_column_types' => 'integer,bigint,boolean',
+ 'hide_default_column_types' => 'json,jsonb,hstore',
+ 'skip_on_db_migrate' => 'false',
+ 'format_bare' => 'true',
+ 'format_rdoc' => 'false',
+ 'format_yard' => 'false',
+ 'format_markdown' => 'false',
+ 'sort' => 'false',
+ 'force' => 'false',
+ 'frozen' => 'false',
+ 'classified_sort' => 'true',
+ 'trace' => 'false',
+ 'wrapper_open' => nil,
+ 'wrapper_close' => nil,
+ 'with_comment' => 'true'
+ )
+ end
+
+ Annotate.load_tasks
+end
diff --git a/lib/tasks/dev.rake b/lib/tasks/dev.rake
new file mode 100644
index 0000000..b517eed
--- /dev/null
+++ b/lib/tasks/dev.rake
@@ -0,0 +1,52 @@
+desc "Fill the database tables with some sample data"
+task sample_data: :environment do
+ starting = Time.now
+
+ Task.delete_all
+ User.delete_all
+
+ people = Array.new
+ people << { first_name: "Alice", last_name: "Smith" }
+ people << { first_name: "Bob", last_name: "Smith" }
+ people << { first_name: "Carol", last_name: "Smith" }
+ people << { first_name: "Doug", last_name: "Smith" }
+
+ people.each do |person|
+ username = person.fetch(:first_name).downcase
+
+ user = User.create(
+ email: "#{username}@example.com",
+ password: "password",
+ username: username.downcase,
+ )
+
+ p user.errors.full_messages
+ end
+
+ users = User.all
+
+ # users.each do |user|
+ # rand(15).times do
+ # a_task = user.tasks.create(
+ # body: Faker::Quote.jack_handey,
+ # status: ["notstarted", "pending", "complete"].sample,
+ # )
+ # p a_task.errors.full_messages
+ # end
+ # end
+ users.each do |user|
+ Task.statuses.values.each do |status|
+ 10.times do
+ user.tasks.create(
+ body: Faker::Quote.jack_handey,
+ status: status,
+ )
+ end
+ end
+ end
+
+ ending = Time.now
+ p "It took #{(ending - starting).to_i} seconds to create sample data."
+ p "There are now #{User.count} users."
+ p "There are now #{Task.count} tasks."
+end
diff --git a/test/controllers/tasks_controller_test.rb b/test/controllers/tasks_controller_test.rb
new file mode 100644
index 0000000..8059c1a
--- /dev/null
+++ b/test/controllers/tasks_controller_test.rb
@@ -0,0 +1,48 @@
+require "test_helper"
+
+class TasksControllerTest < ActionDispatch::IntegrationTest
+ setup do
+ @task = tasks(:one)
+ end
+
+ test "should get index" do
+ get tasks_url
+ assert_response :success
+ end
+
+ test "should get new" do
+ get new_task_url
+ assert_response :success
+ end
+
+ test "should create task" do
+ assert_difference('Task.count') do
+ post tasks_url, params: { task: { body: @task.body, owner_id: @task.owner_id } }
+ end
+
+ assert_redirected_to task_url(Task.last)
+ end
+
+ test "should show task" do
+ get task_url(@task)
+ assert_response :success
+ end
+
+ test "should get edit" do
+ get edit_task_url(@task)
+ assert_response :success
+ end
+
+ test "should update task" do
+ patch task_url(@task), params: { task: { body: @task.body, owner_id: @task.owner_id } }
+ assert_redirected_to task_url(@task)
+ end
+
+ test "should destroy task" do
+ assert_difference('Task.count', -1) do
+ delete task_url(@task)
+ end
+
+ assert_redirected_to tasks_url
+ end
+end
diff --git a/test/fixtures/tasks.yml b/test/fixtures/tasks.yml
new file mode 100644
index 0000000..c41ee43
--- /dev/null
+++ b/test/fixtures/tasks.yml
@@ -0,0 +1,27 @@
+# == Schema Information
+#
+# Table name: tasks
+#
+# id :bigint not null, primary key
+# body :text
+# status :string default("notstarted")
+# created_at :datetime not null
+# updated_at :datetime not null
+# owner_id :bigint not null
+#
+# Indexes
+#
+# index_tasks_on_owner_id (owner_id)
+#
+# Foreign Keys
+#
+# fk_rails_... (owner_id => users.id)
+#
+
+one:
+ owner: one
+ body: MyText
+
+two:
+ owner: two
+ body: MyText
diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml
new file mode 100644
index 0000000..8cf19fc
--- /dev/null
+++ b/test/fixtures/users.yml
@@ -0,0 +1,30 @@
+# == Schema Information
+#
+# Table name: users
+#
+# id :bigint not null, primary key
+# email :string default(""), not null
+# encrypted_password :string default(""), not null
+# remember_created_at :datetime
+# reset_password_sent_at :datetime
+# reset_password_token :string
+# username :citext
+# created_at :datetime not null
+# updated_at :datetime not null
+#
+# Indexes
+#
+# index_users_on_email (email) UNIQUE
+# index_users_on_reset_password_token (reset_password_token) UNIQUE
+# index_users_on_username (username) UNIQUE
+#
+
+# This model initially had no columns defined. If you add columns to the
+# model remove the '{}' from the fixture names and add the columns immediately
+# below each fixture, per the syntax in the comments below
+#
+one: {}
+# column: value
+#
+two: {}
+# column: value
diff --git a/test/models/task_test.rb b/test/models/task_test.rb
new file mode 100644
index 0000000..65a97f5
--- /dev/null
+++ b/test/models/task_test.rb
@@ -0,0 +1,26 @@
+# == Schema Information
+#
+# Table name: tasks
+#
+# id :bigint not null, primary key
+# body :text
+# status :string default("notstarted")
+# created_at :datetime not null
+# updated_at :datetime not null
+# owner_id :bigint not null
+#
+# Indexes
+#
+# index_tasks_on_owner_id (owner_id)
+#
+# Foreign Keys
+#
+# fk_rails_... (owner_id => users.id)
+#
+require "test_helper"
+
+class TaskTest < ActiveSupport::TestCase
+ # test "the truth" do
+ # assert true
+ # end
+end
diff --git a/test/models/user_test.rb b/test/models/user_test.rb
new file mode 100644
index 0000000..d542a7c
--- /dev/null
+++ b/test/models/user_test.rb
@@ -0,0 +1,27 @@
+# == Schema Information
+#
+# Table name: users
+#
+# id :bigint not null, primary key
+# email :string default(""), not null
+# encrypted_password :string default(""), not null
+# remember_created_at :datetime
+# reset_password_sent_at :datetime
+# reset_password_token :string
+# username :citext
+# created_at :datetime not null
+# updated_at :datetime not null
+#
+# Indexes
+#
+# index_users_on_email (email) UNIQUE
+# index_users_on_reset_password_token (reset_password_token) UNIQUE
+# index_users_on_username (username) UNIQUE
+#
+require "test_helper"
+
+class UserTest < ActiveSupport::TestCase
+ # test "the truth" do
+ # assert true
+ # end
+end
diff --git a/test/system/tasks_test.rb b/test/system/tasks_test.rb
new file mode 100644
index 0000000..62aaea3
--- /dev/null
+++ b/test/system/tasks_test.rb
@@ -0,0 +1,45 @@
+require "application_system_test_case"
+
+class TasksTest < ApplicationSystemTestCase
+ setup do
+ @task = tasks(:one)
+ end
+
+ test "visiting the index" do
+ visit tasks_url
+ assert_selector "h1", text: "Tasks"
+ end
+
+ test "creating a Task" do
+ visit tasks_url
+ click_on "New Task"
+
+ fill_in "Body", with: @task.body
+ fill_in "Owner", with: @task.owner_id
+ click_on "Create Task"
+
+ assert_text "Task was successfully created"
+ click_on "Back"
+ end
+
+ test "updating a Task" do
+ visit tasks_url
+ click_on "Edit", match: :first
+
+ fill_in "Body", with: @task.body
+ fill_in "Owner", with: @task.owner_id
+ click_on "Update Task"
+
+ assert_text "Task was successfully updated"
+ click_on "Back"
+ end
+
+ test "destroying a Task" do
+ visit tasks_url
+ page.accept_confirm do
+ click_on "Destroy", match: :first
+ end
+
+ assert_text "Task was successfully destroyed"
+ end
+end