Как отправлять полиморфные комментарии в ленту? [Ошибка]

Если пользователь нажимает кнопку [+ Комментарий]

введите здесь описание изображения

он сталкивается с этим злым зверем:

ActiveRecord::RecordNotFound in CommentsController#create
Couldn't find Comment with 'id'=
Line: @commentable = resource.singularize.classify.constantize.find(id)

действия/индекс

<%= link_to activity.user.name, activity.user %>
<%= render "activities/#{activity.trackable_type.underscore}/#{activity.action}", activity: activity %>
<%= render "comments/comments", comments: activity.comments %>
<%= render "comments/form", new_comment: Comment.new(commentable_id: activity.id, commentable_type: activity.class.model_name) %>

комментарии/_форма

<%= form_for new_comment do |f| %>
  <%= f.text_area :content, rows: 4, class: 'form-control', placeholder: 'Enter Comment' %>
  <%= button_tag(type: 'submit', class: "btn") do %>
    <span class="glyphicon glyphicon-plus"></span> Comment
  <% end %>
<% end %>

Activities_controller

def index
  @activities = Activity.order("created_at desc").where(user_id: current_user.following_ids)
  @commentable = @activity
  @comment = Comment.new
end

Ошибку можно найти здесь:

class CommentsController < ApplicationController
  before_action :load_commentable
  before_action :set_comment, only: [:show, :edit, :update, :destroy, :like]
  before_action :logged_in_user, only: [:create, :destroy]

    def index
        @comments = @commentable.comments
    end

    def new
        @comment = @commentable.comments.new
    end

    def create
        @comment = @commentable.comments.new(comment_params)
        if @comment.save
            redirect_to @commentable, notice: "comment created."
        else
            render :new
        end
    end

    def edit
        @comment = current_user.comments.find(params[:id])
    end

    def update
        @comment = current_user.comments.find(params[:id])
        if @comment.update_attributes(comment_params)
            redirect_to @commentable, notice: "Comment was updated."
        else
            render :edit
        end
    end

    def destroy
        @comment = current_user.comments.find(params[:id])
        @comment.destroy
        redirect_to @commentable, notice: "comment destroyed."
    end

  def like
    @comment = Comment.find(params[:id])
    @comment_like = current_user.comment_likes.build(comment: @comment)
    if @comment_like.save
            @comment.increment!(:likes)
        flash[:success] = 'Thanks for liking!'
    else
        flash[:error] = 'Two many likes'
      end  
        redirect_to(:back)
  end

private
  def set_comment
    @comment = Comment.find(params[:id])
  end

    def load_commentable
        resource, id = request.path.split('/')[1, 2]
        @commentable = resource.singularize.classify.constantize.find(id) #Here it is!
    end

    def comment_params
        params[:comment][:user_id] = current_user.id
        params.require(:comment).permit(:content, :commentable, :user_id, :like)
    end
end

Ошибка возникла из ответа здесь: Как добавить полиморфные комментарии кормить?

разработка.log

