Search code examples
ruby-on-railsdevise

Rails Devise - Create user and update associated record


Ruby version: 2.6.3

Rails version: 6.0

I have 2 models

1) User

has_one :address, dependent: :destroy
accept_nested_attributes :address

2) Address

belongs_to :user, optional: true

I used devise for user model. Address model has some records already but they aren't associated with the user. When user comes for registration that time i have to show the list of available addresses which are not associated with any user.

I wanted to use a nested form for this situation. I override devise registration controller, but attributes are not correctly in parameters.

here is my code of registration form

  <%= f.fields_for :address do |sc| %>
    <%= sc.label :address %>
    <%= sc.select :address, options_for_select(Address.available_addresses&.map{ |i| [i.address, i.id] }), class: 'form-control' %>
  <% end %>

parameters

Parameters: {"authenticity_token"=>"MN6zE3Z7B7zhQupa6kvbqGN4kmc8pAHRrdqtKipDclki3f6H5M919YCe9O7b+M8X49wuD3UczzpRJDl0Fmx0SQ==", "user"=>{"first"=>"daa", "last"=>"dasa", "email"=>"aa@g.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "address_attributes"=>{"address"=>"1"}, "commit"=>"Sign up"}

application_controller.rb

before_action :configure_permitted_parameters, if: :devise_controller?

def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:first, :last, address_attributes: [:id, :address]] )
  end

the main thing is it is not passing as attributes. it is passing only as address: [:address] . if i write f.fields_for :address it is not showing in view. but if i write fields_for :address than only it is showing in form. its quite weird why it is not working as expected.

I don't have to create a new record of address. How can I associate existing record of has one to a user?

Update

When I use address attributes it is just creating a new record for the address instead of updating address record for the user. it is quite strange for me why it is not updating record and inserting a new one. I just wanted to update user id of an address record. I don't want to create a new record of address model.

Update I resolve my issue with below code

new.html.erb

  <%= fields_for :address do |sc| %>
    <%= sc.label :address %>
    <%= sc.select :address, options_for_select(Address.available_addresses&.map{ |i| [i.address, i.id] }), class: 'form-control' %>
  <% end %>

users/registrations_controller.rb
if resource.persisted?
  if resource.active_for_authentication?
     address = Address.find(params[:address][:address])
     address.update_column(:user_id, resource.id)

I really wanted to know why this is happening, I used nested attributes, but it was just creating new record rather creating new user and updating address. it is a very small issue I wanted to figure it out what is happening behind the scenes.


Solution

  • What helped me:

    1. In user.rb, override the address_attributes= method with:
    def address_attributes=(address_attrs)
      self.address = Address.find_or_initialize_by(id: address_attrs[:id])
      self.address.attributes = address_attrs
    end
    
    1. In the registration form:
    <%= f.fields_for :address, resource.address ? resource.address : resource.build_address do |address_form| %>
        <%= address_form.label :id, "Address" %>
        <%= address_form.collection_select :id, Address.where(user_id: nil), :id, :address, include_blank: "Choose address", class: "form-control" %>
    <% end %>
    
    1. Registrations Controller:
    def configure_sign_up_params
      devise_parameter_sanitizer.permit(:sign_up, keys: [:name, address_attributes: [:id]])
    end
    

    References:

    https://stackoverflow.com/a/9864783/11883546

    https://stackoverflow.com/a/48014151/11883546