feat: add user registration functionality

- Implement user creation in UsersController
- Add user registration form in new.html.erb
- Create error messages partial for form validation
- Add gravatar helper for user profile
- Update routes to include resources for users
- Introduce integration tests for signup validation

This commit establishes the foundation for user registration, allowing users to sign up with their details and providing feedback on form errors. It enhances the user experience by integrating visual elements like gravatars and error messages.
This commit is contained in:
songtianlun 2024-12-31 16:34:52 +08:00
parent cd558466be
commit 9fac43f46d
10 changed files with 212 additions and 13 deletions

View File

@ -13,6 +13,5 @@
*= require_self
*/
@import "bootstrap-sprockets";
@import "bootstrap";

View File

@ -1,3 +1,7 @@
@import "bootstrap-sprockets";
@import "bootstrap";
/* color */
$light-gray: #777;
@ -60,9 +64,9 @@ p {
}
}
img {
display: none;
}
//img {
// display: none;
//}
/* footer */
footer {
@ -89,3 +93,86 @@ footer {
}
}
/* mixins, variables, etc. */
$gray-medium-light: #eaeaea;
@mixin box_sizing {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
/* miscellaneous */
.debug_dump {
clear: both;
float: left;
width: 100%;
margin-top: 45px;
@include box-sizing;
}
/* sidebar */
aside {
section.user_info {
margin-top: 20px;
}
section {
padding: 10px 0;
margin-top: 20px;
&:first-child {
border: 0;
padding-top: 0;
}
span{
display: block;
margin-bottom: 3px;
line-height: 1;
}
h1 {
font-size: 1.4em;
text-align: left;
letter-spacing: -1px;
margin-bottom: 3px;
margin-top: 0;
}
}
}
.gravatar {
float: left;
margin-right: 10px;
}
.gravatar_edit {
margin-top: 15px;
}
/* forms */
input, textarea, select, .uneditable-input {
border: 1px solid #bbb;
width: 100%;
margin-bottom: 15px;
@include box_sizing;
}
input {
height: auto !important;
}
/* forms */
#error_explanation {
color: red;
ul {
color: red;
margin: 0 0 30px 0;
}
}
.field_with_errors {
@extend .has-error;
.form-control {
color: $state-danger-text;
}
}

View File

@ -1,4 +1,28 @@
class UsersController < ApplicationController
def show
@user = User.find(params[:id])
# debugger
end
def new
@user = User.new
# debugger
end
def create
@user = User.new(user_params)
if @user.save
flash[:success] = "Welcome to the Sample App!"
redirect_to @user
# redirect_to user_url(@user)
else
render 'new'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
end

View File

@ -1,2 +1,7 @@
module UsersHelper
def gravatar_for(user, size: 80)
gravatar_id = Digest::MD5.hexdigest(user.email.downcase)
gravatar_url = "https://secure.gravatar.com/avatar/#{gravatar_id}?s=#{size}"
image_tag(gravatar_url, alt: user.name, class: "gravatar")
end
end

View File

@ -1,5 +1,5 @@
<!DOCTYPE html>
<html>
<html lang="en">
<head>
<!-- <title><%#= content_for(:title) || "Sample App" %></title>-->
<title><%= full_title(yield(:title)) %></title>
@ -10,8 +10,15 @@
<body>
<%= render 'layouts/header' %>
<div class="container">
<% flash.each do |message_type, message| %>
<%= content_tag(:div, message, class: "alert alert-#{message_type}") %>
<!-- <div class="alert alert-<%#= message_type %>"><%#= message %></div>-->
<% end %>
<%= yield %>
<%= render 'layouts/footer' %>
<%#= debug(params) if Rails.env.development? %>
<%= debug(params.to_yaml) if Rails.env.development? %>
<%= debug(Time.now) if Rails.env.development? %>
</div>
</body>
</html>

View File

@ -0,0 +1,12 @@
<% if @user.errors.any? %>
<div id="error_explanation">
<div class="alert alert-danger">
The form contains <%= pluralize(@user.errors.count, "error") %>.
</div>
<ul>
<% @user.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>

View File

@ -1,3 +1,24 @@
<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>
<p>This will be a signup page for new users.</p>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_with(model: @user, local: true) do |f| %>
<%= render 'shared/error_messages' %>
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control' %>
<%= f.label :email %>
<%= f.email_field :email, class: 'form-control' %>
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>
<%= f.label :password_confirmation, "Confirmation" %>
<%= f.password_field :password_confirmation, class: 'form-control' %>
<%= f.submit "Create my account", class: "btn, btn-primary" %>
<% end %>
</div>
</div>

View File

@ -0,0 +1,12 @@
<%provide(:title, @user.name) %>
<div class="row">
<aside class="col-md-4">
<section class="user_info">
<h1>
<%= gravatar_for @user %>
<%= @user.name %>
</h1>
</section>
</aside>
</div>

View File

@ -1,16 +1,19 @@
Rails.application.routes.draw do
get "users/new"
get "static_pages/home"
get "static_pages/help"
get "static_pages/about"
get "static_pages/contact"
# get "users/new"
# get "static_pages/home"
# get "static_pages/help"
# get "static_pages/about"
# get "static_pages/contact"
root "static_pages#home"
get '/help', to: 'static_pages#help'
get '/about', to: 'static_pages#about'
get '/contact', to: 'static_pages#contact'
get '/signup', to: 'users#new'
root "static_pages#home"
resources :users
# Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
# Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500.

View File

@ -0,0 +1,29 @@
require "test_helper"
class UsersSignupTest < ActionDispatch::IntegrationTest
test "invalid signup information" do
get signup_path
assert_no_difference 'User.count' do
post users_path, params: { user: { name: "",
email: "user@invalid",
password: "foo",
password_confirmation: "bar" } }
end
assert_template 'users/new'
assert_select 'div#error_explanation'
assert_select 'div.alert-danger'
end
test "valid signup information" do
get signup_path
assert_difference 'User.count', 1 do
post users_path, params: { user: {name: "Example User",
email: "user@example.com",
password: "password",
password_confirmation: "password" } }
end
follow_redirect!
assert_template 'users/show'
assert_not flash.notice
end
end