Search code examples
ruby-on-rails-3methodscontrollerrouteslink-to

Create action to change boolean value in Rails 3


I have a simple model for suggestions in my Rails 3 application. I am trying to add a simple link_to link on the index view that when clicked marks the suggestion as approved.

So far I have the following code:

routes.rb

resources :suggestions do
 get :approve
end

suggestions_controller.rb

def approve
 @suggestion = Suggestion.find(params[:id])
 @suggestion.update_attribute(:approved, 'true')
 @suggestion.update_attribute(:approved_on, Time.now)
 redirect_to suggestion_path
end

suggestion.rb

attr_accessible :author, :details, :localip, :title, :approved, :approved_on

schema.rb

create_table "suggestions", :force => true do |t|
 t.string   "title"
 t.string   "author"
 t.text     "details"
 t.string   "localip"
 t.datetime "created_at",                     :null => false
 t.datetime "updated_at",                     :null => false
 t.boolean  "approved",    :default => false
 t.datetime "approved_on"
end

index.html.erb (suggestions)

<% if @suggestion.approved? %>
    <%= @suggestion.approved_on %>
<% else %>
    Not yet approved. (<%= link_to "Approve", approve_suggestion_url(@approve), :method => :put %>)
<% end %>

When using the above code, I get the following exception error:

undefined method `approved?' for nil:NilClass

Am I missing a step out somewhere something?


Solution

  • Most probably, the code you have posted is inside an each loop like

    <% @suggestions.each do |suggestion| %>
      ...
      <% if @suggestion.approved? %>
        <%= @suggestion.approved_on %>
      <% else %>
        Not yet approved. (<%= link_to "Approve", approve_suggestion_url(@approve), :method => :put %>)
      <% end %>
    <% end %>
    

    You need to use suggestion variable instead of @suggestion instance variable. Also, to construct suggestion approve url, you'll need to use suggestion instead of @approve. Code should be like

      <% if suggestion.approved? %>
        <%= suggestion.approved_on %>
      <% else %>
        Not yet approved. (<%= link_to "Approve", approve_suggestion_url(suggestion), :method => :put %>)
      <% end %>
    

    Also, you should modify your routes.rb to reflect that approve action is a member action.

    resources :suggestions do
      put :approve, on: :member
    end
    

    To understand the difference between member and collection routes, read difference between collection route and member route in ruby on rails?.