Search code examples
ruby-on-railsrubyrating

Posts Rating - Rails


I am implementing rating system in rails for posts.

On viewing a post one can rate the post by clicking radio button. Below is the code. Consider only the post and rating don't consider tags, topics..

And there is no user in my concept one can rate whenever he needed and it should be added with existing rating of the post.

But, When I am doing this in log it shows the following:

Server log:

Started PATCH "/posts/34" for 127.0.0.1 at 2015-12-08 18:36:55 +0530
Processing by PostsController#update as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"l3aae99V424OyKVt5ULmqX2Mcs7DY2GYBskbLyhqqNENDn24ldCDAt4gNcgjESlFR6eaP0vcvrcoOerGE9lH5A==", "post"=>{"rating_ids"=>["5"]}, "commit"=>"Rate", "id"=>"34"}
  Post Load (0.0ms)  SELECT  "posts".* FROM "posts" WHERE "posts"."id" = ? LIMIT 1  [["id", 34]]
  CACHE (0.0ms)  SELECT  "posts".* FROM "posts" WHERE "posts"."id" = ? LIMIT 1  [["id", "34"]]
   (0.0ms)  begin transaction
  SQL (4.0ms)  INSERT INTO "ratings" ("star", "post_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["star", 5], ["post_id", 34], ["created_at", "2015-12-08 13:06:55.626133"], ["updated_at", "2015-12-08 13:06:55.626133"]]
   (216.0ms)  commit transaction
   (0.0ms)  begin transaction
  Rating Load (1.0ms)  SELECT  "ratings".* FROM "ratings" WHERE "ratings"."id" = ? LIMIT 1  [["id", 5]]
  Rating Load (0.0ms)  SELECT "ratings".* FROM "ratings" WHERE "ratings"."post_id" = ?  [["post_id", 34]]
  SQL (2.0ms)  UPDATE "ratings" SET "post_id" = NULL WHERE "ratings"."post_id" = ? AND "ratings"."id" IN (4, 25)  [["post_id", 34]]
  SQL (3.0ms)  UPDATE "ratings" SET "post_id" = ?, "updated_at" = ? WHERE "ratings"."id" = ?  [["post_id", 34], ["updated_at", "2015-12-08 13:06:55.878147"], ["id", 5]]
   (170.0ms)  commit transaction
Redirected to http://localhost:3000/topics/9
Completed 302 Found in 489ms (ActiveRecord: 397.0ms)

where it changes the post.id to NULL

SQL (2.0ms)  UPDATE "ratings" SET "post_id" = NULL WHERE "ratings"."post_id" = ? AND "ratings"."id" IN (4, 25)  [["post_id", 34]]

I don't know how this happens and how to overcome this So, Please help.

It changes the Rating database as below:

1st column: id, 2nd column: star, 3rd column: post_id

1,1,NULL
2,2,NULL
3,3,NULL
4,4,NULL
5,5,34
6,4,NULL
7,1,NULL
8,1,NULL
9,5,NULL
10,1,NULL
11,5,NULL
12,1,NULL
13,4,NULL
14,3,NULL
15,4,NULL
16,4,NULL
17,4,NULL
18,2,NULL
19,1,NULL
20,5,NULL
21,3,NULL

Post model:

class Post < ActiveRecord::Base
    belongs_to :topic   
    has_many :comments
    has_and_belongs_to_many :tags
  has_many :ratings
end

Rating model:

class Rating < ActiveRecord::Base
  belongs_to :post
end

Post show.html.erb

<p id="notice"><%= notice %></p>

<p>
  <strong>Name:</strong>
  <%= @posts.name %> (
  <%= @posts.topic.name %> )
</p>

<p>
  <strong>Email:</strong>
  <%= @posts.email %>
</p>

<p>
  <strong>Message:</strong>
  <%= @posts.message %>
</p>

 <strong>Tags:</strong>
<% @posts.tags.each do |tag| %>
    <div>
        <%= tag.name %> <br>
    </div>
 <% end %>
<br>

<strong>Rating:</strong>
<%= @posts.ratings.group(:star).count %>


<%= form_for @posts do |f| %>
    <% (1..5).each do |rating| %>

        <%= radio_button_tag "post[rating_ids][]", rating %>
        <%= rating %>

<% end %>

<%= f.submit('Rate') %>

<% end %>


<%= link_to 'Comments', post_comments_path(@posts) %>
<%= link_to 'Edit', edit_post_path(@posts) %> |
<%= link_to 'Back', topic_posts_url(@posts.topic) %>

Post controller:

class PostsController < ApplicationController
  before_action :set_post, only: [:show, :edit, :update, :destroy]

  # GET /posts
  # GET /posts.json
  def index
    if params[:topic_id].to_i > 0
          @topic = Topic.find(params[:topic_id])
          @posts = @topic.posts.paginate(page: params[:page], per_page: 10)
    else
      @posts = Post.eager_load(:topic).paginate(page: params[:page], per_page: 10)
    end
    end

  # GET /posts/1
  # GET /posts/1.json
  def show
      @posts = Post.find(params[:id])
      @tags = @posts.tags
      @comment = Comment.new(:post => @posts)
  end

  # GET /posts/new
  def new
      @topic = Topic.find(params[:topic_id])
    @posts = @topic.posts.new
  end

  # GET /posts/1/edit
  def edit
    @posts = Post.find(params[:id])
    @tags = @posts.tags
  end

  # POST /posts
  # POST /posts.json
  def create
      @topic = Topic.find(params[:topic_id])
    @posts = @topic.posts.build(post_params)

    respond_to do |format|
      if @posts.save
        format.html { redirect_to topic_url(@posts.topic_id), notice: 'Post was successfully created.' }
        format.json { render :show, status: :created, location: @posts }
      else
        format.html { render :new }
        format.json { render json: @posts.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /posts/1
  # PATCH/PUT /posts/1.json
  def update

    @posts = Post.find(params[:id])
    @tags = @posts.tags
    respond_to do |format|
      @posts.ratings.create(:star => params[:post][:rating_ids][0].to_i)
      if @posts.update(post_params)

        format.html { redirect_to topic_url(@posts.topic_id), notice: 'Post was successfully updated.' }
        format.json { render :show, status: :ok, location: @posts }
      else
        format.html { render :edit }
        format.json { render json: @posts.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /posts/1
  # DELETE /posts/1.json
  def destroy
    @posts.destroy
    respond_to do |format|
      format.html { redirect_to topic_url(@posts.topic_id), notice: 'Post was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

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

    # Never trust parameters from the scary internet, only allow the white list through.
    def post_params
      params.require(:post).permit(:name, :email, :message, :topic_id, {tag_ids:[]}, rating_ids:[])
    end
end

I am new to rails and I need to implement this without using any gem.. Please help how it changes the post_id to NULL which I denoted in server log..


Solution

  • This is because after you created a Rating manually then goes @posts.update(rating_ids:[5]), which states that this post only should have rating with id 5, not 5 stars

    Plus are you sure want your unauthenticated users to have access to post editing?