Star rating System in Ruby on Rails (AJAX based)
After looking at couple of websites, I realized that AJAX based rating system are a must for any socieal networking website :). So here is how I implemented it (I used mostly instructions from Dave Naffi's website to implement this.
Steps
1)Download Acts as rateable plugin from Juxie.com
2) Creating ratings table where you will be storing your ratings:
OR you can use migrations (should you migrations ;)) in a file named xxx_add_ratings_table.rb in db/migrate directory of your application
Please note that here my ratings is associated with a model named "Association". The neat thing about acts_as_rateable plugin is that it will automatically notice this and accordingly calculate the weight by averaging the votes by number of members who voted. (pretty cool :)). Also one other good thing is that you can more than one model as rateable. I haven't tried this feature but I noticed that the ratings table stores the name of the rateable model in the field named "rateable_type"
3) Now its time to associate our model ("Association" in my case) to ratings table.
Here is how you do it (for my case the file is/model/Association.rb)
class Association <>
If you are eager to see how you databae entries would look like, here is an e.g
4) Now its time to add images, views, partials and controller
Controller (/controllers/ratings_controller.rb)
views (/views/view_in_which_you_want_to_display_your_ratings html )
Views - Partial (/views/rating/_rating.html). I have 5 list items because I am rating my "association" with 0 to 5 stars
Views (/views/ratings/rate.rjs) This calls the page.replace_html method which replaces html in a given div (start-ratings-block in my case)
Lastly we need to add css for class 'star-rating'
Here is it
Note that my images are copied in images directory inside public directory of application.
Here are the images incase you want to use them (Please change the width in the *-stars* block in your css if you end up using some other image
star_rating.gif
all_star.gif
After looking at couple of websites, I realized that AJAX based rating system are a must for any socieal networking website :). So here is how I implemented it (I used mostly instructions from Dave Naffi's website to implement this.
Steps
1)Download Acts as rateable plugin from Juxie.com
Command> cd
Command> ruby script\install http://juixe.com/svn/acts_as_rateable
2) Creating ratings table where you will be storing your ratings:
mysql> desc ratings;
+---------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| rating | int(11) | YES | | 0 | |
| created_at | datetime | NO | | | |
| rateable_type | varchar(15) | NO | | | |
| rateable_id | int(11) | NO | | 0 | |
| member_id | int(11) | YES | MUL | NULL | |
+---------------+-------------+------+-----+---------+----------------+
OR you can use migrations (should you migrations ;)) in a file named xxx_add_ratings_table.rb in db/migrate directory of your application
class AddRatingsTable< force =""> true do |t|
t.column :rating, :integer, :default => 0
t.column :created_at, :datetime, :null => false
t.column :rateable_type, :string, :limit => 15,
:default => "", :null => false
t.column :rateable_id, :integer, :default => 0, :null => false
t.column :member_id, :integer , :null => false
end
end
def self.down
drop_table :ratings
end
end
Please note that here my ratings is associated with a model named "Association". The neat thing about acts_as_rateable plugin is that it will automatically notice this and accordingly calculate the weight by averaging the votes by number of members who voted. (pretty cool :)). Also one other good thing is that you can more than one model as rateable. I haven't tried this feature but I noticed that the ratings table stores the name of the rateable model in the field named "rateable_type"
3) Now its time to associate our model ("Association" in my case) to ratings table.
Here is how you do it (for my case the file is
class Association <>
If you are eager to see how you databae entries would look like, here is an e.g
mysql> select * from ratings limit 5;
+----+--------+---------------------+---------------+-------------+-----------+
| id | rating | created_at | rateable_type | rateable_id | member_id |
+----+--------+---------------------+---------------+-------------+-----------+
| 3 | 5 | 2006-12-18 22:08:12 | Association | 42 | 18 |
| 4 | 5 | 2006-12-19 07:03:04 | Association | 27 | 18 |
| 8 | 5 | 2006-12-19 07:03:55 | Association | 36 | 18 |
| 9 | 5 | 2006-12-19 07:03:57 | Association | 39 | 18 |
| 11 | 3 | 2006-12-19 07:04:04 | Association | 40 | 18 |
+----+--------+---------------------+---------------+-------------+-----------+
- id: is the id of ratings table
- rating: is the ratings itself (In my case ratings go from 1 to 5)
- created_at: date time when the entry was created
- rateable_type : The model , Association in my case
- rateable_id : Association id (just a reminder...association is the model which stores some text and this text is being rated by users. You can imagine it as a testimonial in orkut/linkedin)
- member_id: The user id of the user. In my case all this info is stored in members table
4) Now its time to add images, views, partials and controller
Controller (
class RatingController < association =" Association.find(params[:id])" rateable_type =" 'Association'" rateable_id =" ?" member_id =" ?" rating =""> params[:rating], :member_id => current_member.id) #add a new entry containinig the rating (1-5), association id (both this stored in the param[:rating] and member id)
end
end
views (
Views - Partial (/views/rating/_rating.html). I have 5 list items because I am rating my "association" with 0 to 5 stars
<ul class='star-rating'>
<li class='current-rating' style='width:<%(association.rating * 30).to_i -%>px;'>
Currently <%= number_with_precision(association.rating, 1) %>/5 Stars.
</li>
<li>
<%= link_to_remote( "1", {:url => { :controller => "rating",
:action => "rate", :id => association.id, :rating => 1}},
:class => 'one-star', :name => '1 star out of 5') %>
</li>
<li>
<%= link_to_remote( "2", {:url => { :controller => "rating",
:action => "rate", :id => association.id, :rating => 2}},
:class => 'two-stars', :name => '2 stars out of 5') %>
</li>
<li>
<%= link_to_remote( "3", {:url => { :controller => "rating",
:action => "rate", :id => association.id, :rating => 3}},
:class => 'three-stars', :name => '3 stars out of 5') %>
</li>
<li>
<%= link_to_remote( "4", {:url => { :controller => "rating",
:action => "rate", :id => association.id, :rating => 4}},
:class => 'four-stars', :name => '4 stars out of 5') %>
</li>
<li>
<%= link_to_remote( "5", {:url => { :controller => "rating",
:action => "rate", :id => association.id, :rating => 5}},
:class => 'five-stars', :name => '5 stars out of 5') %>
</li>
</ul>
Views (
page.replace_html "star-ratings-block#{@association.id}", :partial => 'rating/rating', :locals => { :association => @association }
#note I am replacing the div named "start-ratings-block" (e.g. star-ratings-block45). This is possible because I named by div by conctenating the id of "association".
Lastly we need to add css for class 'star-rating'
Here is it
/* styles for the star rater */
.star-rating{
list-style:none;
margin: 0px;
padding:0px;
width: 150px;
height: 30px;
position: relative;
background: url(/images/star_rating.gif) top left repeat-x;
}
.star-rating li{
padding:0px;
margin:0px;
/*\*/
float: left;
/* */
}
.star-rating li a{
display:block;
width:30px;
height: 30px;
text-decoration: none;
text-indent: -9000px;
z-index: 20;
position: absolute;
padding: 0px;
}
.star-rating li a:hover{
background: url(/images/star_rating.gif) left center;
z-index: 2;
left: 0px;
}
.star-rating a.one-star{
left: 0px;
}
.star-rating a.one-star:hover{
width:30px;
}
.star-rating a.two-stars{
left:30px;
}
.star-rating a.two-stars:hover{
width: 60px;
}
.star-rating a.three-stars{
left: 60px;
}
.star-rating a.three-stars:hover{
width: 90px;
}
.star-rating a.four-stars{
left: 90px;
}
.star-rating a.four-stars:hover{
width: 120px;
}
.star-rating a.five-stars{
left: 120px;
}
.star-rating a.five-stars:hover{
width: 150px;
}
.star-rating li.current-rating{
background: url(/images/star_rating.gif) left bottom;
position: absolute;
height: 30px;
display: block;
text-indent: -9000px;
z-index: 1;
}
Note that my images are copied in images directory inside public directory of application.
Here are the images incase you want to use them (Please change the width in the *-stars* block in your css if you end up using some other image
star_rating.gif
all_star.gif
Comments