充当嵌套资源的Votable

时间:2017-02-05 21:32:19

标签: javascript jquery html ruby-on-rails

我是铁杆上的新手,已经创建了一个列表和评论应用程序,(yelp类型),我希望用户对评论进行投票,我已经安装了act作为可投票并配置如下,但我似乎缺少一些东西...任何想法为什么会出现这个错误?

以下是我的routes.rb

Rails.application.routes.draw do

  devise_for :users

  resources :listings do
    resources :reviews, except: [:show, :index, :upvote, :downvote] do
      resources :user do
        put "upvote", to: "reviews#upvote"
        put "downvote", to: "reviews#downvote"
      end
    end
  end

  get 'pages/about'

  get 'pages/how'

  get 'pages/faqs'

  get 'pages/contact'

  get 'pages/privacy'

  get 'pages/tos'

  get 'pages/guidelines'

  root 'listings#index'

  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end

这是我的show.html.erb,我会在工作时将其变为部分

<div class="row">
  <div class="col-md-3">
    <%= image_tag @listing.image_url (:medium) %>
      <h3><%= @listing.name %></h3>
        <div class="star-rating" data-score= <%= @avg_rating  %> ></div>
          <p class="small"><%= "#{@reviews.length} reviews" %></p>
          <address>
            <strong>Address:</strong>
            <%= @listing.address %><br>
            <strong>Phone:</strong>
            <%= @listing.phone %><br>
            <strong>Email:</strong>
            <%= mail_to @listing.email %> <br>
            <strong>Website:</strong>
            <%= link_to @listing.website, @listing %>
          </address>
        <hr>
          <p>
            <strong>About:</strong>
            <p><%= h(@listing.description).gsub(/\n/, '<br/>').html_safe %></p>
          </p>
  </div>
  <div class="col-md-9">
    <%= link_to "Haiya, Post a Review ", new_listing_review_path(@listing), class: "btn btn-info" %> <br><br>
      <table class="table">
        <thead>
            <tr>
              <th class="col-md-3"></th>
              <th class="col-md-9"></th>
            </tr>
          </thead>           
          <tbody>
             <% if @reviews.blank? %>
             <tr>
              <p>No reviews yet. Be the first to write one!</p>
            <% else %>
                <% @reviews.each do |review| %>              
                    <td>
                      <h4> <%= "#{review.user.first_name.capitalize} #{review.user.last_name.capitalize[0]}." %></h4>
                      <p class = "small"><%= time_ago_in_words(review.created_at) %> ago </p>
                    </td>

                    <td>
                      <div class="star-rating" data-score= <%= review.rating %> ></div>
                      <p><%= h(review.comment).gsub(/\n/, '<br/>').html_safe %></p>

                      <%= link_to 'UP', listing_review_user_upvote_path(@listing, review), method: :put %>

                      <!-- Check if user is signed in, to enable edit and update -->
                      <% if user_signed_in? %>
                      <% if (review.user == current_user) || (current_user.admin?) %>
                      <%= link_to "Edit", edit_listing_review_path(@listing, review), class: "text-left"  %>
                      <%= link_to "Delete", listing_review_path(@listing, review), method: :delete, class: "text-left"  %>     
                      <% end %>
                    <% end %>

                </td>
              </tr>
            <% end %>
            <% end %>
          </tbody>

        </table>
  </div>
</div>
<% if user_signed_in? && current_user.admin? %>
<%= link_to 'Edit', edit_listing_path(@listing), class: "btn btn-link" %> |
<% end %>
<%= link_to 'Back', listings_path, class: "btn btn-link" %>

<!--The script for star ratings. -->

<script>
  $('.star-rating').raty({
    path: 'https://s3.eu-west-2.amazonaws.com/bebuwaphotos/uploads/stars',
    readOnly: true,
    score: function() {
      return $(this).attr('data-score');
    }
  });
</script>

这是我的评论控制器

