将注册添加到 Rails 8' 身份验证
本文最初发表于《使用 Ruby on Rails 构建 SaaS》(作者:Rails Designer)
Rails 8 终于推出了开箱即用的身份验证功能。❤️ 当它发布时,大多数人都惊讶于它没有提供注册(注册)新用户的方法。但这是有意识的决定,因为创建用户通常不是 SaaS 所需的唯一资源。当有人新注册您的产品时,还需要采取许多其他操作并创建资源。
本文探讨了我使用某种东西(通常称为**表单对象**)来实现这一点的方法。让我们来看看。
如果您想继续,请查看此 repo。此提交是一个 vanilla Rails 8 应用程序,其中已运行“bin/rails generate authentication”。
对于新功能,我总是喜欢从外到内开始。这意味着我从 UI 开始,然后再进入内部(更多内容请参阅另一篇文章)。
让我们在**app/views/signups/new.html.erb**创建表单:
<%= tag.div(flash[:alert], style: "color:red") if flash[:alert] %> <%= tag.div(flash[:notice], style: "color:green") if flash[:notice] %> <%= form_with model: @signup do |form| %> <%= form.email_field :email_address, required: true, autofocus: true, autocomplete: "username", placeholder: "Enter your email address", value: params[:email_address] %>
<%= form.password_field :password, required: true, autocomplete: "current-password", placeholder: "Enter your password", maxlength: 72 %>
<%= form.submit "Sign up" %> <% end %>
它与 Rails 的 **sessions/new.html.erb** 非常相似。
**注意**:本节中的文章重点介绍(业务)逻辑,不包含任何样式。我建议查看 Rails Designer 上的大量文章,以提高您的 UI、CSS 和 JavaScript 技能!🧑🎓 🎨
下一個路線:
# config/routes.rb root to: "pages#show" resource :signups, path: "signup", only: %w[new create]
我还添加了一个根路由,用户成功注册后将被重定向到该路由。
然后是控制器。这很简单:
class SignupsController < ApplicationController
allow_unauthenticated_access only: %w[new create]
def new
@signup = Signup.new
end
def create
@signup = Signup.new(signup_params)
if user = @signup.save
start_new_session_for user
redirect_to root_url
else
redirect_to new_signups_path
end
end
private
def signup_params
params.expect(signup: [ :email_address, :password ])
end
end`allow_unauthenticated_access` 来自 Rails 的身份验证生成器。然后另一个小新东西是 `params.expect(signup: [ :email_address, :password, :terms ])`。以前您可能已经看到过 `params.require(:signup).permit(:email_address, :password)`。这是此 PR 中添加的新 Rails 8+ 语法。
这一切看起来都很熟悉,对吧?但特殊之处在于 **Signup** 类。这不是您的常规 ActiveModel,而是一个所谓的 **Form Object**。
# app/models/signup.rb
class Signup
include ActiveModel::Model
include ActiveModel::Attributes
attribute :email_address, :string
attribute :password, :string
validates :email_address, presence: true
validates :password, length: 8..128
def save
if valid?
User.create!(email_address: email_address, password: password)
end
end
def model_name
ActiveModel::Name.new(self, nil, self.class.name)
end
end你看,我只是把它存储在 **app/models** 中;不需要其他文件夹。还请注意,它只是一个普通的 Ruby 类(通常称为 **PORO**),也就是说,它不是从 **ApplicationRecord** 继承的,但它看起来(而且听起来很像!)很像。
这是由于 `model_name` 方法和包含的两个模块。这允许您在表单生成器中引用对象(`form_with model: Signup.new`)。
对我来说,这种设置的美妙之处在于你现在有一个可以负责更多事情的类。毕竟,当注册一个新的 SaaS 时,通常会发生更多的事情:
您的特定用例还需要其他任何内容。让我们通过一个例子来稍微扩展一下上面的类:
# app/models/signup.rb
class Signup
include ActiveModel::Model
include ActiveModel::Attributes
attribute :email_address, :string
attribute :password, :string
validates :email_address, presence: true
validates :password, length: 8..128
def save
if valid?
User.create!(email_address: email_address, password: password).tap do |user|
create_workspace_for user
send_welcome_email_to user
end
end
end
def model_name
ActiveModel::Name.new(self, nil, self.class.name)
end
private
def create_workspace_for(user)
# eg. user.workspaces.create
end
def send_welcome_email_to(user)
# eg. WelcomeEmail.perform_later user
end
end现在,当 `valid?` 返回 true 时,将创建一个工作区并发送一封欢迎电子邮件。它还使用 `tap`:这将传递用户对象并将其作为对象返回(这在 **SignupsController#create** 操作中很有用。
我喜欢将我的方法编写得易于阅读和理解(类似于 Rails 8 身份验证代码的编写方式,例如“start_new_session_for user”)。
我现在只添加了两个额外的步骤,但你可以想象工作区创建也会在另一个类中再次发生。你可以随意扩展你需要的任何内容。
我们不要止步于此,让我们添加一个复选框,让用户接受您的服务条款。首先更新视图:
<%= form_with model: @signup do |form| %> <%# … %> <%= form.check_box :terms %> <%= form.label :terms %>
<% end %>
然后验证它是否存在于 Signup 类中。
class Signup # … attribute :terms, :boolean, default: false validates :terms, acceptance: true # … end
然后允许该属性在参数中传递。
class SignupsController < ApplicationController
# …
def signup_params
params.expect(signup: [ :email_address, :password, :terms ])
end
end类似地,你可以添加一个复选框来选择他们加入你的电子邮件通讯(并使用类似本文中描述的保险库之类的工具将其存储为首选项!💡
为了从头到尾完成此操作,让我们创建一个简单的视图,用户在注册后会被重定向到该视图。
# app/views/pages/show.html.erbSign up Successful
<%= button_to "Log out", session_path, method: :delete %>
使用这种方法,您将拥有一个可以包含注册所需的所有步骤的类。易于推理,易于测试!
当然这只是开始!从 UI 和 CSS(查看 Rails Designer 的 UI 组件库)到添加验证消息等等。
这样,您就将注册添加到了 Rails 8 身份验证中。此外,此代码不仅限于 Rails 8,还可以轻松添加到旧版本的 Rails。