Devise User Review/Rating System in Rails 4 - ruby-on-rails

I'm trying to create a review system on users in rails. I want one user to be able to rate another user on their profile page in devise. I've tried a few different methods but I am fairly new to rails and haven't been able to accomplish this.
Right now I have default devise views but no user profile page. I'd like users to review a another user on 5 or so different issues.
Any help would be much appreciated!

In order to do that, you can use the association called has_many through association :
http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association
Your models should look like that "
class User < ActiveRecord::Base
has_many :rates
has_many :rated_users, through: :rates, class_name: "User", foreign_key: :rated_user_id # The users this user has rated
has_many :rated_by_users, through: :rates, class_name: "User", foreign_key: :rating_user_id # The users that have rated this client
end
class Rates < ActiveRecord::Base
belongs_to :rating_user, class_name: "User"
belongs_to :rated_user, class_name: "User"
end
And your migrations :
class createRates < ActiveRecord::Migration
def change
create_table :changes do |t|
t.belongs_to :rated_user
t.belongs_to :rating_user
t.integer :value
t.timestamps
end
end
end

Oxynum - great concept! After adding models and applying migrations, starts with templates. Starting point for you is a users_controller.rb. Probably, you already have a 'show' action inside UsersController. This action available for authenticated users.
Modify this action to smth like:
class UsersController < ApplicationController
before_filter :authenticate_user!
before_filter :load_ratable, :only => [:show, :update_rating]
def show
# Renders app/views/users/show.html.erb with user profile and rate controls
end
def update_rating
my_rate_value = params[:value] == 'up' ? +1 : -1
if #rated_by_me.blank?
Rate.create(rated_user: #userProfile, rating_user: #user, value: my_rate_value)
flash[:notice] = "You rated #{#userProfile.name}: #{params[:value]}"
else
flash[:notice] = "You already rated #{#userProfile.name}"
end
render action: 'show'
end
protected:
def load_ratable
#userProfile = User.find(params[:id]) # - is a viewed profile.
#user = current_user # - is you
#rated_by_me = Rate.where(rated_user: #userProfile, rating_user: #user)
end
end
Add to routes:
get 'users/update_rating/:value' => 'user#update_rating'
Start rails server, Log In, and try to change rating directly:
http://localhost:3000/users/update_rating/up

Related

Rails has to and belongs to many correct rails association?

I'm setting up my rails association for an app and I'm not sure if my associations are correct for my use case. The use case is: A product can be added once by a user. Once created other users can then add the same product to their own "feed" within the app. I want to be able to do User.products to list all of a users products. And for products I want to be able to do something like Product.where(id: 2).users to list all of the users that have added the product. I'm currently using a has_and_belongs_to_many association but I think that this is incorrect for what I am trying to achieve?
User model: has_and_belongs_to_many :products
Product model: has_and_belongs_to_many :users
add_index "products_users", ["product_id"], name: "index_products_users_on_product_id"
add_index "products_users", ["user_id"], name: "index_products_users_on_user_id"
Do this:
#app/models/user.rb
class User < ActiveRecord::Base
has_many :created_products, class_name: "Product", foreign_key: :user_id #-> created product
has_and_belongs_to_many :products #-> list of products
end
#app/models/product.rb
class Product < ActiveRecord::Base
belongs_to :user #-> created the product
has_and_belongs_to_many :users #-> list of users
end
You'll need to add the appropriate foreign_key to your User model (user_id in the Product model for the belongs_to :user association) --
--
If your has_and_belongs_to_many relationship is working already, the above should be sufficient.
If not, you need to look up this documentation to see how it works, and then create a join table called products_users (which is populated with the appropriate data):
$ rails g migration CreateProductsUsers
#db/migrate/create_products_users______.rb
class CreateProductsUsers < ActiveRecord::Migration
def change
create_table :products_users, id: false do |t|
t.references :product
t.references :user
end
end
end
$ rake db:migrate
It will allow you to create a single product for a user (IE the Product object will have a direct association with the user who created it). The Product and User models will also be joined with the habtm relationship.
In your controllers, you could use the following:
#config/routes.rb
resources :products #-> url.com/products
scope "profile" do
resources :products, only: :index #-> url.com/profile/products
end
This will allow you to use the following:
#app/controllers/products_controller.rb
class ProductsController < ApplicationController
before_action :product, only: :edit
def index
#products = current_user.products #-> if you're using Devise
end
def edit
#product = current_user.created_products.find params[:id]
end
def new
#product = current_user.created_products.new
end
def create
#product = current_user.created_products.new product_params
#product.save
end
private
def product
redirect_to root_path, notice: "This is not your product" unless current_user.products.exists? params[:id]
end
def product_params
params.require(:product).permit(:x, :y, :z)
end
end
To be able using has_and_belongs_to_many create association, you must create one temperator table container 2 column are product_id, user_id
you can refer
http://apidock.com/rails/ActiveRecord/Associations/ClassMethods/has_and_belongs_to_many
http://guides.rubyonrails.org/association_basics.html#the-has-and-belongs-to-many-association

Ruby on Rails relationship model

In Ruby on Rails 4, how do you create a many-to-many relationship inside a relationship model for a friends list such as Facebook using the has_many :through ... syntax ?? I'm a newbie and currently learning Ruby on Rails 4. I have looked at this link.
But still have a hard time grasping it.
you will need a join table that references both sides of the relations
let us say you have an relation Post and another relation Category with a many to many relationship between them you need a join table to be able to represent the relationship.
migration for a join table would be
class CreateCategoriesPosts < ActiveRecord::Migration
def change
create_table :categories_posts do |t|
t.integer :category_id
t.integer :post_id
t.timestamps
end
add_index :categories_posts, [:category_id, :post_id]
end
end
and in the models/post.rb
Class Post < ActiveRecord::Base
has_and_belongs_to_many :categories
end
and in the models/category.rb
Class Category < ActiveRecord::Base
has_and_belongs_to_many :posts
end
more here:
http://guides.rubyonrails.org/association_basics.html#the-has-and-belongs-to-many-association
I think #RAF pretty much nailed it. But to use the OP's example:
class User < ActiveRecord::Base
has_and_belongs_to_many :users_list
end
class UsersList < ActiveRecord::Base
has_and_belongs_to_many :users
end
Although at first it might seem like a User should have only one list of friends (UsersList), that might not always be the case. Think of types within the UserList model, such as: 'close friends', 'work friends', 'all friends' for example.
My advice: dig into the Rails guides. This is a concept worth learning and truly understanding (which I'm still doing :).
many-to_many relationships are a simple concept, but complex when using the database because of the way databases work. A person could have 1 to N different friends, which means that a single entry for a database would need a dynamic amount of memory for each entry, which in the db world is a no-no. So instead of creating a list of friends you would have to make a table that represents the links between friends, for example:
friendship.rb
class Friendship < ActiveRecord::Base
belongs_to :friend, foreign_key: 'friend_A' # this entry has a field called 'friend_A'
belongs_to :friend, foreign_key: 'friend_B' # this entry has a field called 'friend_B'
end
These links will represent your network of friends. However, as the two previous answers have mentioned, Rails has some nifty magic, "has_and_belongs_to_many", which will do this for you.
NOTICE: The problem here is that in my StatusesController, in the index action, the #relationship object only gets the statuses of all your friends, but does not get your own statuses. Is there a better way of approaching this? I am trying to create a view to view all statuses of users that are your friends, and your own statuses too, and so far, I can't seem to figure out how to order it chronologically, even if in my status model, i included "default_scope -> { order(created_at: :desc) } ". Any advice would be deeply appreciated
class User < ActiveRecord::Base
has_many :relationships
has_many :friends, :through => :relationships
has_many :inverse_relationships, class_name: 'Relationship', foreign_key: 'friend_id'
has_many :inverse_friends, through: 'inverse_relationships', :source => :user end
#
class Relationship < ActiveRecord::Base
# before_save...
belongs_to :user
belongs_to :friend, class_name: 'User'
end
#
class RelationshipsController < ApplicationController
def friend_request
user_id = current_user.id
friend_id = params[:id]
if Relationship.where( user_id: user_id, friend_id: friend_id, accepted: false).blank?
Relationship.create(user_id: user_id, friend_id: friend_id, accepted: false)
redirect_to user_path(params[:id])
else
redirect_to user_path(params[:id])
end
end
def friend_request_accept
# accepting a friend request is done by the recipient of the friend request.
# thus the current user is identified by to_id.
relationship = Relationship.where(user_id: params[:id], friend_id: current_user.id).first
if Relationship.exists?(relationship) and relationship.accepted == false
relationship.update_attributes(accepted: true)
end
redirect_to relationships_path
end
def friend_request_reject
relationship = Relationship.where(user_id: params[:id], friend_id: current_user.id).first
relationship.destroy
redirect_to relationships_path
end
################################
def index
#relationships_pending = Relationship.where(friend_id: current_user.id, accepted: false)
end
end
#
class StatusesController < ApplicationController
def index
#status = Status.new
#relationship = Relationship.where('friend_id = ? OR user_id = ?', current_user.id, current_user.id).
where( accepted: true)
end
def new
#status = Status.new
end
end
#

Ruby on Rails - Limit a user to a set number of database entries

I want to limit the amount of records a user can add to the database.
I'm not sure of the 'Rails' way to go about this...
I am using Devise and thought of creating a custom validation method but you can't access current_user from within a model and it isn't correct.
How can I do this from the controller and still return an error message to my users?
I had this
validate :post_count
def post_count
current = current_user.posts.count
limit = current_user.roles.first.posts.count
if current > limit
errors.add(:post, "Post limit reached!")
end
end
but it isn't the correct way to go about it as it would be hacky to get the current_user into the model
You could do something like this:
class User < ActiveRecord::Base
has_many :domains
has_many :posts, through: :domains
def post_limit
roles.first.posts.count
end
end
class Domain < ActiveRecord::Base
belongs_to :user
has_many :posts
end
class Post < ActiveRecord::Base
belongs_to :domain
delegate :user, to: :domain
validate :posts_count_within_limit, on: :create
def posts_count_within_limit
if self.user.posts(:reload).count >= self.user.post_limit # self is optional
errors.add(:base, 'Exceeded posts limit')
end
end
end
Based on this answer.

remove specific user from joined table

In Ruby on Rails I have a user models and a jobs model joined through a different model called applicants. I have a button for the users when they want to "remove their application for this job" but I don't know how to remove the specific user, and for that matter I don't know if I'm doing a good job at adding them either (I know atleast it works).
user.rb
class User < ActiveRecord::Base
...
has_many :applicants
has_many:jobs, through: :applicants
end
job.rb
class Job < ActiveRecord::Base
...
has_many :applicants
has_many:users, through: :applicants
end
applicant.rb
class Applicant < ActiveRecord::Base
belongs_to :job
belongs_to :user
end
when someone applies for a job my jobs controller is called:
class JobsController < ApplicationController
...
def addapply
#job = Job.find(params[:id])
applicant = Applicant.find_or_initialize_by(job_id: #job.id)
applicant.update(user_id: current_user.id)
redirect_to #job
end
...
end
Does that .update indicate that whatever is there will be replaced? I'm not sure if I'm doing that right.
When someone wants to remove their application I want it to go to my jobs controller again but I'm not sure what def to make, maybe something like this?
def removeapply
#job = Job.find(params[:id])
applicant = Applicant.find_or_initialize_by(job_id: #job.id)
applicant.update(user_id: current_user.id).destroy
redirect_to #job
end
does it ave to sort through the list of user_ids save them all to an array but the one I want to remove, delete the table then put them all back in? I'm unsure how this has_many works, let alone has_many :through sorry for the ignorance!
thanks!
Let's assume the user will want to remove their own application. You can do something like this:
class UsersController < ApplicationController
def show
#applicants = current_user.applicants # or #user.find(params[:id]), whatever you prefer
end
end
class ApplicantsController < ApplicationController
def destroy
current_user.applications.find(params[:id]).destroy
redirect_to :back # or whereever
end
end
And in your view:
- #applicants.each do |applicant|
= form_for applicant, method: :delete do |f|
= f.submit
Don't forget to set a route:
resources :applicants, only: :destroy
Some observations, I would probably name the association application instead of applicant. So has_many :applications, class_name: 'Applicant'.

Rails, devise, acl

I have followed this tut http://railsapps.github.com/tutorial-rails-bootstrap-devise-cancan.html I want to do something like this:
before_filter :authenticate_user!
before_filter :authenticate_VIP!
before_filter :authenticate_admin!
before_filter :authenticate_somerole!
I have tables: roles, users, user_roles and I don't want to create another table (rails g devise VIP create another table).
I want to have methods authenticate_ROLE. How to do this ?
I have three table, Users, Roles, and RoleRelationships (or role_users, it's up to you)
This is my Role table:
class Role < ActiveRecord::Base
attr_accessible :name
has_many :role_relationships
has_many :users, through: :role_relationships
end
Role table will have name column for roles, like: "admin", "teacher", "vip" (as you want).
And this is User table:
class User < ActiveRecord::Base
devise ...
has_many :role_relationships
has_many :roles, through: :role_relationships
end
and my RoleRelationship table:
class RoleRelationship < ActiveRecord::Base
attr_protected :role_id, :user_id
belongs_to :user
belongs_to :role
end
I set up my app one user can have many roles, you can set up your way. So, i have a role?(role) method in my user.rb, like this:
def role?(role)
return role == RoleRelationship.find_by_user_id(self.id).role.name
end
Then in my abilities files, i define abilities of users:
def initialize(user)
user ||= User.new # guest user
if user.role? "teacher"
can :read, Course
can :manage, Topic, user_id: user.id
can :create, Topic
else user.role? "admin"
can :manage, Course
end
So, teacher will only read Course, and admin can CRUD Course. To do that, i use method load_and_authorize_resource in my CoursesController:
class CoursesController < ApplicationController
load_and_authorize_resource
before_filter :authenticate_user!
...
end
Finally, in my views, i used code like this:
<% if can? manage, #course %>
Only admin can work, see what happen here.
<% end %>
So, as you see, teacher only can read Course so they can't see or do what admin can do, in this case, is create course or edit course.
This is what i built in my online test app, you can reference and do the same for your app.

Resources