Skip to content

Instantly share code, notes, and snippets.

@bookwyrm
Last active May 24, 2023 11:04
Show Gist options
  • Save bookwyrm/1424056e732647898414 to your computer and use it in GitHub Desktop.
Save bookwyrm/1424056e732647898414 to your computer and use it in GitHub Desktop.
Cleaning up Rails app signup with Devise and Reform
class Account < ActiveRecord::Base
has_many :users
end
# POST /resource
def create
build_resource(sign_up_params)
resource_saved = resource.save
yield resource if block_given?
if resource_saved
# Do saved stuff...
else
# Re-render to fix
end
end
<%# app/views/devise/registrations/new.html.erb %>
<h2>Sign up</h2>
<%= simple_form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :email, required: true, autofocus: true %>
<%= f.input :company_name, required: true %>
<%= f.input :password, required: true, hint: ("#{@minimum_password_length} characters minimum" if @validatable) %>
<%= f.input :password_confirmation, required: true %>
</div>
<div class="form-actions">
<%= f.button :submit, "Sign up" %>
</div>
<% end %>
<%= render "devise/shared/links" %>
# app/forms/registration_form.rb
class RegistrationForm < Reform::Form
include Composition
property :company_name, on: :account
property :email, on: :user
property :password, on: :user
property :password_confirmation, on: :user, empty: true
model :user
validates :email, presence: true
validates :password, presence: true, confirmation: true
validates :password, length: { minimum: 8 }
validates :company_name, presence: true
def active_for_authentication?
true
end
def authenticatable_salt
end
def save
return false unless valid?
sync
user = model[:user]
user.account = model[:account]
user.save
end
end
# app/controllers/registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
def create
configure_permitted_parameters
super
end
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :company_name
end
def build_resource(hash = nil)
self.resource = registration_form = RegistrationForm.new(user: User.new, account: Account.new)
unless hash.nil? || hash.length == 0
self.resource.validate hash
end
end
def after_sign_up_path_for(resource)
root_path
end
end
# spec/controllers/registrations_controller_spec.rb
require 'rails_helper'
RSpec.describe RegistrationsController, type: :controller do
before :each do
@request.env['devise.mapping'] = Devise.mappings[:user]
end
describe "POST #create" do
let(:post_params) { attributes_for(:user).merge(attributes_for(:account)) }
it "Creates a user" do
expect {
post :create, user: post_params
}.to change(User, :count).by(1)
end
it "Creates an account" do
expect {
post :create, user: post_params
}.to change(Account, :count).by(1)
end
it "Associates the user with the account" do
post :create, user: post_params
user = User.last
account = Account.last
expect(user.account).to eq(account)
end
end
end
# config/routes.rb
Rails.application.routes.draw do
devise_for :users, controllers: {
registrations: 'registrations',
}
root 'welcome#index'
end
# app/models/user.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
belongs_to :account
end
# spec/features/user_registrations_spec.rb
require 'rails_helper'
describe 'User registration' do
let(:user_email) { Faker::Internet.email }
let(:user_password) { Faker::Internet.password(8) }
let(:company_name) { Faker::Company.name }
before :each do
visit new_user_registration_path
fill_in 'user_company_name', with: company_name
fill_in 'user_email', with: user_email
fill_in 'user_password', with: user_password
fill_in 'user_password_confirmation', with: user_password
click_button 'Sign up'
end
it "lets the user log in" do
visit new_user_session_path
fill_in 'user_email', with: user_email
fill_in 'user_password', with: user_password
click_button 'Log in'
expect(page).to have_content("Welcome")
end
end
@neumachen
Copy link

Isn't the Devise::RegistrationsController does a resource.active_for_authentication? instead of save?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment