views:

127

answers:

2

Simple RoR question...I am learning ROR and am making a simple voting app. The candidates are listed in a table and have upvote/downvote links next to their name. I am trying to make it so all the user does is click the link, the vote count is updated, and they are redirected to the initial page. I am not using scaffolding. For some reason this action is not doing anything close to what I want:

def upvote
  @name = Name.find(params[:id])
  @name[:votes] += 1
  respond_to do |format|
    if @name.update_attributes(params[:name])
      flash[:notice] = 'Candidate was upvoted'
      format.html = { redirect_to :action => "index" }
      format.xml = { head :ok }
    else
      format.html = { render :action => "index" }
      format.xml = { render :xml => @name.errors, :status => :unprocessable_entity }
    end
  end
end

I do have the link in the view calling the correct action, it's trying to call :show, though.

please don't judge me too harshly lol...

+3  A: 

The update_attributes method is generally used to set the fields of an ActiveRecord object from a form POST. The fields would be found as the hash params[:name], e.g. params[:name][:votes].

If you are clicking on a link to call the upvote method, then you are just doing a GET request. All you need to do is call @name.save to save the record.

def upvote
  @name = Name.find(params[:id])
  @name[:votes] += 1
  respond_to do |format|
    if @name.save
      flash[:notice] = 'Candidate was upvoted'
      format.html = { redirect_to :action => "index" }
      format.xml = { head :ok }
    else
      format.html = { render :action => "index" }
      format.xml = { render :xml => @name.errors, :status => :unprocessable_entity }
    end
  end
end

EDIT: From the comments, we also determined that the routes were set up improperly and that the link_to code in the view needed to include @name.id.

Schrockwell
it still does nothing, just goes to the 'show' action for some reason...anyway thanks for your help, my problem must not be in the controller...
W_P
Yeah, I thought it was weird that the show action is being called. It would help if you could also show the code in the view you are using to create the link. Also, if you have any routes configured, that would be helpful to know, as well.
Schrockwell
<% @names.each do |name| %> <tr> <td><%= link_to "UP", :action => :upvote %>/<%= link_to "DOWN", :action => :downvote %></td> <td><%=h name.candidate_name %></td> </tr><% end %>
W_P
this is the relevant part of the view, here are the routes:ActionController::Routing::Routes.draw do |map| map.resources :names, :collection => { :upvote => :post } map.connect ':controller/:action/:id' map.connect ':controller/:action/:id.:format' map.root :controller => "names"
W_P
In routes.rb, you should map the upvote action to GET, not POST: map.resources :names, :collection => { :upvote => :get } . As mentioned in Steve's post, run 'rake routes' to see how your routes lay out to debug this sort of thing.
Schrockwell
Thanks! I just had to change that and add :id => name.id to the 'link_to' field and it worked great. Thanks for all your help
W_P
+3  A: 

Typically the RESTful URL that maps to show is:

my_resource/id

So, e.g.,

candidates/1

Just at a guess, I'll bet if you look in config/routes.rb, you'll find something like:

map.resources :candidates

Where my_resource is the name of your controller. If you are going to use this kind of routing, then how does the resource provide upvoting? The custom method seems wise in this case, so:

map.resources :candidates, :collection => { :upvote => :post }

If you run

rake routes | grep candidate

before and after, you can see what's been added. Hope this helps.

Steve
Thanks for your help!
W_P