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..
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?