Started POST "/comments" for ::1 at 2015-04-23 20:12:14 -0400
Processing by CommentsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"hU1lxg2BMqSyBo8j2SGiEB4wZ3ez5kz/E64mp6ssbwBnh+DddyTtNQxY+IYCluHHvs2wIBxrtD5hQVA5sGtXBg==", "comment"=>{"content"=>"test"}, "button"=>""}
  [1m[35mUser Load (0.2ms)[0m  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1  [["id", 2]]
  [1m[36mHabit Load (0.1ms)[0m  [1mSELECT "habits".* FROM "habits" WHERE "habits"."user_id" = ?[0m  [["user_id", 2]]
  [1m[35mHabit Load (2.5ms)[0m  SELECT "habits".* FROM "habits"
  [1m[36mActsAsTaggableOn::Tag Load (0.3ms)[0m  [1mSELECT "tags".* FROM "tags" WHERE (LOWER(name) = LOWER('ingrain'))[0m
  [1m[35mComment Load (0.3ms)[0m  SELECT  "comments".* FROM "comments" WHERE "comments"."id" = ? LIMIT 1  [["id", nil]]
Completed 404 Not Found in 16ms

ActiveRecord::RecordNotFound (Couldn't find Comment with 'id'=):
  app/controllers/comments_controller.rb:61:in `load_commentable'

Большое спасибо!


person AnthonyGalli.com    schedule 22.04.2015    source источник
comment
Могу я спросить, что вы пытаетесь сделать с этой строкой? Похоже, это работает до Comment.find(id). Если да, то можно упростить? Отдельно основная проблема заключается в том, что @commentable может быть нулевым, и вы не защищаете от этого, насколько я вижу.   -  person steve klein    schedule 24.04.2015
comment
Эй, @steveklein, да, я думаю, мы можем упростить до того, что даст нам: undefined local variable or method 'id. Я получил код из этого эпизода railscasts: -исправлено. Он также предлагает другую альтернативу: def load_commentable klass = [Valuation].detect { |c| params["#{c.name.underscore}_id"]} @commentable = klass.find(params["#{klass.name.underscore}_id"]) end, которая затем дает undefined method 'name' for nil:NilClass для 2-й строки.   -  person AnthonyGalli.com    schedule 24.04.2015
comment
Нам нужно определить имя комментируемого ресурса и его id. Мы получим их из request.path, разбивая его на каждую косую черту и захватывая второй и третий элементы, поэтому, если путь /valuations/1, это будут два используемых элемента. Мы можем использовать их для установки @commentable, вызвав singlelularize.classify.constantize, чтобы получить класс модели, и вызвав find для этого, чтобы получить экземпляр по идентификатору. Не знаю, как это обойти @steveklein   -  person AnthonyGalli.com    schedule 24.04.2015


Ответы (2)


Проблема в том, что для того, чтобы это работало, похоже, что комментарии настроены как вложенный ресурс того, что вы комментируете в своем файле маршрутов.

Итак, если вам нужны комментарии к действиям, у вас будет:

resources :activites do
  resources :comments
end

Таким образом, когда метод #load_commentable выбирает путь запроса, он получит комментируемое и идентификатор из первых двух сегментов.

Вместо этого похоже, что вы пытаетесь использовать комментарии в качестве ресурса верхнего уровня.

ОБНОВЛЕНИЕ: когда вы вызываете свой частичный запрос, просто передайте вспомогательную функцию URL, которую должна использовать форма. Как это:

<%= render "comments/form", new_comment: Comment.new(commentable_id: activity.id, commentable_type: activity.class.model_name), create_url: :activity_comments_path %>

Затем, в партиале, просто вызовите этот помощник и передайте результат в качестве параметра URL-адреса, например:

<%= form_for new_comment, url: send(create_url, new_comment.commentable)
person Joe Martinez    schedule 24.04.2015
comment
У меня уже было это, но у меня также было это как ресурс высшего уровня. Я удалил его как ресурс верхнего уровня, и теперь я получаю сообщение об ошибке: undefined method 'comments_path' for ... строка: <%= form_for new_comment do |f| %> так что, возможно, вы что-то поняли. - person AnthonyGalli.com; 24.04.2015
comment
Когда вы передаете локальную переменную new_comment партиалу, попробуйте ее как activity.comments.build — если это не генерирует путь с использованием помощника пути вложенного ресурса, вы можете просто передать помощник пути, который вы хотите использовать. - person Joe Martinez; 24.04.2015
comment
Эй, Джо Мартинес, только что закончил беседу со Стивом. Мы не смогли ее решить. Может быть невозможно. Вы готовы поболтать? Спасибо Джо! - person AnthonyGalli.com; 24.04.2015
comment
Это определенно возможно - вам просто нужно пройти через хелпер пути к вашему частичному комментарию. Есть ли у обмена стеками функция чата? - person Joe Martinez; 26.04.2015
comment
Да, может быть, вы можете помочь мне попробовать, прежде чем я полностью сдаюсь. Встретимся здесь, если сможешь Джо: chat.stackoverflow.com/rooms /76301/ Спасибо за помощь! - person AnthonyGalli.com; 26.04.2015
comment
Джо, в какое время ты работаешь? Вы передумали общаться? Извините за настойчивость, я просто очень хочу это сделать - ваша моя последняя надежда :/ - person AnthonyGalli.com; 29.04.2015
comment
Похоже, мы никогда не онлайн одновременно - лол. Если вы опубликуете свое мнение и свое частичное содержание, я покажу вам изменение, которое, как я думаю, исправит это. - person Joe Martinez; 29.04.2015
comment
Я обновил свой пример, указав, как вы должны передать вспомогательный URL-адрес, чтобы это сработало. Убедитесь, что вы также используете вложенные маршруты, которые я описал в первой части моего ответа. Удачи! - person Joe Martinez; 29.04.2015

В load_commentable перед действием вы можете перенаправить на страницу с ошибкой или что-то еще, если @commentable равно nil. Как бы то ни было, вы пытаетесь получить доступ к атрибутам этого nil объекта другими методами (create в случае этой ошибки).

person steve klein    schedule 24.04.2015
comment
Мне трудно реализовать то, что вы имеете в виду: / Проблема заключается в том, что когда я нажимаю «Отправить», не будут ли они все нулевыми, поскольку сначала нужно сохранить? Вы предлагаете добавить условие к строке before_action :load_commentable? Никогда такого не видел, поэтому думаю, что неправильно понимаю. жаль Стив. - person AnthonyGalli.com; 24.04.2015
comment
Разве вы не ожидаете, что @commentable будет действительным (а не nil), когда вы create и comment? Вы просто используете before_action для удобства - если бы вы переместили этот код в начале каждого зависимого действия, вы бы никогда не работали с потенциально nil объектом. Вот почему я не сторонник использования before_action таким образом — это не очень прозрачно. В конце load_commentable можно добавить redirect_to root_path if @commentable == nil. При необходимости можем организовать чат. - person steve klein; 24.04.2015
comment
Давай сделаем это! У меня возникла проблема с вашим последним комментарием. Хотите встретиться со мной здесь: chat.stackoverflow.com/rooms/76194/ ? - person AnthonyGalli.com; 24.04.2015