We're trying to create a conditional statement inside Devise's new registration form so that different fields are shown for different types of roles. The problem is that the role itself should already be decided before the registration form is rendered, so we implemented a select_role view where the user chooses between 2 roles: user and volunteer. This information is stored for the purpose of creating the new registration and the user is redirected to the form page with its correct conditional.
We tried to change Devise's sign up shared link from
<%= link_to "Sign up", new_registration_path(resource_name) %>
to
<%= link_to "Sign up", select_role_path %>
,
but if in the select_role method in the registrations controller we add the redirect_to new_user_registration_path
line, the sign up link just redirects straight to the devise form without the user making their choice and if we remove this line and get to the select_role view, the submit button just renders the current page again.
I. app/views/devise/registrations/new.html.erb
<%= simple_form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :name, required: true, input_html: { autocomplete: "name" } %>
...
<%= f.input :password_confirmation, required: true, input_html: { autocomplete: "new-password" } %>
<% if session[:chose_volunteer] %>
<%= f.input :profession %>
<%= f.input :professional_registration %>
<%= f.input :specialty %>
<%= f.hidden_field :roles, value: 'volunteer' %>
<% else %>
<%= f.hidden_field :roles, value: 'user' %>
<% end %>
</div>
II. app/views/users/registrations/select_role.html.erb
<%= form_tag select_role_path, method: :post do %>
<%= select_tag :role_id, options_for_select(Role.where(name: ['user', 'volunteer']).pluck(:name, :id)) %>
<%= submit_tag "Select Role" %>
<% end %>
III. app/controllers/users/registrations_controller.rb
class Users::RegistrationsController < Devise::RegistrationsController
def select_role
chose_volunteer = params[:role_id] == Role.find_by(name: 'volunteer').id.to_s
session[:chose_volunteer] = chose_volunteer
#redirect_to new_user_registration_path
end
end
IV. app/controllers/registrations_controllers.rb
class RegistrationsController < Devise::RegistrationsController
before_action :configure_sign_up_params, only: [:create]
def create
super
resource.add_role(params[:user][:roles])
end
protected
def configure_sign_up_params
devise_parameter_sanitizer.permit(:sign_up, keys: [:name, :age, :phone, :city, :state, :country, :address, :instagram, :profession, :professional_registration, :specialty, roles: []])
end
end
V. config/routes.rb
Rails.application.routes.draw do
devise_for :users, controllers: { registrations: "registrations" }
root to: "pages#home"
devise_scope :user do
get 'select_role', to: 'users/registrations#select_role'
end
resources :users
resources :forum_threads do
resources :forum_posts, only: [:create]
end
end
There are no create or select_role methods in my users controller.
How do I correctly redirect the user to the new registration form from the select_role page with the role choice being carried over?
I would just create separate routes, controllers and views for the two different kinds of registrations. It's a lot less wonky and good OOP.
Code reuse can be acheived by inheritance, mixins and partials.