Implicit routing for nested controllers with the same namespace

Given Rails 4.1, two controllers CRM::CompaniesController

and CRM::ContactPeople

, two models CRM::Company

and, CRM::ContactPerson

and the following routes:

namespace :crm do
  resources :companies do
    resources :contact_people
  end
end

      

The generated helper urls contain the CRM namespace only once, which is exactly what I want:

crm_company_contact_people      GET  /crm/companies/:company_id/contact_people(.:format)
new_crm_company_contact_person  GET  /crm/companies/:company_id/contact_people/new(.:format) 
# ...

      

However, using the Array approach for URL helpers

= form_for([@crm_company, @crm_contact_person]) do |f|

      

trying to create a url with each namespace:

undefined method `crm_company_crm_contact_people_path' for #<#<Class...

      

I would like to have the "crm" in my paths only once at the beginning (unless it breaks the general Rails approach), and it would be ugly to add the url to each form explicitly. Is there something I can do (perhaps in routes, model, or the first argument of form_for) so that Rails knows how to build the correct path? Or is there a more Rails way of creating such a structure so that Rails automatically knows how to create paths?

+3


source to share


2 answers


You need to include the namespace in your call to form_for

:

= form_for([:crm, @crm_company, @crm_contact_person]) do |f|



Also, since you are using named models, you need to define the following class method for them ( from rails / rails issue # 10705 ) to ignore the namespace:

def self.use_relative_model_naming?
  true
end

      

+1


source


I tried several approaches to find the least annoying approach for me. I start by changing the CRM namespace to use the relative model name:

module CRM
  def self.use_relative_model_naming?
    true
  end
end

      

However, this removes the namespace from every entity, including the company. So the following doesn't work:

= url_for @crm_company
# undefined method `company_path'

      

To avoid this, I tried to ignore only certain models by changing the model name (note that this has more side effects than URL generation):

class CRM::ContactPerson < ActiveRecord::Base
  def self.model_name
    ActiveModel::Name.new(self, CRM)
  end
end

      



Now the following urls work fine:

= url_for @crm_company
= url_for [@crm_company, @crm_contact_person]

      

But if CRM :: ContactPerson is shallowly nested and appears as a child of CRM :: Company AND as a child of CRM itself, the problem at the top appears:

= url_for @crm_contact_person
# undefined method `contact_person_path'

      

In this case, we could split the nested and unnamed part into CRM :: Companies :: ContactPerson and CRM :: ContactPerson and use the relative model name for the CRM :: Companies module. However, this appears to be a lot of overhead and may even be worse than using explicit URL helpers.

So at the moment I can't seem to find a comprehensive solution, but at least for nested resources works fine.

0


source







All Articles