Rails 5多态Comment模型结合Devise新建评论参数始终校验不通过
Hey there, let's work through why your Comment params are stuck as permitted => false—even using params.permit(:all) isn't fixing it because this is almost always about how your request parameters are structured, not the permit logic itself. Let's break this down step by step:
1. First, Check Your Request Params Structure
Start by looking at your Rails server logs when you submit the comment form. You should see something like this:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"abc123", "comment"=>{"title"=>"My Comment", "description"=>"Great post!", "commentable_id"=>"5", "commentable_type"=>"Post"}, "commit"=>"Create Comment"}
If you don't see a top-level comment key wrapping your form fields, that's the core problem. Rails' strong parameters rely on this nested structure, so params.permit(:all) would only allow top-level params (like utf8 or authenticity_token), not the actual comment data.
2. Fix Your Form to Include Polymorphic Fields
Your form_with call looks okay, but you're missing the hidden fields that link the comment to its parent commentable object. Add these to your _form.html.erb:
<%= form_with(model: comment, local: true) do |form| %> <%# Add hidden fields for polymorphic association %> <%= form.hidden_field :commentable_id, value: @commentable.id %> <%= form.hidden_field :commentable_type, value: @commentable.class.name %> <%# Your existing title/description fields %> <div class="field"> <%= form.label :title %> <%= form.text_field :title %> </div> <div class="field"> <%= form.label :description %> <%= form.text_area :description %> </div> <div class="actions"> <%= form.submit %> </div> <% end %>
You'll also need to set @commentable in your controller's new action so the form knows which object the comment belongs to:
# comments_controller.rb def new @commentable = find_commentable @comment = @commentable.comments.new end private def find_commentable # Pulls the parent object from params (e.g., post_id, article_id) params.each do |name, value| if name =~ /(.+)_id$/ return $1.classify.constantize.find(value) end end nil end
3. Correct Your Strong Params Method
Even if you use params.permit(:all), you need to first target the nested comment hash. Replace your current params method with this:
# comments_controller.rb private def comment_params params.require(:comment).permit(:title, :description, :commentable_id, :commentable_type) end
Here's why params.permit(:all) didn't work: it permits all top-level params, but your actual comment data is nested under comment. The require(:comment) ensures we're only working with that nested hash, then permit allows the specific fields we need.
4. Double-Check Devise Integration (If Needed)
If your Comment model belongs to a User (which makes sense with Devise), don't let the form submit a user_id (that's a security risk). Instead, set it manually in the create action:
def create @commentable = find_commentable @comment = @commentable.comments.new(comment_params) @comment.user = current_user # Link the comment to the logged-in user if @comment.save redirect_to @commentable, notice: 'Comment added successfully!' else render :new end end
This way, you avoid exposing user_id in the form, and you ensure the comment is tied to the correct user.
Final Check
After making these changes, submit the form again and check your logs. You should see the comment params nested under comment, and the server won't log "Unpermitted parameters" anymore. If it still does, double-check that all fields you're submitting are included in the permit list.
内容的提问来源于stack exchange,提问作者Kieu Hua

