-1

I'm trying to build an app where when a user signs up, the user along with an organization and a membership to that organization are created. However, I continue to run into an issue where the user is created, but neither the organization nor the membership are.

I have tried many things, but mostly keep getting this same error:

Unpermitted parameter: :organization. Context: { controller: Users::RegistrationsController, action: create, request: #<ActionDispatch::Request:0x0000000117db8248>, params: {"authenticity_token"=>"[FILTERED]", "user"=>{"first_name"=>"John", "last_name"=>"Doe", "email"=>"john@test.com", "position"=>"CEO", "organization"=>{"name"=>"JohnDoeCo"}, "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Sign up", "controller"=>"users/registrations", "action"=>"create"} }

My models are as such:

class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

  has_one :membership
  has_one :organization, through: :membership
  accepts_nested_attributes_for :membership, :organization

end
class Organization < ApplicationRecord
    has_many :memberships
    has_many :users, through: :memberships

    validates :name, presence: true
end
class Membership < ApplicationRecord
  belongs_to :organization
  belongs_to :user
end

My Registrations Controller is:

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

  # GET /resource/sign_up
  def new
    super
    resource.build_membership
    resource.build_organization
  end

  # POST /resource
  def create
    super
  end

  # GET /resource/edit
  def edit
    super
  end

  # PUT /resource
  def update
    super
  end

  # DELETE /resource
  def destroy
    super
  end

  protected
  
  def configure_sign_up_params
    devise_parameter_sanitizer.permit(:sign_up) do |u|
      u.permit(
        :first_name,
        :last_name,
        :position,
        :email,
        :password,
        :password_confirmation,
        organization_attributes: [:name],
        membership_attributes: [:organization_id, :user_id]
      )
    end
  end

end

And my view for registrations/new looks like:

<h2>Sign up</h2>

<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
  <%= render "users/shared/error_messages", resource: resource %>

  <div class="field">
    <%= f.label :first_name %><br />
    <%= f.text_field :first_name, autofocus: true %>
  </div>

  <div class="field">
    <%= f.label :last_name %><br />
    <%= f.text_field :last_name %>
  </div>

  <div class="field">
    <%= f.label :email %><br />
    <%= f.email_field :email, autocomplete: "email" %>
  </div>

  <div class="field">
    <%= f.label :position %><br />
    <%= f.text_field :position %>
  </div>

  <%= f.fields_for :organization do |fm| %>

      <%= fm.label :name %><br />
      <%= fm.text_field :name %>

  <% end %>

  <div class="field">
    <%= f.label :password %>
    <% if @minimum_password_length %>
    <em>(<%= @minimum_password_length %> characters minimum)</em>
    <% end %><br />
    <%= f.password_field :password, autocomplete: "new-password" %>
  </div>

  <div class="field">
    <%= f.label :password_confirmation %><br />
    <%= f.password_field :password_confirmation, autocomplete: "new-password" %>
  </div>

  <div class="actions">
    <%= f.submit "Sign up" %>
  </div>
<% end %>

<%= render "users/shared/links" %>
AaronM
  • 47
  • 1
  • 5

2 Answers2

1

I think the issue here is that resource.build_organization is running after the response is rendered and not before.

When f.fields_for :organization is then called #organization returns nil and not an instance of organization so Rails doesn't understand that it should be naming the parameters for nested attributes.

What you want to do is to pass a block to the super method:

# Do not use `::` when defining nested classes/modules
# @see https://github.com/rubocop/ruby-style-guide#namespace-definition
module Users
  class RegistrationsController < Devise::RegistrationsController
    before_action :configure_sign_up_params, only: [:create]

    # GET /resource/sign_up
    def new
      super do |user|
        resource.build_membership
        resource.build_organization
      end
    end

    # ...
  end
end 

This works since most of the Devise controller methods yield at key points to let you tap into the flow and do things to the resource:

class Devise::RegistrationsController < DeviseController
  # GET /resource/sign_up
  def new
    build_resource
    yield resource if block_given? # <- your code should be running here
    respond_with resource
    # <- not here
  end
end
max
  • 96,212
  • 14
  • 104
  • 165
-1

The error is trying to tell you to whitelist the organization param. See this answer and the Strong Parameters documentation.

ZimbiX
  • 485
  • 3
  • 7
  • I changed the params based on your answer as follows to add the line: `{membership_attributes: [:organization_id, :user_id, organization_attributes: [:name]]}` But I am still running into the same error. – AaronM Mar 17 '23 at 19:05
  • I don't have much experience in this, but from a scan of the docs, I think it might need to be `membership_attributes` when editing, and `membership` when creating – ZimbiX Mar 17 '23 at 19:11
  • Just tried it without `_attributes` when creating, no luck. – AaronM Mar 17 '23 at 19:41