11
votes

I'm trying to create a simple link that will allow an admin to approve a user on my website

quite similar to what this guy was trying : In Rails 3 how do I use button_to to change the value of a boolean?

Here's how it was supposed to work :

  1. Admin clicks the link to approve a user
  2. The link calls the activate function in UsersController
  3. The active function calls that users model
  4. the user model updates the approved attribute to true and saves it

and here's how I was going to do it

in my users#index view

 <% @users.each do |user| %> 
 <%= link_to 'Approve', :action => "index", :method => 'activate', :id => user.id, :class => 'btn btn-mini btn-danger' %> 
<% end %> 

in my userController

def activate
  @user = User.find(params[:user])
  @user.activate_user
end

in my user model

def activate_user 
  self.approved = 'true'
  self.save
end

and my routes

devise_for :users, :controllers => { :registrations => "registrations" }

resources :users do
  member do
    get 'activate'
    put 'activate'
  end
end

match "users/:id/activate" => "users#activate"

Now when I click the link (to approve users), I'm sent back to the user index page (like I'm supposed to) but the user field "approved" is still set to false :I

The URL I get after clicking the link :

  http://localhost:3000/users?class=btn+btn-mini+btn-danger&id=2&method=activate

Any ideas?

UPDATE

As suggested iv added the URL to the link_to helper

<% @users.each do |user| %> 
  <%= link_to "Approve", :controller => "users", :id => user.id, :action => "activate", :method => :put, :approved => true %> 
<% end %>

When I click the helper link I get

wrong number of arguments (1 for 2) 

in app/controllers/users_controller.rb:7:in `activate'

def activate
  @user = User.find(params[:id])
  @user.update_attribute(params[:user])
  redirect_to "/users?approved=false"
end

line 7 where the error is @user.update_attribute(params[:user])

What else should I put there?

oh and here is my route for this method

match "/users/:id/activate" => "users#activate"

UPDATE V2 So I have changed that update line to :

@user.update_attributes(@user.approved, "true")

and it seems to do everything i want it to do except changing the value to true !

I've also tried to use 1 for true (and the update_attribute function) and non-strings.. running out of ideas here lol

The solution

Well this is awkward but so it happens that in my user model i had attr_accessor :approved this resulted in that the model never went to the database to update the :approved column BUT instead it updated the local variable :approved so next time when I looked at the column then of course the :approved value had not changed

tldr? if you have attr_accessor in your model with the same name as the column your trying to update => remove it

3
The second parameter of link_to should be a url, then you put in your options. Try link_to "Approve", users_path, #...Ian Armit
Tru running rake routes and see which route actually points to users#activate. Use the helper variable.ichigolas

3 Answers

8
votes

You can update the code below

You View

<% @users.each do |user| %> 
<%= link_to 'Approve', active_user_path(user) %> 
<% end %>

You Controller

def activate
  @user = User.find(params[:id])
  if @user.update_attribute(:approved, true)
    redirect_to "something"
  else
   render "something"
  end 
end

Your routes

match "users/:id/activate" => "users#activate", :as => "active_user"

Hope can help you.

2
votes

Looks like you aren't calling link_to properly. Notice that you have the action as a http parameter and not part of the URL.

The URL should be

http://localhost:3000/users/123/activate

Look at the examples on this page:

http://apidock.com/rails/ActionView/Helpers/UrlHelper/link_to

I think you need to use the :controller => 'users', :action => 'activate'.

Remember you can use a string here for the path as well: "/users/${@user.id}/activate"

0
votes

The attr_accessor method will create an instance variable as well as the getter and setter for said variable.

When you try to update the database column with that name, it uses the instance variable instead. This is useful if you want to have a "virtual column", that will act as an actual column but is stored in memory.

For database columns you have attr_accessible which allows for mass assignment of that column (this will be deprecated in rails 4), or you can use no method to define the accessibility of columns and let ActiveRecord deal with it.