路由关注和多态模型:如何共享控制器和视图?

鉴于路线:

Example::Application.routes.draw do concern :commentable do resources :comments end resources :articles, concerns: :commentable resources :forums do resources :forum_topics, concerns: :commentable end end 

而型号:

 class Comment < ActiveRecord::Base belongs_to :commentable, polymorphic: true end 

当我编辑或添加评论时,我需要回到“可评论”对象。 不过,我有以下几个问题:

1)根据父对象, comments_controller.rbredirect_to会有所不同

2)对视图的引用也会有所不同

 = simple_form_for comment do |form| 

是否有实用的方法来共享此comment资源的视图和控制器?

您可以在之前的filter中找到父类,如下所示:

comments_controller.rb

 before_filter: find_parent def find_parent params.each do |name, value| if name =~ /(.+)_id$/ @parent = $1.classify.constantize.find(value) end end end 

现在,您可以根据父类型重定向或执行任何操作。

例如在视图中:

 = simple_form_for [@parent, comment] do |form| 

或者在控制器中

comments_controller.rb

 redirect_to @parent # redirect to the show page of the commentable. 

在Rails 4中,您可以将选项传递给关注点。 所以,如果你这样做:

 # routes.rb concern :commentable do |options| resources :comments, options end resources :articles do concerns :commentable, commentable_type: 'Article' end 

然后当你rake routes ,你会看到你得到一条路线

POST /articles/:id/comments, {commentable_type: 'Article'}

这将覆盖请求尝试设置以保证其安全的任何内容。 然后在你的CommentsController中:

 # comments_controller.rb class CommentsController < ApplicationController before_filter :set_commentable, only: [:index, :create] def create @comment = Comment.create!(commentable: @commentable) respond_with @comment end private def set_commentable commentable_id = params["#{params[:commentable_type].underscore}_id"] @commentable = params[:commentable_type].constantize.find(commentable_id) end end 

使用rspec测试这种控制器的一种方法是:

 require 'rails_helper' describe CommentsController do let(:article) { create(:article) } [:article].each do |commentable| it "creates comments for #{commentable.to_s.pluralize} " do obj = send(commentable) options = {} options["#{commentable.to_s}_id"] = obj.id options["commentable_type".to_sym] = commentable.to_s.camelize options[:comment] = attributes_for(:comment) post :create, options expect(obj.comments).to eq [Comment.all.last] end end end