【问题标题】:Route concern and polymorphic model: how to share controller and views?路由关注点和多态模型:如何共享控制器和视图?
【发布时间】:2013-05-04 15:46:47
【问题描述】:

给定路线:

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.rb 中的 redirect_to 会因父对象而异

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

= simple_form_for comment do |form|

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

【问题讨论】:

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


    【解决方案1】:

    在 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
    

    【讨论】:

    • 感谢您的回答,非常有帮助!不幸的是,我发现了一个错误——在 routes.rb 中,您必须使用“关注”方法使用关注点,例如:“关注点:commentable,commentable_type:'Article'”。
    【解决方案2】:

    您可以像这样在前置过滤器中找到父级:

    cmets_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|
    

    或者在控制器中

    cmets_controller.rb

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

    【讨论】:

    • 感谢您的想法;尽管我可以有多个父母,但我会试一试。例如我需要simple_form_for [forum, forum_topic, comment];或redirect_to [forum, forum_topic]。我会玩 splats,看看它会把我带到哪里。
    • @amencarini 你仍然可以帮 Arjan 一个忙并接受他的回答!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-21
    • 2019-03-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多