In working on a RESTful website, I''ve encountered a stumbling block involving polymorphic associations. For example, given: map.resources :posts do |post| post.resources :comments, :name_prefix => ''post_'' end map.resources :photos do |photo| photo.resources :comments, :name_prefix => ''photo_'' end Where comments is polymorphic. The acts_as_commentable plugin fits the bill. So we have routes like: /posts/678/comments /photos/185/comments If we want to create a new comment for photo 678 we would send a POST to /posts/678/comments. Nice and RESTful. But... how do I generate the path for the form target if the comment form is in a shared partial (DRY)? I did find one post about this on Rails Weenie and the answer was more of a workaround... an ugly helper that uses link_to. Is there any way to do this gracefully, such as *_path? Ideally: <% form_for(comment_path(@photo)) %> ...would be smart enough to determine the object type of @photo and generate the correct /photos/@photo.id/comments route automatically. Any thoughts? Anyone run into this, and if so how did you solve it? Thanks! -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Funny, moments before you posted this I was struggling with the exact same thing *and* was looking at the exact same Techno Weenie article. I opted to go with a modified version of the before_filter approach like so. Read below for my observations. # POST /comments # POST /comments.xml def create @comment = Comment.new(params[:comment]) @commentable = find_commentable @commentable.comments << @comment respond_to do |format| if @comment.save flash[:notice] = ''Comment was successfully created.'' format.html { eval("redirect_to #{@commentable.class.to_s.underscore}_url(@commentable)") } format.js # render create.rjs; update comment listing format.xml { head :created, :location => eval("#{@commentable.class.to_s.underscore}_url(@commentable)") } else format.html { render :controller => @commentable.class.to_s.underscore, :id => @commentable.id, :action => :show } format.js { :render :js => @comment.errors.to_json } # XXX format.xml { render :xml => @comment.errors.to_xml } end end end private def find_commentable # lazy regex, just finds instances of /controller/id sections = request.env[''REQUEST_URI''].scan(%r{/(\w+)/(\d*)}) sections.map! do |controller_name, id| [controller_name.singularize.camelize, id] end klass, id = sections.pop eval("#{klass}.find(id)") end I''ve got the entire thing working brilliantly as long as it''s a Ajaxed or if the non-Ajax submission is valid. What I haven''t figured out yet to do properly is handle invalid non-Ajax submissions and still populate the input fields. I see two possible paths: 1. Perform a redirection after doing some session storage. Implement a before_filter that checks for session-stored form submissions and errors. 2. Move all views that are commentable into partials. Though #2 is "kinda OK", it remains a bit of a stretch. Interested to hear your thoughts and any code improvements. - Roderick -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
I''m glad I''m not the only one struggling with this problem! Frankly, I''m a bit surprised Rails 1.2 is going to be released with open questions like this. How are you generating your form destinations in your comment form(s)? -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Carl Johnson wrote:> How are you generating your form destinations in your comment form(s)?Here''s what I have, let me know if you work up something better. In news_items/show.rhtml: <%= render :partial => ''shared/comment_form'', :locals => { :commentable => @news_item } %> shared/_comment_form.rhtml: <div id="comment_form"> <h2>New comment</h2> <%= error_messages_for :comment %> <% remote_form_for(:comment, :url => comments_path(commentable)) do |f| -%> <p> <label for="body">Comment</label><br /> <%= f.text_area :body %> </p> <p> <%= submit_tag ''Create'' %> </p> <% end -%> </div> -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
> <% remote_form_for(:comment, :url => comments_path(commentable)) do > |f| -%>I am not able to simply use comments_path because I have overlapping routes. Like this: map.resources :pictures do |picture| picture.resources :comments, :name_prefix => ''picture_'' map.resources :posts do |post| post.resources :comments, :name_prefix => ''post_'' So in order for my New Comment form to POST to the correct URL I have to use either picture_comments_path or post_comments_path. In the routing above the name_prefixes are required, otherwise one overwrites the other. It seems like your solution will work for you as long as you have only one parent defined in the routing for comments, but as soon as you want to add comments for something like :blog_items, comments_path is not going to know what to do. Unless I''m missing something? Carl -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Carl Johnson wrote:> It seems like your solution will work for you as long as you have only > one parent defined in the routing for comments, but as soon as you want > to add comments for something like :blog_items, comments_path is not > going to know what to do. Unless I''m missing something?You are right. I hadn''t tackled that issue yet. However, it should be solvable by something (untested and hand-coded) like: pictures/show.rhtml: <%= render :partial => ''shared/comment_form'', :locals => { :commentable => @picture, :name_prefix => ''picture_'' } %> shared/_comment_form.rhtml: <% eval("remote_form_for(:comment, :url => #{name_prefix}comments_path(commentable))") do |f| -%> -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
> You are right. I hadn''t tackled that issue yet. However, it should be > solvable by something (untested and hand-coded) like: > > pictures/show.rhtml: > > <%= render :partial => ''shared/comment_form'', :locals => { > :commentable => @picture, :name_prefix => ''picture_'' } %>Yeah that''s pretty simple. I''ll probably do the same too... been putting off converting my comment submission to RESTful so far. I still think that the _path generators should be able to do a little magic and determine the correct route for polymorphic targets. Hopefully that will eventually be built-in. I will try to tackle it myself in the Rails code but it will take me quite a while, if ever! :) -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Roderick van Domburg wrote:> You are right. I hadn''t tackled that issue yet. However, it should be > solvable by something (untested and hand-coded) like: > > pictures/show.rhtml: > > <%= render :partial => ''shared/comment_form'', :locals => { > :commentable => @picture, :name_prefix => ''picture_'' } %> > > shared/_comment_form.rhtml: > > <% eval("remote_form_for(:comment, :url => > #{name_prefix}comments_path(commentable))") do > |f| -%>FYI, this inspired me to convert to RESTful comment submissions and here''s what I did. I tried to limit what I pass to each partial since I already have to pass a bunch of pagination stuff. show.rhtml: <%= render(:partial => ''shared/comments'', :locals => {:comment_pages => @comment_pages, :count => @comment_count, :item => @picture})%> shared/_comments.rhtml: <% form_for(:comment, :url => eval("#{item.class.to_s.downcase}_comments_path(#{item.id})")) do |f| %> -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
On 1/16/07, Carl Johnson <rails-mailing-list-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> wrote:> <% form_for(:comment, :url => > eval("#{item.class.to_s.downcase}_comments_path(#{item.id})")) do |f| %>We do a lot of polymorphic stuff like this where I work. Just a suggestion: instead of eval("#{item.class.to_s.downcase}_comments_path(#{item.id})") try send("#{item.class.to_s.downcase}_comments_path", item.id)) Or, wrap it up: def polymorphic_comments_path(item) send("#{item.class.to_s.underscore}_comments_path", item)) end If you find yourself using eval, there''s usually another way to do it in Ruby. -- Chris Wanstrath http://errtheblog.com --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
hi, so far, so good, I''m having the same problems. say now I can create Comment for an Article, rendering comment form partial directly from /app/views/articles/show.rhtml <%= render(:partial => ''shared/comment_form'', :locals => {:item => @article, :name_prefix => ''article_''})%> #/app/views/shared/_comment_form.rhtml <%= error_messages_for :comment %> <% form_for(:comment, :url => polymorphic_comments_path(item)) do |f| %> <dl> <dt class="required">Title<br /><small>Please be concise.</small></dt> <dd><%= f.text_field ''title'' %></dd> <dt class="required">Comment<br /><small>Write your comment here.</small></dt> <dd><%= f.text_area ''comment'', :class => ''articleintroduction'' %></dd> </dl> <p> <%= submit_tag "Create" %> </p> <% end %> this form will generate <form action="/articles/1/comments" method="post"> which works well. # routes.rb map.resources :articles do |post| post.resources :comments, :name_prefix => ''article_'' end all done. # controller using simply_commentable # POST /comments # POST /comments.xml def create @commentable = find_commentable @comment = @commentable.comment_by!(current_user,params[:comment] ) respond_to do |format| if @comment.save flash[:notice] = ''Comment was successfully created.'' format.html { eval("redirect_to #{@commentable.class.to_s.underscore}_url(@commentable)") } format.js # render create.rjs; update comment listing format.xml { head :created, :location => eval("#{@commentable.class.to_s.underscore}_url(@commentable)") } else format.html { render :controller => @commentable.class.to_s.underscore, :id => @commentable.id, :action => :show } format.js { render :js => @comment.errors.to_json } # to check format.xml { render :xml => @comment.errors.to_xml } end end end private def find_commentable sections = request.env[''REQUEST_URI''].scan(%r{/(\w+)/(\d*)}) sections.map! do |controller_name, id| [controller_name.singularize.camelize, id] end klass, id = sections.pop eval("#{klass}.find(id)") end as suggested. I''m posting the entire thing just for reference to other users. anyway a question arises, say I want to edit a comment, we should use the controller Comments, how is the link_to built? with which routes and params? what should we put in the views/partials? thanks -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Have you made any progress on this? I''ve been searching for the same answers. Claudio Poli wrote:> hi, > so far, so good, I''m having the same problems. > > say now I can create Comment for an Article, rendering comment form > partial directly from /app/views/articles/show.rhtml > > ...snip... > > as suggested. I''m posting the entire thing just for reference to other > users. > anyway a question arises, say I want to edit a comment, we should use > the controller Comments, how is the link_to built? with which routes and > params? what should we put in the views/partials? > > thanks-- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---