views:

931

answers:

4

[see later answer for more]

I think this is just a simple rails question, and mostly on how i've named my models and reference them in my view. So a little background, I'm using the vote_fu plugin, which I think is great, however I'm having a hard time getting the voting to work from a link as follows:

<%= link_to "vote for", current_user.vote_for(answer) %>

Where current_user is a helper and returns the current user that is logged in making this request, the issue is likely in the way I state answer which belongs to my question model, any help is really appreciated, even if you just help me down the right path!

oh! also it works in console... so if I do:

user = User.find(1)
user.vote_for(Question.last)

It works as expected.

A: 

Blah! I solved the first part of my question... well... maybe, it seems my solution isn't very restful, here is what I did:

<%= link_to "Vote Up", :url => current_user.vote_for(answer), :method => :post %>

So the weird thing here is that it works, but every time I reload the page it adds a vote up to all the users with an answer (or comments as most blogs would be concerned), it also makes the url localhost/questions/65?method=post&url=true, I'm not sure what my next plan of action here is.


After a little more investigation, the example the vote_fu example app has this in the controller's create action, but I don't even have a controller for my vote model and the votes are still made, any idea?

def create
@quote = Quote.find(params[:quote_id])

respond_to do |format|
  if current_user.vote(@quote, params[:vote])
    format.rjs  { render :action => "create", :vote => @vote }
    format.html { redirect_to([@quote.user, @quote]) }
    format.xml  { render :xml => @quote, :status => :created, :location => @quote }
  else
    format.rjs  { render :action => "error" }
    format.html { render :action => "new" }
    format.xml  { render :xml => @vote.errors, :status => :unprocessable_entity }
  end
end
Joseph Silvashy
Like I said above, that `vote_for` call belongs in your controller. `vote_for` casts a vote.
Andy Gaskell
It's already in the plugin's functionality, do I still need to put it in the controller?
Joseph Silvashy
You mentioned that it works in the console. You are sending your user object a message "vote for the last question". Now imagine what's going on as Ruby builds your link: you are sending a message to your user object "vote for this answer" as you're building the link. Let's look in the example code - /examples/votes/_voteable_vote.html.erb - if you want to use this plugin the easiest way is going to be modeling your code after that view.
Andy Gaskell
wow, awesome feedback, that helps, I suppose I should make the partials same as the example to get it right, that would prevent the voting on page reload, as the request won’t be made... I think. I'll try tomorrow. thanks for the feedback.
Joseph Silvashy
+1  A: 

The example, which is pretty old, has this in the view:

<%= link_to "Vote Up", :url => current_user.vote_for(answer), :method => :post %>

But this makes the URL have the vote method in the query string... he is using rjs, and I'd prefer to use jquery, not sure how to go about my next step in getting this to work and not vote for all the answers on the page?

Joseph Silvashy
+1  A: 

A clarification of "vote_for belongs in your controller":

You have:

<%= link_to "Vote Up", current_user.vote_for(answer) %>

What you really want is:

<%= link_to "Vote Up", :controller => 'my_controller', :action => 'vote', :id => answer %>

The current_user.vote_for method is a method on the server. If you call that method in your view (.rhtml file), the vote will happen when the page is rendered, not when the user clicks the link. Instead, create a 'vote' method on an appropriate controller (I called it my_controller here, make it whatever you want). The vote method then looks like the vote_fu example. The link_to creates a hyperlink to the voting action.

If you're trying to do this via ajax, replace link_to with link_to_remote.

<%= link_to_remote "Vote Up", :url => { :controller => 'my_controller', :action => 'vote', :id => answer } %>

If your views/my_controller/vote template file is '.rjs', the javascript in that file will be executed when the result of the method returns to the page. If it is '.rhtml', you should look into the helpers for link_to_remote for easily updating a div on the page with the contains of the result of the method (http://api.rubyonrails.org/classes/ActionView/Helpers/PrototypeHelper.html#M001645 - you want the :update option )

audiodude
+1  A: 

current_user.vote_for(answer) will call that method right away. Just because it's in :url doesn't mean it gets any special treatment. It'll be executed just like any other ruby method.

You probably want to do something like this.

// view
<%= link_to "Vote up", :url => vote_up_answer_path(answer), :method => "post" %>

// controller
class AnswersController < ApplicationController
  def vote_up
    answer = Answer.find(params[:id])
    current_user.vote_up(answer)
    redirect_to :back
  end
end

// routes
map.resources :answers, :member => {:vote_up => :post, :vote_down => :post}
August Lilleaas