问题
In the app I am building to learn Rails, I have a polymorphic relationship between the model "TAG" and the models "ANNOTATION" and "DOCUMENT". Similar to Article and Comment models.
Create and destroy of tags is working. Now, I want to update the tags and run into a no method error I don't understand. Tried many alternatives (e.g. using <%= link_to tag.content, [object, tag]...
with the form <%= simple_form_for object.tag ...
).
The form is called using:
<% object.tags.each do |tag| %>
<% unless tag.content.blank? %>
<tr>
<td><%= link_to tag.content, @tag, method: :patch %></td>
This is the tags controller:
class TagsController < ApplicationController
def index
end
def create
tagable = detect_tagable
tagable.tags.create(tag_params)
redirect_to tagable_path(tagable)
end
def update
tagable = detect_tagable
@tag = tagable.tags.find(params[:id])
@tag.save
render '_tag_update'
end
def destroy
tagable = detect_tagable
@tag = tagable.tags.find(params[:id])
@tag.destroy
redirect_to tagable_path(tagable)
end
private
def tagable_path(tagable)
case tagable
when Document
document_path(tagable)
when Annotation
annotate_path(tagable)
else
fail 'Unknown tagable'
end
end
def detect_tagable
if params[:annotation_id]
Annotation.find(params[:annotation_id])
elsif params[:document_id]
Document.find(params[:document_id])
else
fail 'Tagable not found'
end
end
def tag_params
params.require(:tag).permit(:content, :location, :tagtype_id,annotation_attributes: { annotation_ids:[] }, document_attributes: { document_ids:[] })
end
end
It renders the correct form _tag_update.html.erb
with the right parameters (annotation id and tag id) yet throws the error on:
<%= simple_form_for @tag, html: { class: 'form-vertical', multipart: true },
Full error
NoMethodError in Tags#update Showing /Users/Dimitri/Documents/AppDev/shine/app/views/tags/_tag_update.html.erb where line #1 raised: undefined method `tag_path' for #<#:0x007fc2aede9d88> Did you mean? tagtype_path Extracted source (around line #1): 1 2 3 4 5 6
<%= simple_form_for @tag, html: { class: 'form-vertical', multipart: true }, wrapper: :horizontal_form, wrapper_mappings: { check_boxes: :horizontal_radio_and_checkboxes, radio_buttons: :horizontal_radio_and_checkboxes, file: :horizontal_file_input, Rails.root: /Users/Dimitri/Documents/AppDev/shine
Application Trace | Framework Trace | Full Trace:
app/views/tags/_tag_update.html.erb:1:in
_app_views_tags__tag_update_html_erb___1949489846228898836_70237067101380' app/controllers/tags_controller.rb:17:in
update' Request
Parameters:
{"_method"=>"patch", "authenticity_token"=>"LhqKjyjbYdznMvx+GjsIL0phwT8pRTtanooKU6Xt4hHaPRFMmZJmZVm7GGZa8iaWxN1MIfm7xHwwhSSrSBoO/g==", "annotation_id"=>"6", "id"=>"24"}
回答1:
When you pass a record to link_to
, form_for
or redirect_to
rails passes the record to the polymorphic route helpers (note that this has nothing to do with polymorphic associations).
To generate a route to a nested resource you need to pass both the parent and child record:
simple_form_for( [@tag.taggable, @tag], # ...
link_to( @tag.content, [@tag.taggable, @tag] )
redirect_to( [@tag.taggable, @tag] )
From your controller you don't need to do:
def tagable_path(tagable)
case tagable
when Document
document_path(tagable)
when Annotation
annotate_path(tagable)
else
fail 'Unknown tagable'
end
end
Just redirect_to taggable
and rails will figure out the route for you by using the clever conventions.
Nesting is not always good.
Member routes do not need to be nested. Since each record be accessed by a unique id you can unnest the member routes:
# avoids duplication
concern :taggable do
resources :tags, only: [:new, :index, :create]
end
# generates GET|PATCH|DELETE /tags/:id and /tags/:id/edit
resources :tags, only: [:show, :edit, :destroy, :update]
resources :documents, concerns: :taggable
resources :annotations, concerns: :taggable
The resources :annotations, shallow: true
option gives somewhat similar results.
This means that you can do redirect_to(@tag)
or link_to('Delete tag', @tag, method: :delete )
来源:https://stackoverflow.com/questions/40056756/rails-5-nomethod-error-undefined-method