我的Rails应用程序中有几个模型,它们是:
我需要向Photo
或Album
发表评论,显然属于User
。我将使用polymorphic associations。
# models/comment.rb
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :commentable, :polymorphic => true
end
问题是,为新评论描述#create
行动的Rails方式是什么。我看到了两种选择。
1。描述每个控制器中的评论创建
但这不是一个干燥的解决方案。我可以为显示和创建注释创建一个常见的局部视图,但我将不得不重复自己为每个控制器编写注释逻辑。所以它没有工作
2。创建新的CommentsController
这是我想的正确方法,但正如我所知:
要使其工作,您需要声明外键列和a 声明多态接口的模型中的type列
像这样:
# schema.rb
create_table "comments", force: :cascade do |t|
t.text "body"
t.integer "user_id"
t.integer "commentable_id"
t.string "commentable_type"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
所以,当我编写非常简单的控制器时,它将接受来自远程表单的请求:
# controllers/comments_controller.rb
class CommentsController < ApplicationController
def new
@comment = Comment.new
end
def create
@commentable = ??? # How do I get commentable id and type?
if @comment.save(comment_params)
respond_to do |format|
format.js {render js: nil, status: :ok}
end
end
end
private
def comment_params
defaults = {:user_id => current_user.id,
:commentable_id => @commentable.id,
:commentable_type => @commentable.type}
params.require(:comment).permit(:body, :user_id, :commentable_id,
:commentable_type).merge(defaults)
end
end
我如何获得commentable_id
和commetable_type
?我猜,commentable_type
可能是模型名称。
另外,从其他视图制作form_for @comment
的最佳方法是什么?
答案 0 :(得分:5)
我会使用嵌套路由和良好的旧继承。
Rails.application.routes.draw do
resources :comments, only: [:show, :edit, :update, :destroy] # chances are that you don't need all these actions...
resources :album, shallow: true do
resources :comments, only: [:new, :index, :create], module: 'albums'
end
resources :photos, shallow: true do
resources :comments, only: [:new, :index, :create], module: 'photos'
end
end
class CommentsController < ApplicationController
before_action :set_commentable, only: [:new, :index, :create]
def create
@comment = @commentable.comments.new(comment_params) do |c|
c.user = current_user
end
# ...
end
# ...
end
class Albums::CommentsController < ::CommentsController
private
def set_commentable
@commentable = Album.find(param[:id])
end
end
class Photos::CommentsController < ::CommentsController
private
def set_commentable
@commentable = Photo.find(param[:id])
end
end
虽然您可以简单地让CommentsController
查看参数以确定“可评论”资源是什么,我宁愿选择此解决方案为CommentsController
,否则最终会处理远远超过单个资源的情况膨胀成神级。
当你有索引动作并且需要根据父资源执行连接或者事情变得复杂时,这真的很闪耀。
使用partials制作可重复使用的表单非常简单:
# views/comments/_form.html.erb
<%= form_for([commentable, commentable.comment.new]) do |f| %>
<%= f.label :body %>
<%= f.text_field :body %>
<% end %>
然后你会这样包括它:
<%= render partial: 'comments/form', commentable: @album %>
答案 1 :(得分:4)
你最好nesting it in the routes,然后从父类委派:
# config/routes.rb
resources :photos, :albums do
resources :comments, only: :create #-> url.com/photos/:photo_id/comments
end
# app/controllers/comments_controller.rb
class CommentsController < ApplicationController
def create
@parent = parent
@comment = @parent.comments.new comment_params
@comment.save
end
private
def parent
return Album.find params[:album_id] if params[:album_id]
Photo.find params[:photo_id] if params[:photo_id]
end
def comment_params
params.require(:comment).permit(:body).merge(user_id: current_user.id)
end
end
这将自动为您填写。
为了给自己一个@comment
个对象,您必须使用:
#app/controllers/photos_controller.rb
class PhotosController < ApplicationController
def show
@photo = Photo.find params[:id]
@comment = @photo.comments.new
end
end
#app/views/photos/show.html.erb
<%= form_for [@photo, @comment] do |f| %>
...