1

Given the following models:

class Blog < ActiveRecord::Base
  has_many :posts
end

class SiteBlog < Blog
end

class ProjectBlog < Blog
end

class Post <ActiveRecord::Base
  belongs_to :blog
end

And the following routes:

resources :blogs do
  resources :posts
end

In say a form partial, the following will work fine if @blog is a Blog:

form_for [@blog, @post] ...

However, if @blog is a ProjectBlog or SiteBlog, it bombs since it will be looking for a URL helper such as project_blog_posts.

I guess something like this would solve this:

[:project_blogs, :site_blogs].each |blogs| do
  resources blogs do
    resources :posts
  end
end

I'm wondering whether there's a way to use the routes for subclassed models (e.g. ProjectBlog) to use the routes of the parent model (Blog). The "as" option only deals with the last object passed like [@blog, @post] to form_for.

Update

As requested below, here are the routes:

resources :blogs, only: [:show] do
  resources :posts, only: [:new, :create, :edit, :update]
end

               blog_posts POST   /blogs/:blog_id/posts(.:format)                         posts#create
            new_blog_post GET    /blogs/:blog_id/posts/new(.:format)                     posts#new
           edit_blog_post GET    /blogs/:blog_id/posts/:id/edit(.:format)                posts#edit
                blog_post PUT    /blogs/:blog_id/posts/:id(.:format)                     posts#update
                     blog GET    /blogs/:id(.:format)                                    blogs#show

Update 2:

The tip from an answer below:

form_for [@blog, @post], url: blog_posts_path(@blog, @post) do |f|

This works for "new" actions only, for "edit" actions, I'd get - as expected - a bad URL:

params[:action]   # => "edit"
blog_posts_path(@blog, @post)   # => "/blogs/publikationsreihe-tafelrunde/posts.5"

So the "if" I mentioned would fix this:

form_for [@blog, @post], url: params[:action]=='new' ? blog_posts_path(@blog, @post) : blog_post_path(@blog, @post) do |f|

But this looks incredibly clumsy, there must be a better way.

svoop
  • 3,318
  • 1
  • 23
  • 41

1 Answers1

0

Easily solvable by passing the resource url to the form:

<%= form_for [@blog, @post], :url => blog_posts_path(@blog, @post) do |f| %>
  ...
<%- end %>
Jon
  • 10,678
  • 2
  • 36
  • 48
  • I've tried that, but this hardcoded URL works for new records only. Editing with the same form triggers a "No route matches [PUT] /blogs/123/posts" error. An if would fix this, but there should be a less ugly way to get there. – svoop Mar 09 '12 at 07:59
  • Sounds like your routes.rb is wrong then. The nested blogs/posts resources should provide that exact PUT resource for updating posts. Can you show us the output of "rake routes" ? – Jon Mar 09 '12 at 08:32
  • Well, you shouldn't be routing to /blogs/123/posts with a PUT. It should be /blogs/123/posts/ ... and just seen my error. Try my updated link above ... I was missing the @post object in the blog_posts url helper. – Jon Mar 09 '12 at 11:55
  • I don't route /blogs/123/posts with a PUT. AFAIK the blog_posts_path helper is no good for edit (see Update 2 above). – svoop Mar 09 '12 at 12:46
  • Are you using single-table-inheritance for these models, or do you have site_blogs and project_blogs tables? Also, why do you need to distinguish between them at the model level? – Jon Mar 09 '12 at 13:41
  • I'm using STI. The models share maybe half the code, but differ in other parts. For example: SiteBlog maps to owhers via the generic Ownership model whereas ProjectBlog proxies the owners from the attached Project relationship. – svoop Mar 12 '12 at 09:24