1

In another question that i asked recently i got a really good answer and the code worked... But i do not know exactly why it works... Now i have a similar problem, but don't know how to solve it...?

What i have:

Models

users
questions (with answer_id)
answers
votes (with answer_id and user_id)

model for users:

has_many :questions
has_many :votes
def can_vote_on? (question)
    !question.answers.joins(:votes).where('votes.user_id = ?', id).exists?
  end

def voted_answer? (question)
   (what to do here...?) 
  end

model for questions:

belongs_to :user
has_many :answers, :dependent => :destroy
accepts_nested_attributes_for :answers, :reject_if => lambda { |a| a[:text].blank? }, :allow_destroy => true

model for answers:

belongs_to :question
has_many :users, :through => :votes, :dependent => :destroy
has_many :votes

model for votes:

belongs_to :answer
belongs_to :user

In my question view i want to make a text bold when the current_used has voted on that specific answer. So how do i finish this:

<% for answer in @question.answers %>
 <% if current_user.voted_answer? (@question) %>
  <td>
   <strong><%= answer.text %></strong> 
  </td> 
 <% else %>
  <td>
   <%= answer.text %>
  </td> 
 <% end %>
<% end %>

Thijs

Thijs
  • 387
  • 5
  • 20

2 Answers2

3

you may do this

<% for answer in @question.answers %>
  <% if answer.votes.index{|vote| vote.user_id == current_user.id} %>
    <td>
    <strong><%= answer.text %></strong> 
    </td> 
  <% else %>
    <td>
    <%= answer.text %>
    </td> 
  <% end %>
<% end %>

UPDATE

more logical variant create voted_by_user? function in class Answer

class Answer
  def voted_by_user?(user)
    voits.where('votes.user_id = ?', user.id).exists?
  end
end

<% @question.answers.each do |answer| %>
  <td>
    <% if answer.voted_by_user?(current_user) %>
      <strong><%= answer.text %></strong> 
    <% else %>
      <%= answer.text %>
    <% end %>
  </td> 
<% end %>
Sector
  • 1,210
  • 12
  • 14
1

It sounds like you just want the opposite result of can_vote_on?, i.e. if a user cannot vote on an answer (can_vote_on? returns false), then it means that they already voted (voted_answer? should return true in this case) and vice versa.

One way to solve this is to have voted_answer? return the negation of can_vote_on:

def voted_answer? (question)
    !can_vote_on? question
end

Or of course you could use the query you used in can_vote_on? without the negation:

def voted_answer? (question)
    question.answers.joins(:votes).where('votes.user_id = ?', id).exists?
end

But I would prefer the first solution due to the DRY principle.

UPDATE

I was wrong about the negation. In this case you're dealing with a specific answer, not all of them.

In your model you'll want the following:

def voted_answer? (answer)
    answer.votes.where('votes.user_id = ?', id).exists?
end
McStretch
  • 20,495
  • 2
  • 35
  • 40
  • Thanks but it doesn't work... Now i get al the results bold, because the query checks if any of the votes.user_id exists... and i only wnat the current_user.id voted answer... – Thijs Apr 05 '11 at 11:43
  • @Thijs - gotcha, I wasn't sure where id was coming from in that call. Have you tried substituting id with current_user.id in the second example I showed? I figured `can_vote_on?` was using the current user's id as well. – McStretch Apr 05 '11 at 12:03
  • What i tried but i get undefined method errors all the time: def voted_on? (question) question.answers.joins(:votes).where('votes.user_id = ?', current_user.id) end – Thijs Apr 05 '11 at 12:08
  • @Thijs - Do you have a `current_user` method defined anywhere? It looks like you don't. – McStretch Apr 05 '11 at 12:10
  • I use devise, but current_user works in views... but not in my model... I allready got the problem solved on a more simple way... read the answer below. – Thijs Apr 05 '11 at 12:22
  • @Thijs - More simple? Now you're throwing in a bunch of logic in the view, which is generally a less-preferred practice. If anything you could pass in the current_user.id from the view into the method. – McStretch Apr 05 '11 at 12:33
  • Euhmm... i agree with you that logics don't belong in the view... not all of it... But can you then explain how you'd solve it? With a model? I'm also trying to get a count of all the votes per answer... Oh boy i thought i'd understand rails after reading railstutorial book and agile web dev. for rails.. – Thijs Apr 05 '11 at 12:37
  • I get this error: NoMethodError in Questions#show Showing /home/thijs/rails_projects/rebasev2/app/views/questions/show.html.erb where line #35 raised: undefined method `answer' for # I also put the following in my view: <% if current_user.voted_answer? (@question.answer) %> – Thijs Apr 05 '11 at 12:51
  • 1
    Yeah `answer` is not defined on question, `answers` is. You want to pass in `answer` from the for loop, leave off `@question`: `<% if current_user.voted_answer? (answer) %>` – McStretch Apr 05 '11 at 12:54
  • Yes it worked!! Thank you so much for the help!! Can you also explain how the method works? In the model...? I really want to learn it, copying code is handy, but i need to script lots more...!! Thanks!! – Thijs Apr 05 '11 at 13:05
  • 1
    @Thijs - No problem I'm glad it worked. So in your view you're looping through all of the question's answers. You're then passing each answer into `voted_answer?`. This method takes the answer argument and gets its votes (through a db query), and then looks for any votes on that answer with the current_user's id. You can simply call "id" because it is a method available via any object, and since you're calling `voted_answer?` on the current_user, you're checking for the current_user's id. If a vote for that answer exists given the current_user, then you know that answer was the one chosen. – McStretch Apr 05 '11 at 13:11