feat: ✨ Create users
Users migration, model, controller. user_id to links. signup view
This commit is contained in:
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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}`)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class User < ApplicationRecord
|
||||
validates_uniqueness_of :username
|
||||
|
||||
has_secure_password
|
||||
end
|
||||
@@ -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 %>
|
||||
@@ -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>
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
Vendored
+9
@@ -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
|
||||
@@ -0,0 +1,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'test_helper'
|
||||
|
||||
class UserTest < ActiveSupport::TestCase
|
||||
# test "the truth" do
|
||||
# assert true
|
||||
# end
|
||||
end
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user