Merge pull request 'Configure Devise to send emails using the tenant's slug for the URL' (#155) from wedding-creation into main
Reviewed-on: #155
This commit is contained in:
commit
5f66373d50
@ -30,6 +30,10 @@ class ApplicationController < ActionController::Base
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def default_url_options(options = {})
|
||||||
|
options.merge(path_params: { slug: ActsAsTenant.current_tenant&.slug })
|
||||||
|
end
|
||||||
|
|
||||||
def set_tenant
|
def set_tenant
|
||||||
ActsAsTenant.current_tenant = Wedding.find_by(slug: params[:slug])
|
ActsAsTenant.current_tenant = Wedding.find_by(slug: params[:slug])
|
||||||
end
|
end
|
||||||
|
@ -3,4 +3,24 @@
|
|||||||
class Users::RegistrationsController < Devise::RegistrationsController
|
class Users::RegistrationsController < Devise::RegistrationsController
|
||||||
clear_respond_to
|
clear_respond_to
|
||||||
respond_to :json
|
respond_to :json
|
||||||
|
|
||||||
|
def create
|
||||||
|
wedding = Wedding.create(wedding_params)
|
||||||
|
unless wedding.persisted?
|
||||||
|
render json: { errors: wedding.errors.full_messages }, status: :unprocessable_entity
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
ActsAsTenant.with_tenant(wedding) do
|
||||||
|
super do |user|
|
||||||
|
wedding.destroy unless user.persisted?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def wedding_params
|
||||||
|
{ slug: params[:slug], **params.expect(wedding: :date) }
|
||||||
|
end
|
||||||
end
|
end
|
@ -15,6 +15,8 @@
|
|||||||
# index_weddings_on_slug (slug) UNIQUE
|
# index_weddings_on_slug (slug) UNIQUE
|
||||||
#
|
#
|
||||||
class Wedding < ApplicationRecord
|
class Wedding < ApplicationRecord
|
||||||
|
SLUG_REGEX = /[a-z\d-]+/
|
||||||
|
|
||||||
validates :date, presence: true
|
validates :date, presence: true
|
||||||
validates :slug, presence: true, uniqueness: true
|
validates :slug, presence: true, uniqueness: true, format: { with: /\A#{SLUG_REGEX}\z/ }
|
||||||
end
|
end
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
<%# Copyright (C) 2024 Manuel Bustillo %>
|
||||||
|
|
||||||
|
<p>Welcome <%= @email %>!</p>
|
||||||
|
|
||||||
|
<p>You can confirm your account email through the link below:</p>
|
||||||
|
|
||||||
|
<p><%= link_to 'Confirm my account', confirmation_url(slug: ActsAsTenant.current_tenant&.slug, confirmation_token: @token) %></p>
|
9
app/views/users/mailer/email_changed.html.erb
Normal file
9
app/views/users/mailer/email_changed.html.erb
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<%# Copyright (C) 2024 Manuel Bustillo %>
|
||||||
|
|
||||||
|
<p>Hello <%= @email %>!</p>
|
||||||
|
|
||||||
|
<% if @resource.try(:unconfirmed_email?) %>
|
||||||
|
<p>We're contacting you to notify you that your email is being changed to <%= @resource.unconfirmed_email %>.</p>
|
||||||
|
<% else %>
|
||||||
|
<p>We're contacting you to notify you that your email has been changed to <%= @resource.email %>.</p>
|
||||||
|
<% end %>
|
5
app/views/users/mailer/password_change.html.erb
Normal file
5
app/views/users/mailer/password_change.html.erb
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<%# Copyright (C) 2024 Manuel Bustillo %>
|
||||||
|
|
||||||
|
<p>Hello <%= @resource.email %>!</p>
|
||||||
|
|
||||||
|
<p>We're contacting you to notify you that your password has been changed.</p>
|
10
app/views/users/mailer/reset_password_instructions.html.erb
Normal file
10
app/views/users/mailer/reset_password_instructions.html.erb
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<%# Copyright (C) 2024 Manuel Bustillo %>
|
||||||
|
|
||||||
|
<p>Hello <%= @resource.email %>!</p>
|
||||||
|
|
||||||
|
<p>Someone has requested a link to change your password. You can do this through the link below.</p>
|
||||||
|
|
||||||
|
<p><%= link_to 'Change my password', edit_password_url(slug: ActsAsTenant.current_tenant&.slug, reset_password_token: @token) %></p>
|
||||||
|
|
||||||
|
<p>If you didn't request this, please ignore this email.</p>
|
||||||
|
<p>Your password won't change until you access the link above and create a new one.</p>
|
9
app/views/users/mailer/unlock_instructions.html.erb
Normal file
9
app/views/users/mailer/unlock_instructions.html.erb
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<%# Copyright (C) 2024 Manuel Bustillo %>
|
||||||
|
|
||||||
|
<p>Hello <%= @resource.email %>!</p>
|
||||||
|
|
||||||
|
<p>Your account has been locked due to an excessive number of unsuccessful sign in attempts.</p>
|
||||||
|
|
||||||
|
<p>Click the link below to unlock your account:</p>
|
||||||
|
|
||||||
|
<p><%= link_to 'Unlock my account', unlock_url(slug: ActsAsTenant.current_tenant&.slug, unlock_token: @token) %></p>
|
@ -246,7 +246,7 @@ Devise.setup do |config|
|
|||||||
# Turn scoped views on. Before rendering "sessions/new", it will first check for
|
# 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
|
# "users/sessions/new". It's turned off by default because it's slower if you
|
||||||
# are using only default views.
|
# are using only default views.
|
||||||
# config.scoped_views = false
|
config.scoped_views = true
|
||||||
|
|
||||||
# Configure the default scope given to Warden. By default it's the first
|
# Configure the default scope given to Warden. By default it's the first
|
||||||
# devise role declared in your routes (usually :user).
|
# devise role declared in your routes (usually :user).
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Rails.application.routes.draw do
|
Rails.application.routes.draw do
|
||||||
mount LetterOpenerWeb::Engine, at: "/letter_opener" if Rails.env.development?
|
mount LetterOpenerWeb::Engine, at: "/letter_opener" if Rails.env.development?
|
||||||
scope ":slug", constraints: {slug: /[a-z]+/} do
|
scope ":slug", constraints: { slug: Wedding::SLUG_REGEX } do
|
||||||
devise_for :users, skip: [:registration, :session, :confirmation]
|
devise_for :users, skip: [:registration, :session, :confirmation]
|
||||||
devise_scope :user do
|
devise_scope :user do
|
||||||
post 'users', to: 'users/registrations#create'
|
post 'users', to: 'users/registrations#create'
|
||||||
|
@ -3,5 +3,20 @@
|
|||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe Wedding, type: :model do
|
RSpec.describe Wedding, type: :model do
|
||||||
pending "add some examples to (or delete) #{__FILE__}"
|
describe 'validations' do
|
||||||
|
subject { build(:wedding) }
|
||||||
|
describe 'slug' do
|
||||||
|
it { should allow_value('foo').for(:slug) }
|
||||||
|
it { should allow_value('foo-bar').for(:slug) }
|
||||||
|
it { should allow_value('foo-123').for(:slug) }
|
||||||
|
it { should allow_value('foo-123-').for(:slug) }
|
||||||
|
it { should allow_value('foo--123').for(:slug) }
|
||||||
|
|
||||||
|
it { should_not allow_value('Foo').for(:slug) }
|
||||||
|
it { should_not allow_value('/foo').for(:slug) }
|
||||||
|
it { should_not allow_value('foo/123').for(:slug) }
|
||||||
|
it { should_not allow_value('foo_123').for(:slug) }
|
||||||
|
it { should_not allow_value('foo/').for(:slug) }
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -14,6 +14,7 @@ module Swagger
|
|||||||
name: 'slug',
|
name: 'slug',
|
||||||
in: :path,
|
in: :path,
|
||||||
type: :string,
|
type: :string,
|
||||||
|
pattern: Wedding::SLUG_REGEX,
|
||||||
example: :default,
|
example: :default,
|
||||||
description: 'Wedding slug'
|
description: 'Wedding slug'
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ RSpec.describe 'users/registrations', type: :request do
|
|||||||
parameter Swagger::Schema::SLUG
|
parameter Swagger::Schema::SLUG
|
||||||
parameter name: :body, in: :body, schema: {
|
parameter name: :body, in: :body, schema: {
|
||||||
type: :object,
|
type: :object,
|
||||||
required: [:user],
|
required: [:user, :wedding],
|
||||||
properties: {
|
properties: {
|
||||||
user: {
|
user: {
|
||||||
type: :object,
|
type: :object,
|
||||||
@ -23,6 +23,13 @@ RSpec.describe 'users/registrations', type: :request do
|
|||||||
password: SwaggerResponseHelper::PASSWORD,
|
password: SwaggerResponseHelper::PASSWORD,
|
||||||
password_confirmation: SwaggerResponseHelper::PASSWORD
|
password_confirmation: SwaggerResponseHelper::PASSWORD
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
wedding: {
|
||||||
|
type: :object,
|
||||||
|
required: %i[date],
|
||||||
|
properties: {
|
||||||
|
date: { type: :string, format: :date},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user