views:

152

answers:

1

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
+1  A: 

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]}  }
zetetic
where should i define this method? articles_voted_on
Gotjosh
You could create a named scope in the User model to retrieve the articles voted on.
zetetic
Are you certain that i have to create the named scope on the Users model? I've been struggling with this for a couple of days now and i can't seem to think how can i actually return a list of articles the current user has voted on, however i did managed to accomplish this from the Articles model easily, i have edited my post and added the method. Perhaps you could sunlight me a little more.
Gotjosh
See my edit. Does that help?
zetetic
Yes, it does. (that's what I've been looking for a way that i can reference the user itself inside the user model) However the object @user keeps coming out null, do i need to instantiate it somewhere?
Gotjosh
Any idea? I can't seem to make it even with "self"
Gotjosh
Yes, @user would have to be instantiated in the controller. Although you could also just call `current_user` if you are using Authlogic.
zetetic
no results with either way (Yes, I'm using authlogic) with current user i get: undefined local variable or method `current_user' for #<User:0x661a898>, and with @user i just get a null output on the console.... (SELECT "articles".* FROM "articles" INNER JOIN "votes" ON votes.article_id = articles.id WHERE (votes.user_id = NULL) )
Gotjosh
Hmm. `current_user` should return a User instance if logged in, otherwise `nil`. Can you show the code where that error occurs?
zetetic
I'm sorry that it took me so long to respond, been VERY busy lately. Anyways, current_user does return a User instance if logged in (Because i have used it through out the application) however i believe that it only works on controllers/views and not on models. I have edited the question with the both methods I'm using. Again, really appreciate your help.
Gotjosh
Thank you very much for your help, it now works :-) I don't know why but i tried SELF earlier, right now i seem to be struggling with the EDIT partial, would you mind giving me an idea of how the method in the controller and the view would go?
Gotjosh
How about posting this as a new question, seeing as this comment thread is getting lengthy?
zetetic
will do thanks :)
Gotjosh