Reputation: 7361
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"=>"[email protected]", "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.
Upvotes: 1
Views: 1359
Reputation: 710
What helped me:
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
<%= 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 %>
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
Upvotes: 1
Reputation: 1089
You need to generate devise controllers and configure the registrations_controller.rb
Configure devise controllers
since you need to build the address after creating new user.
rails g devise:controllers users -c=registrations
And add the controllers to the devise_for routes:
For example:
devise_for :users, controllers: { registrations: 'users/registrations' }
Then you can edit sign_up_params to include address_parameters
def sign_up_params
params.require(:user).permit(:first, :last, address_attributes: [:your_address_attributes])
end
Also you need to override new
in registrations_controller
to include building the address
def new
super { resource.build_address }
end
To know how this works, you need to have a look at registerations_controller
for the views part you still need the f.fields_for :address
Hope this helps.
Upvotes: 1