Search code examples
ruby-on-railsrubydevisepolymorphic-associations

Rails - how can I make a profile switch on a radio button using a device and polymorphic associations?


I am new to development on rails. I need help with customizing the device. I have user with polymorphic association - profilable. When registering, I need to fill in the profilable depending on the selected radio button.

class Users::RegistrationsController < Devise::RegistrationsController
  before_action :configure_sign_up_params, only: [:create]
  before_action :configure_account_update_params, only: [:update]

  protected

  def configure_sign_up_params
    devise_parameter_sanitizer.permit(:sign_up, keys: %i[email profilable])
  end

  def configure_account_update_params
    devise_parameter_sanitizer.permit(:account_update, keys: %i[email])
  end
end

model User

class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

  belongs_to :profilable, polymorphic: true

  def set_client_profile
    c = ClientProfile.new
    self.profilable = c
  end

  def set_realtor_profile
    r = RealtorProfile.new
    self.profilable = r
  end
end

model ClientProfile

class ClientProfile < ApplicationRecord
  has_one :user, as: :profilable
end

model RealtorProfile

class RealtorProfile < ApplicationRecord
  has_one :user, as: :profilable
end

and this in my views/devise/registrations/new.html.erb

<div class="field">
    <%= f.label :profilable, 'Client' %>
    <%= f.radio_button :profilable, 'Client' %>
    <%= f.label :profilable, 'Realtor' %>
    <%= f.radio_button :profilable, 'Realtor'%>
    <% if params[:profilable] == 'Client' %>
      <% resource.set_client_profile %>
    <% else %> 
      <% resource.set_realtor_profile %>
    <% end %>
  </div>

This is error after registration:

1 error prohibited this user from being saved: Profilable must exist

sorry for this horrible code


Solution

  • This part of code

     <% if params[:profilable] == 'Client' %>
          <% resource.set_client_profile %>
        <% else %> 
          <% resource.set_realtor_profile %>
        <% end %>
    

    will be executed only on view rendering. The resource here is a an empty model that you use only for creating a form. This instance is not an actual model that will be created after the create request hits the server. So, both set_client_profile and set_client_profile will be never called in create method of the controller. This code should be removed.

    I guess the easiest way to do it is to redefine create method in Users::RegistrationsController. The original code of this method can be found in the repo. So, it can be modified like this:

     def create
        build_resource(sign_up_params)
    
        #here comes your modification
        if sign_up_params[:profilable] == 'Client'
          resource.set_client_profile
        else
          resource.set_realtor_profile
        end
    
        resource.save
        # After that, copy the rest of the original `create` method
        ...