Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Voting update on Ruby on Rails

Right now, I'm in the middle of building a social media app on Ruby on Rails, i have implemented a 5 point voting system. Where you can vote the news posted on the site from 1-5, what I'd like to know is, What is the best approach at handling the updates on the voting system.

In example. If a user already voted in an article I'd like to bring back score he gave in the article and soft-lock the voting (since i only allow 1 vote per user and i allow to change your vote at any time), but if he hasn't I'll bring up the article with the the voting on 0.

I know a way to accomplish this, i could do it in the view, and check if the current user has already voted on this article i would send them to the EDIT view otherwise to the SHOW view. (I think)

Anyways, what would be the "correct" approach to do this?

EDIT: I forgot to say that the voting combo box it's a partial that I'm rendering. Am i suppose to just update the partial somehow?

EDIT2:

class Article < ActiveRecord::Base

  has_many :votes
  belongs_to :user

  named_scope :voted_by, lambda {|user| {:joins => :votes, :conditions => ["votes.user_id = ?",  user]}  }
end

class User < ActiveRecord::Base
  has_many :articles
  has_many :votes, :dependent => :destroy

  def can_vote_on?(article)
    Article.voted_by(current_user).include?(article) #Article.voted_by(@user).include?(article)
  end

end
like image 301
Gotjosh Avatar asked May 28 '26 15:05

Gotjosh


1 Answers

Create a method in the User model that responds true if the user can vote on an article:

class User < ActiveRecord::Base

...

def can_vote_on?(article)
  articles_voted_on.include?(article) # left as an exercise for the reader...
end

end

In the view, render a form if the user can edit, otherwise render a normal view:

<% if @user.can_vote_on?(@article) %>
  <%= render :partial => "vote_form" %>
<% else %>
  <%= render :partial => "vote_display" %>
<% end %>

Or you could handle the whole thing in the controller, and render separate templates for the form version and the normal version. The best approach depends on the specifics of your situation.

EDIT2

As you discovered, current_user doesn't work in the model. This makes sense, because the can be called from migrations, libraries, etc., where there is no concept of a session.

There's no need to access the current user anyway, since your instance method is (by definition) being called on an instance. Just refer to self in the model, and call the method from the view on current_user, which is an instance of User:

(in the model)

  def can_vote_on?(article)
    Article.voted_by(self).include?(article)
  end

(in the view)

<% if current_user.can_vote_on?(@article) %>

Or you could substitute @user for current_user if the controller assigns it.

One last thing, I think your named scope should use user.id, like so:

named_scope :voted_by, lambda {|user| {:joins => :votes, :conditions => ["votes.user_id = ?",  user.id]}  }
like image 72
zetetic Avatar answered May 31 '26 04:05

zetetic



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!