I just implemented this the other day, and it is really very simple. First, you need to add another allowed parameter to the Devise registration form in
app/controllers/application_controller.rb
class ApplicationController < ActionController::Base protect_from_forgery with: :exception before_action :configure_permitted_parameters, if: :devise_controller? after_action :verify_authorized, unless: :devise_controller? protected def configure_permitted_parameters devise_parameter_sanitizer.for(:sign_up) { |u| u.permit( :username, :email, :password, :password_confirmation, :remember_me, :sign_up_code ) } end end
These parameters do not have to match, but you need to make sure that any field of the form that you use to enter the registration code matches the name that you pass here.
Now update the development view with a field for the code attribute:
app/views/devise/registrations/new.html.erb
<%= form_for( resource, as: resource_name, url: registration_path(resource_name)) do |f| %> <%= f.text_field :sign_up_code %> <% end %>
Next we need to add a virtual attribute and some verification:
app/models/user.rb
class User < ActiveRecord::Base attr_accessor :sign_up_code validates :sign_up_code, on: :create, presence: true, inclusion: { in: ["your_code"] } # The rest of your model end
Now everything is ready!
Please note that you can also do something like the following if you need dynamic invitation codes from the invite_codes table:
inclusion: { in: proc { InviteCode.where( used: false ).map( &:code ) } }
In the above model, I have the line code and boolean used to make sure that invitation codes can only be used once.
For example, I use the following seed.rb code to populate the invitation codes when creating the database:
invite_codes = (0...50).map { { code: SecureRandom.hex(7), used: false } } invite_codes = invite_codes.uniq invite_codes.each do |invite_code| InviteCode.find_or_create_by!( invite_code ) end