1

I have a Profile model, which is inherited by a Customer and Vendor model. Profile has_many :posts.

When I do

form_for [ @profile, @post ] do |f|

Instead of callind profile_posts_path, form_for will actually call customer_posts_path or vendor_posts_path.

Since I want to have URLs like '/foo', '/bar', where foo and bar are usernames I wrote the routes like this:

resources :profiles, path: '/', constraints: { id: /[A-Z0-9\-\+\.]+/i } do
    resources :posts
end

resources :customers, path: '/', constraints: { id: /[A-Z0-9\-\+\.]+/i } do
    resources :posts
end

resources :vendors, path: '/', constraints: { id: /[A-Z0-9\-\+\.]+/i } do
    resources :posts
end

This way all requestes to '/foo' will be handled by the ProfilesController (it's the first in the list) and path helpers will be generated so that form_for will work.

However even if it works, this is far from ideal. There is evident repetition. If I need to add another nested resource I would have to add it trice.

So I refactored it like this (I know that this is horrible, but it works):

profile_block = Proc.new do
    resources :posts
end
resources :profiles, path: '/', constraints: { id: /[A-Z0-9\-\+\.]+/i }, &profile_block
resources :customer, path: '/', constraints: { id: /[A-Z0-9\-\+\.]+/i }, &profile_block
resources :vendor, path: '/', constraints: { id: /[A-Z0-9\-\+\.]+/i }, &profile_block

But this is still horrible. What I would really love to have is the as parameter to be an array, so that I could do:

resources :profiles, path: '/', constraints: { id: /[A-Z0-9\-\+\.]+/i }, as: [ 'profiles', 'customers', 'vendors' ] do
    ...
end

Is it possible to achieve something similar? Everything would be mapped to the same controller. And no repetition is in act. Any way to create named routes without having to call resources or match or anything...

Thanks in advance

edit: The relation between posts and profiles might become polymorphic in the near future. So the last solution proposed by AJcodex will break.

I find this frustrating, I will probably request this feature for the next rails

Francesco Boffa
  • 1,402
  • 1
  • 19
  • 35

1 Answers1

1

Some options:

  1. use a symbol form_for([:profile, @post]) do |f|

  2. alias the other methods. See this for adding routes: How to define own routing helpers in rails 3?

    alias_method :customers_path, :profiles_path
    
  3. iterate over the symbols in routes

in routes.rb

[ :profiles, :customers, :vendors ].each do |name|
  resources name, path: '/', constraints: { id: /[A-Z0-9\-\+\.]+/i }, as: name do
    resources :posts
  end
end

You should consider using a client-side framework though, because then you can separate the client-facing routes from the API routes. RESTful requests with the server, vanity URLs for the user.

edit:

Is there a reason you need routes for customers and vendors for posts? Have all posts handled by the profiles controller. Get rid of the vendors and customers fancy url's all together.

Depending on if it's a customer or vendor, render a different view if necessary.

edit 2:

do it by hand:

<%= form_for @post, as: :post, url: profile_path(@customer, @post) do |f| %>
  ...
<% end %>
Community
  • 1
  • 1
AJcodez
  • 31,780
  • 20
  • 84
  • 118
  • Number 3 was surely more elegant than my 'horrible' solution. However it would still generate a lot of unneded routes. I might use this as a last chance. I'll try the others first :) – Francesco Boffa Oct 08 '13 at 19:13
  • Posts are handled by the PostsController :P. I don't want to have a CustomerController or a VendorController, but I still need STI as customers and vendors have a lot of fields in commond, and a few unique fields each. I wouldn't even use the path helpers. The problem is that form_for and link_to will use that *fancy* path helpers, while I'd like to use the profile_path for everything – Francesco Boffa Oct 08 '13 at 19:40
  • Ok, I admit it would be a good solution and I was tempted to mark this as the accepted answer. However I just remembered that the relation between post and profile might become polymorphic in the future (post might be written on resources other than profiles). And that would break your solution. I will edit the question to add this detail. However, I will accept your answer if no other answers will pop up, as a *thank you* :) – Francesco Boffa Oct 08 '13 at 21:33
  • sounds like you could use a Concern for posts, resource :profiles for routes, and never the two would mix. good luck tho! – AJcodez Oct 08 '13 at 21:37