Reputation: 11
Using Signed Global IDs with Polymorphic Select Fields in Rails Forms: My models:
class Comment < ApplicationRecord
belongs_to :commentable, polymorphic: true
end
class Post < ApplicationRecord
has_many :comments, as: :commentable
end
class Photo < ApplicationRecord
has_many :comments, as: :commentable
end
My controllers:
class CommentsController < ApplicationController
def new
@comment = Comment.new
end
def create
@comment = Comment.new(comment_params)#errors this location...
end
def comment_params
params.require(:comment).permit(:commentable)
end
end
I have in table commets (commetable_type,_id)
Upvotes: 0
Views: 59
Reputation: 102250
From the purely technical standpoint your code doesn't work as the association=(associate)
setter method expects a model instance and not a string.
Comment.new(commentable: Post.find(1))
This is different than the association_id=
setter also generated by belongs_to
that you would normally used with a form. But that one will not automatically resolve a global id either so I don't understand how this is supposed to work.
While you could have the controller use different commentables depending on the passed form inputs and resolve the global id explicitly it's not really the best approach as you're making a nested resource implicit from a RESTful standpoint.
You're also not handling the case where the parent id is invalid at all.
I would really just treat this as a normal nested resource and make the connection part of the URL.
resources :photos do
resources :comments, only: :create, module: :photos
end
resources :posts do
resources :comments, only: :create, module: :posts
end
class CommentsController < ApplicationController
def create
@comment = commentable.comments.new(comment_params)
# @todo you probably want to assign the comment to the current
# user unless they are all anonymous
if @comment.save
redirect_to @commentable
else
# render the view where the form is embedded.
end
end
# permit the actual content of the comment instead
def comment_params
params.require(:comment)
.permit(:text, :foo, :bar, :baz)
end
end
module Posts
# Handles POST /posts/1/comments
class CommentsController < ::CommentsController
def commentable
@commentable ||= Post.find(params[:post_id])
end
end
end
module Photos
# Handles POST /photos/1/comments
class CommentsController < ::CommentsController
def commentable
@commentable ||= Photo.find(params[:photo_id])
end
end
end
<%= form_with model: [commentable, comment] do |form| %>
# ...
<% end %>
While this can seem unessicary it makes debugging way easier as you can see from POST /photos/1/comments
exactly what is supposed to be happening and it also gives you a natural way to handle the complexity that always rears it's ugly head sooner or later.
The duplication can be reduced later if you have a large amount of commentable classes.
Upvotes: 2