class ReviewsController < ApplicationController
  before_action :authenticate_user! 
  before_action :set_listing
  before_action :set_review, only: [:show, :edit, :update, :destroy, :upvote, :downvote]
  before_action :check_user, only: [:edit, :update, :destroy]


  # GET /reviews/new
  def new
    @review = Review.new
  end

  # GET /reviews/1/edit
  def edit
  end

  #Added the def upvote and downvote
  def upvote
    @review = Review.find(params[:id])
    @review.upvote_from current_user
    redirect_to :back
  end

  def downvote
    @review = Review.find(params[:id])
    @review.downvote_from current_user
    redirect_to :back
  end


  # POST /reviews
  # POST /reviews.json
  def create
    @review = Review.new(review_params)
    @review.user_id = current_user.id
    @review.listing_id = @listing.id

    respond_to do |format|
        if @review.save
          format.html { redirect_to @listing, notice: 'Your review was successfully posted.' }
          format.json { render :show, status: :created, location: @review }
        else
          format.html { render :new }
          format.json { render json: @review.errors, status: :unprocessable_entity }
        end
      end
    end

  # PATCH/PUT /reviews/1
  # PATCH/PUT /reviews/1.json
  def update
    respond_to do |format|

      if @review.update(review_params)
        format.html { redirect_to root_url, notice: 'Your Review was successfully updated.' }
        format.json { render :show, status: :ok, location: @review }
      else
        format.html { render :edit }
        format.json { render json: @review.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /reviews/1
  # DELETE /reviews/1.json
  def destroy
    @review.destroy
    respond_to do |format|
      format.html { redirect_to listing_path(@listing), notice: 'Your Review was successfully destroyed :(.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_review
      @review = Review.find(params[:id])
    end

    #Check user

     def check_user
      unless (@review.user == current_user) || (current_user.admin?)
        redirect_to root_url, alert: "Sorry, this review belongs to someone else, you can only edit reviews you have posted."
      end
    end


    #set listing

    def set_listing
      @listing = Listing.find(params[:listing_id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def review_params
      params.require(:review).permit(:rating, :comment)
    end
   
end

我的模特:

class Review < ApplicationRecord
	belongs_to :user
	belongs_to :listing
	validates :rating, :comment, presence: true
  	validates :rating, numericality: {
	    only_integer: true,
	    greater_than_or_equal_to: 1,
	    less_than_or_equal_to: 5,
	    message: "You have to select at least 1 star if not more stars.."
	    }

	acts_as_votable 
  									
end

最后这是我的错误

enter image description here

请像新手一样解释..或者5岁。

谢谢你,Eshan,按照你的回答,得到以下错误。

enter image description here

1 个答案:

答案 0 :(得分:1)

  1. 你作为一个新手做得很好。

  2. 当您收到与路线相关的错误时,您要做的第一件事就是在命令行中运行rails routes,这样您就可以在您面前看到您的路线:

  3. enter image description here

    问题:

    您遇到listing_review_user_upvote路径问题,导致/listings/:listing_id/reviews/:review_id/user/:user_id/upvote(.:format) URI模式如上所示。

    此路线需要三个参数: listing_id review_id user_id ,但您可以在视图中以这种方式调用它:

    listing_review_user_upvote_path(@listing, review)

    您根本不发送 user_id ,同时您甚至不需要它,因为您在控制器的操作中使用了 current_user

    解决方案:

    我建议您将路线更新为:

    resources :listings do
        resources :reviews, except: [:show, :index] do
          put "upvote", to: "reviews#upvote"
          put "downvote", to: "reviews#downvote"
          resources :user
        end
    end
    

    并以这种方式在视图中使用它,使用id而不是对象:

    listing_review_user_upvote_path(@listing.id, review.id)

    这两个步骤有望解决您的问题。

    最后,except选项与资源一起使用,以避免生成一些CRUD路由,如:updateindexedit,您不需要与您的自定义路线一起使用,例如:upvotedownvote

    更新

    • 您应该在控制器中使用正确的参数review_id而不是id,将review = Review.find(params[:id])更改为review = Review.find(params[:review_id])

    • 我建议您使用find_by(id: params[:review_id而不是find(params[:review_id,因为如果找不到db中的对象,则find方法会引发异常。