feat: Create users

Users migration, model, controller. user_id to links. signup view
This commit is contained in:
Juan Rodriguez
2021-06-14 08:24:34 -05:00
parent 3e8bdee17a
commit f63be42b4c
21 changed files with 159 additions and 21 deletions
+1 -1
View File
@@ -25,7 +25,7 @@ gem 'jbuilder', '~> 2.5'
# Use Redis adapter to run Action Cable in production
# gem 'redis', '~> 4.0'
# Use ActiveModel has_secure_password
# gem 'bcrypt', '~> 3.1.7'
gem 'bcrypt', '~> 3.1.7'
# Use ActiveStorage variant
# gem 'mini_magick', '~> 4.8'
+3 -4
View File
@@ -45,6 +45,8 @@ GEM
addressable (2.7.0)
public_suffix (>= 2.0.2, < 5.0)
arel (9.0.0)
bcrypt (3.1.16)
bcrypt (3.1.16-java)
bindex (0.8.1)
bootsnap (1.7.5)
msgpack (~> 1.0)
@@ -171,9 +173,6 @@ GEM
thor (1.1.0)
thread_safe (0.3.6)
thread_safe (0.3.6-java)
turbolinks (5.2.1)
turbolinks-source (~> 5.2)
turbolinks-source (5.2.0)
tzinfo (1.2.9)
thread_safe (~> 0.1)
uglifier (4.2.0)
@@ -208,6 +207,7 @@ PLATFORMS
x86-mswin32
DEPENDENCIES
bcrypt (~> 3.1.7)
bootsnap (>= 1.1.0)
byebug
capybara (>= 2.15)
@@ -220,7 +220,6 @@ DEPENDENCIES
simplecov
spring
spring-watcher-listen (~> 2.0.0)
turbolinks (~> 5)
uglifier (>= 1.3.0)
web-console (>= 3.3.0)
webdrivers
+2 -2
View File
@@ -32,8 +32,8 @@ docker-compose run --rm app rubocop
- [x] Stimulus setup
- [x] Link controller (handle redirection)
- [x] Main page with input box
- [ ] Create user model
- [x] Create user model
- [ ] User unit tests
- [ ] Add userId key to link model
- [ ] Login and logout (sessions)
- [ ] Cache with redis?
- [ ] Setup Redis for production cache_store
+7 -1
View File
@@ -1,6 +1,8 @@
# frozen_string_literal: true
class LinksController < ApplicationController
before_action :authenticate, only: [:create]
def redirect
@link = Link.find_by_slug(params[:slug])
@@ -13,7 +15,9 @@ class LinksController < ApplicationController
end
def create
@link = Link.find_or_create_by(url: link_params[:url])
@link = Link.find_or_create_by(url: link_params[:url]) do |link|
link.user = @current_user if @current_user
end
if @link.errors.any?
render json: @link.errors, status: :unprocessable_entity
@@ -22,6 +26,8 @@ class LinksController < ApplicationController
end
end
private
def link_params
params.require(:link).permit(:url)
end
+23
View File
@@ -0,0 +1,23 @@
# frozen_string_literal: true
class UsersController < ApplicationController
def new
@user = User.new
end
def create
@user = User.create(user_params)
if @user.errors.any?
render json: @user.errors, status: :unprocessable_entity
else
session[:user_id] = @user.id
redirect_to '/'
end
end
private
def user_params
params.require(:user).permit(:username, :password)
end
end
+15
View File
@@ -0,0 +1,15 @@
# frozen_string_literal: true
module UsersHelper
def current_user
User.find_by(id: session[:user_id])
end
def logged_in?
!current_user.nil?
end
def authorized
redirect_to '/welcome' unless logged_in?
end
end
@@ -4,16 +4,15 @@ export default class extends Controller {
static targets = ["url", "output"]
onSuccess(event) {
event.preventDefault()
const [, , xhr] = event.detail
this.outputTarget.innerHTML = xhr.response
}
onError(event) {
event.preventDefault()
const [data, ,] = event.detail
alert(data.url.join(' '))
const urlError = `Url: ${data.url.join(' ')}`
alert(urlError)
}
}
@@ -0,0 +1,12 @@
import { Controller } from "stimulus"
export default class extends Controller {
onError(event) {
const [data, ,] = event.detail
const usernameError = `Username: ${data.username.join(' ')}`
const passwordError = `Password: ${data.username.join(' ')}`
alert(`${usernameError}, ${passwordError}`)
}
}
+2
View File
@@ -18,4 +18,6 @@ class Link < ApplicationRecord
def short
Rails.application.routes.url_helpers.short_url(slug: slug)
end
belongs_to :user, optional: true
end
+7
View File
@@ -0,0 +1,7 @@
# frozen_string_literal: true
class User < ApplicationRecord
validates_uniqueness_of :username
has_secure_password
end
+3 -3
View File
@@ -1,14 +1,14 @@
<%= form_with model: Link.new, url: links_path(@link), data: { action: 'ajax:success->links#onSuccess ajax:error->links#onError' } do |form| %>
<%= form_with model: Link.new, url: links_path(@link), data: { action: 'ajax:success->links#onSuccess ajax:error->links#onError' } do |f| %>
<div class="col-span-3 sm:col-span-2">
<label for="company_website" class="block text-sm font-medium text-gray-700">
Website
</label>
<div class="mt-1 flex rounded-md shadow-sm">
<%= form.text_field :url, data: { target: "links.url" }, placeholder: true, class: "focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-md sm:text-sm border-gray-300"%>
<%= f.text_field :url, data: { target: "links.url" }, placeholder: true, class: "focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-md sm:text-sm border-gray-300"%>
</div>
</div>
<div class="px-4 py-3 bg-gray-50 text-right sm:px-6">
<%= form.submit "Generate", class: "inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" %>
<%= f.submit "Generate", class: "inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" %>
</div>
<% end %>
+1
View File
@@ -5,6 +5,7 @@
<div class="grid grid-cols-3 gap-6">
<%= render partial: "links/form" %>
<div data-links-target="output"></div>
<%= button_to "Sign Up", '/users/new', method: :get%>
</div>
</div>
</div>
+10
View File
@@ -0,0 +1,10 @@
<h1>Sign Up</h1>
<div data-controller="users">
<%= form_for @user, data: { action: 'ajax:error->users#onError' } do |f| %>
<%= f.label :username%><br>
<%= f.text_field :username%><br>
<%= f.label :password%><br>
<%= f.password_field :password%><br>
<%= f.submit %>
<%end%>
</div>
+2 -1
View File
@@ -5,5 +5,6 @@ Rails.application.routes.draw do
get '/:slug', to: 'links#redirect', as: :short
resources :links, only: [:create]
resources :links, only: %i[create]
resources :users, only: %i[new create]
end
+12
View File
@@ -0,0 +1,12 @@
# frozen_string_literal: true
class CreateUsers < ActiveRecord::Migration[5.2]
def change
create_table :users do |t|
t.string :username
t.string :password_digest
t.timestamps
end
end
end
@@ -0,0 +1,7 @@
# frozen_string_literal: true
class AddUserIdToLinks < ActiveRecord::Migration[5.2]
def change
add_reference :links, :user, foreign_key: true
end
end
+12 -1
View File
@@ -12,7 +12,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20_210_613_145_459) do
ActiveRecord::Schema.define(version: 20_210_614_114_837) do
# These are extensions that must be enabled in order to support this database
enable_extension 'plpgsql'
@@ -22,6 +22,17 @@ ActiveRecord::Schema.define(version: 20_210_613_145_459) do
t.integer 'click_counter', default: 0
t.datetime 'created_at', null: false
t.datetime 'updated_at', null: false
t.bigint 'user_id'
t.index ['slug'], name: 'index_links_on_slug'
t.index ['user_id'], name: 'index_links_on_user_id'
end
create_table 'users', force: :cascade do |t|
t.string 'username'
t.string 'password_digest'
t.datetime 'created_at', null: false
t.datetime 'updated_at', null: false
end
add_foreign_key 'links', 'users'
end
+15
View File
@@ -0,0 +1,15 @@
# frozen_string_literal: true
require 'test_helper'
class UsersControllerTest < ActionDispatch::IntegrationTest
test 'should get new' do
get users_new_url
assert_response :success
end
test 'should get create' do
get users_create_url
assert_response :success
end
end
+9
View File
@@ -0,0 +1,9 @@
# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
one:
username: MyString
password_digest: MyString
two:
username: MyString
password_digest: MyString
+9
View File
@@ -0,0 +1,9 @@
# frozen_string_literal: true
require 'test_helper'
class UserTest < ActiveSupport::TestCase
# test "the truth" do
# assert true
# end
end
+3 -3
View File
@@ -6088,9 +6088,9 @@ postcss@^7, postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.17, po
supports-color "^6.1.0"
postcss@^8.2.1, postcss@^8.2.10, postcss@^8.2.15, postcss@^8.2.9:
version "8.3.2"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.2.tgz#ed3ec489f5428af5740cd6effcc216b4d455ee64"
integrity sha512-y1FK/AWdZlBF5lusS5j5l4/vF67+vQZt1SXPVJ32y1kRGDQyrs1zk32hG1cInRTu14P0V+orPz+ifwW/7rR4bg==
version "8.3.3"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.3.tgz#ef412a7a67e85c5b2c9f0ab3c4d9e8a3814d55cc"
integrity sha512-gnXd9C4bGKevvlNFd80I8WfxHX+g6MR+W2h19PlDNHUuT9248rHTvCIDeZI3Hvs5mB3gzXiNDwVK3S153WJbZA==
dependencies:
colorette "^1.2.2"
nanoid "^3.1.23"