Search code examples
ruby-on-railsrubyroutes

form_with is trying to generate the action with the wrong path


I'm experimenting with routing and namespaces.

When implementing a form with <%= form_with model: [@user, @address] do |form| %> i receive this error undefined method 'customer_user_customer_addresses_path'

This is the routing schema

  namespace :customer do
    resources :users do
      resource :contact
      resources :addresses
    end
  end

  resolve('Customer::Contact') {
    [:customer, :user, :contact]
  }

All routes printed by rails routes command are as expected.

                 customer_user_addresses GET    /customer/users/:user_id/addresses(.:format)                                                      customer/addresses#index
                                         POST   /customer/users/:user_id/addresses(.:format)                                                      customer/addresses#create
               new_customer_user_address GET    /customer/users/:user_id/addresses/new(.:format)                                                  customer/addresses#new
              edit_customer_user_address GET    /customer/users/:user_id/addresses/:id/edit(.:format)                                             customer/addresses#edit
                   customer_user_address GET    /customer/users/:user_id/addresses/:id(.:format)                                                  customer/addresses#show
                                         PATCH  /customer/users/:user_id/addresses/:id(.:format)                                                  customer/addresses#update
                                         PUT    /customer/users/:user_id/addresses/:id(.:format)                                                  customer/addresses#update
                                         DELETE /customer/users/:user_id/addresses/:id(.:format)                                                  customer/addresses#destroy

This is what i was able to do

  • by creating the Customer::UsersController i was able to access all crud operations for the users resources
  • by creating the Customer::ContactsController i was able to access all crud operations but i had to add the resolve directive in order to make the routes generated correctly
  resolve('Customer::Contact') {
    [:customer, :user, :contact]
  }

This is where i'm in trouble

When implementing the Customer::AddressesController i can't figure out a way to make form_with requesting the correct path.

This is the controller action

  def new
    @breadcrumbs = []
    @user = Customer::User.find(params[:user_id])
    @address = @user.addresses.build
  end

This is the new template

<%= form_with model: [@user, @address] do |form| %>

When i navigate to the new action i get this error undefined method 'customer_user_customer_addresses_path'

In order to make it working i had to pass an url parameter with the correct path: <%= form_with model: [@user, @address], url: customer_user_addresses_path(@user) do |form| %>.

What convention am i missing? is there any way to omit the url parameter?

Info

Repository: https://github.com/LuigiDeCosmis/GestionaleTest

Template to check is under customer/addresses/new.html.erb


Solution

  • Where did customer_ prefix come from?

    You are getting customer_ prefix both for user and address in your error message

    undefined method 'customer_user_customer_addresses_path'
    

    because you are trying to build you path based on models - while both of your User / Address models are placed in Customer namespace.

    To be specific - customer_ prefix came from here:

    Customer::User.model_name.param_key
    # => "customer_user"
    Customer::Address.model_name.param_key
    # => "customer_address"
    

    This is how it's trying to parse it: https://github.com/rails/rails/blob/af773ae44a1ae465cc0d19b1e8bf3fc731221ef0/actionview/lib/action_view/helpers/form_helper.rb#L756

    What convention am i missing?

    I can see no reason why you should namespace your models like that.

    If you want your users to be either customer / admin or anything else - you should rather use STI approach

    https://api.rubyonrails.org/classes/ActiveRecord/Inheritance.html

    https://medium.com/nyc-ruby-on-rails/single-table-inheritance-sti-ruby-on-rails-basics-2a08c81e50af

    Is there any way to omit the url parameter?

    Yes. After you get rid of Customer namespace for models you will be able to see in your routes something like:

    customer_user_addresses
    

    This is an example of routes which can be set up with model option.

    Hope that helps! Good luck!