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

时间:2013-05-04 15:46:47

标签: ruby-on-rails ruby-on-rails-4 rails-activerecord polymorphic-associations

鉴于路线:

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)redirect_to中的comments_controller.rb会有所不同,具体取决于父对象

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

= simple_form_for comment do |form|

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

2 个答案:

答案 0 :(得分:18)

在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

答案 1 :(得分:12)

你可以在之前的过滤器中找到父这样的内容:

<强> 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.