Rails 5 - NoMethod Error - undefined method

那年仲夏 提交于 2019-12-12 02:16:06

问题


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:inupdate' 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!