ruby-on-rails - has_one - rails model references
Preocupación de la ruta y modelo polimórfico: ¿cómo compartir el controlador y las vistas? (2)
Puede encontrar el elemento primario en un filtro anterior como este:
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
Ahora puede redirigir o hacer lo que quiera dependiendo del tipo principal.
Por ejemplo en una vista:
= simple_form_for [@parent, comment] do |form|
O en un controlador
comments_controller.rb
redirect_to @parent # redirect to the show page of the commentable.
Dadas las rutas:
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
Y el modelo:
class Comment < ActiveRecord::Base
belongs_to :commentable, polymorphic: true
end
Cuando edito o agrego un comentario, necesito volver al objeto "commentable". Tengo los siguientes problemas, sin embargo:
1) El redirect_to
en los comments_controller.rb
sería diferente dependiendo del objeto principal
2) Las referencias en las vistas diferirían también
= simple_form_for comment do |form|
¿Hay alguna forma práctica de compartir vistas y controladores para este recurso de comment
?
En Rails 4 puede pasar opciones a las preocupaciones. Entonces, si haces esto:
# routes.rb
concern :commentable do |options|
resources :comments, options
end
resources :articles do
concerns :commentable, commentable_type: ''Article''
end
Luego, cuando rake routes
, verás que obtienes una ruta como
POST /articles/:id/comments, {commentable_type: ''Article''}
Eso anulará todo lo que la solicitud intente establecer para mantenerlo seguro. Luego en tu 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
Una forma de probar dicho controlador con rspec es:
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