Re: Restful Authentication with all the bells and whistles (new 9/05/08)

that fixed it.  thanks!

Re: Restful Authentication with all the bells and whistles (new 9/05/08)

@saundesj and activefx

First a thank you to activefx: I'm new to rails (started barely a week ago) and I managed to set up authentication in my application with your tutorial with only minor cursing :)

Secondly: I had the same problem about activation emails being sent twice (while all other emails were sent only once) that saundesj has.

I managed to trace it to models/user_observer.rb. after_save(user) is triggered twice by the activate! method in models/user.rb.

snippet from user_observer.rb:
def after_save(user)
    UserMailer.deliver_activation(user) if user.pending?
    UserMailer.deliver_forgot_password(user) if user.recently_forgot_password?
    UserMailer.deliver_reset_password(user) if user.recently_reset_password?
end

activate! from user.rb:
def activate!
  @activated = true
  self.update_attribute(:activated_at, Time.now.utc)
  self.update_attribute(:activation_code, nil)
end

I solved it by moving the "@activated = true" before the last update_attribute call, but I'm sure someone around here will have a better solution. Maybe one that's less workaround and more solution :)

Re: Restful Authentication with all the bells and whistles (new 9/05/08)

@nicolash and @activefx

AlreadyActivated was not being raised in user.rb

line 39

def self.find_and_activate!(activation_code)
    raise ArgumentError if activation_code.nil?
    user = find_by_activation_code(activation_code)
    raise ActivationCodeNotFound if !user
    raise AlreadyActivated.new(user) if user.active?
    user.send(:activate!)
    user
end

I've implemented these changes with success:

line 48

def active?
    !activated_at.nil?
end

line 125
def self.find_for_forget(email)
    find :first, :conditions => ['email = ?', email]
end

line 157
def activate!
    @activated = true
    self.update_attribute(:activated_at, Time.now.utc)
end

Last edited by saundesj (2008-02-22 23:19:01)

Re: Restful Authentication with all the bells and whistles (new 9/05/08)

@dasbero: Excellent idea. The User Obeserver model was checking if user.pending? was true each time an attribute was updated in the activate! method. Setting @activated = true just before updating the last attribute means that user.pending? only returns true once and therefore only one activation email is sent. However, I have decided to use saundesj's refactorings to fix the problem.

@saundesj: Great catch, thank you for your fixes, I have incorporated them into the tutorial.


In the user model I changed:

  def self.find_for_forget(email)
    find :first, :conditions => ['email = ? and activation_code IS NULL', email]
  end

to:
  def self.find_for_forget(email)
    find :first, :conditions => ['email = ? and activated_at IS NOT NULL', email]
  end

And as per saundesj's suggestions, I also changed
  def active?   
    activation_code.nil?
  end

to:
  def active?   
    !activated_at.nil?
  end

And changed: 
  def activate!
    @activated = true
    self.update_attribute(:activated_at, Time.now.utc)
    self.update_attribute(:activation_code, nil)
  end

to:
  def activate!
    @activated = true
    self.update_attribute(:activated_at, Time.now.utc)
  end

Re: Restful Authentication with all the bells and whistles (new 9/05/08)

@activefx: I already replaced my workaround with saundesj's code. Thanks to everyone for their fast replies!

Re: Restful Authentication with all the bells and whistles (new 9/05/08)

Hi,

I've gone through most of the steps, and am at the point of doing rake db:migrate. However, despite carefully copying the code directly from the tutorial, I am getting

W:\datafiles.k\InstantRails2\rails_apps\mc_3>rake db:migrate
(in W:/datafiles.k/InstantRails2/rails_apps/mc_3)
rake aborted!
./db/migrate//004_create_permissions.rb:31: syntax error, unexpected kEND, expecting $end

I've looked carefully at the file, but see no errors. All blocks have end at the end as they should.

Could my problem be elsewhere?

Design, XHTML, CSS, CMS, Expression Engine, Open-source, ColdFusion.  Learning Rails.

Re: Restful Authentication with all the bells and whistles (new 9/05/08)

4midori wrote:

Hi,

I've gone through most of the steps, and am at the point of doing rake db:migrate. However, despite carefully copying the code directly from the tutorial, I am getting

W:\datafiles.k\InstantRails2\rails_apps\mc_3>rake db:migrate
(in W:/datafiles.k/InstantRails2/rails_apps/mc_3)
rake aborted!
./db/migrate//004_create_permissions.rb:31: syntax error, unexpected kEND, expecting $end

I've looked carefully at the file, but see no errors. All blocks have end at the end as they should.

Could my problem be elsewhere?

Usually when I get the "unexpected kEND" it's usually a missing parenthesis or bracket. Just glancing at the code you posted, this caught my eye (an extra "/" before 004_create...)

./db/migrate//004_create_permissions.rb:31: syntax error, unexpected kEND, expecting $end

WorkingWithRails.com
Person.recommend(jason_deppen)

Re: Restful Authentication with all the bells and whistles (new 9/05/08)

Jason,

I noticed that too but didn't think it was an error.  Any idea what would cause it?

Ben

Design, XHTML, CSS, CMS, Expression Engine, Open-source, ColdFusion.  Learning Rails.

Re: Restful Authentication with all the bells and whistles (new 9/05/08)

4midori wrote:

Jason,
I noticed that too but didn't think it was an error.  Any idea what would cause it?
Ben

After checking the name of the migration file to look for the stray "/", I would just recheck the code in the 004_create_permissions.rb file specifically looking for missing quotes or parenthesis. Sorry I couldn't be more help.

class CreatePermissions < ActiveRecord::Migration
  def self.up
    create_table :permissions do |t|
      t.integer :role_id, :user_id, :null => false
      t.timestamps
    end
    #Make sure the role migration file was generated first   
    Role.create(:rolename => 'administrator')
    #Then, add default admin user
   #Be sure change the password later or in this migration file
   user = User.new
   user.login = "admin"
   user.email = "info@yourapplication.com"
   user.password = "admin"
   user.password_confirmation = "admin"
   user.save(false)
   user.send(:activate!)
   role = Role.find_by_rolename('administrator')
   user = User.find_by_login('admin')
   permission = Permission.new
   permission.role = role
   permission.user = user
   permission.save(false)
  end

  def self.down
    drop_table :permissions
    Role.find_by_rolename('administrator').destroy   
    User.find_by_login('admin').destroy   
  end
end

WorkingWithRails.com
Person.recommend(jason_deppen)

Re: Restful Authentication with all the bells and whistles (new 9/05/08)

Hmmm.  My code is identical to the posted code. I temporarily renamed 004_create_permissions.rb so it wouldn't run. The other three migrations ran fine, so the problem is definitely with this one.

Has anyone else see the double slash problem?  Could there be an error elsewhere?

Design, XHTML, CSS, CMS, Expression Engine, Open-source, ColdFusion.  Learning Rails.

91

Re: Restful Authentication with all the bells and whistles (new 9/05/08)

Weird.

This is working 100% under Instant Rails on XP.

When I deploy to my RHEL 4 machine...same versions of Ruby and Rails I get the following when I enter my email address to reset the password:

undefined method `password_reset_code='

Here's a snippet from my user model:
protected
 
  # before filter
  def encrypt_password
    return if password.blank?
    self.salt = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{login}--") if new_record?
    self.crypted_password = encrypt(password)
  end
   
  def password_required?
    crypted_password.blank? || !password.blank?
  end
   
  def make_activation_code
    self.activation_code = Digest::SHA1.hexdigest( Time.now.to_s.split(//).sort_by {rand}.join )
  end
 
  def make_password_reset_code
    self.password_reset_code = Digest::SHA1.hexdigest( Time.now.to_s.split(//).sort_by {rand}.join )
  end

The make_activation_code method works fine.

WTF?

Re: Restful Authentication with all the bells and whistles (new 9/05/08)

I followed all the cut and paste instructions and everything worked EXCEPT for one missing line:

activefx wrote:

Now, the views. The first thing I would recommend is to create an application wide layout, that includes at least:

followed by view code for /app/views/layout/application.html.erb

What is missing (at least for me on Mac OS X Leopard, rails 2.0.2) is

<%= yield %>

in order for the various forms to be displayed.

Also, I would have liked some way to add roles, but it was easy enough to do from the rails console:

Role.create(:rolename => 'some_role_name')

Thanks for a great tutorial. Next up: integrating this into RailsSpace!

Re: Restful Authentication with all the bells and whistles (new 9/05/08)

I've got a little problem, is it possible that I can't open a role to edit the roles,...

How are the permissions linked to the persons?

Thanks

Re: Restful Authentication with all the bells and whistles (new 9/05/08)

I don't like the way you activate an account by triggering the show action of the accounts controller. According to REST, the show action shouldn't change data on the server side.

I think here is a good place where pure REST with the 7 default actions is not possible. It is much cleaner to create a custom action called activate and PUT the activation code to that action.

Moreover your passwords_controller is really bloated and needs to be refactored.

By the way, I am trying to think of a safety net for avoiding admin account theft:

If a hacker submits my own email that is associated to my admin account, then a reset_password_code is generated in the DB. Now the hacker can brute force the reset_password_code, then once he finds it, change the password to another one. If on top of that he can change the account's email, then he gets full admin access and I cannot stop him from that. The only way would be to go under PhpMyAdmin, and delete the user record.

Therefore, isn't it better to implement the fact that admins will have the forgot_password feature disabled, and can only change their password by editing their user info when logged in?

PS: actually a hacker could steal any account this way, so this issue should probably be handled at the firewall level that would block too many incoming connections from a same IP.

Last edited by Johnson (2008-02-27 17:38:48)

Re: Restful Authentication with all the bells and whistles (new 9/05/08)

I'm getting a really strange error, when I want to do a rake in the production env I keep getting this error:

== 6 CreatePermissions: migrating =============================================
-- create_table(:permissions)
   -> 0.0037s
rake aborted!
execution expired


In developmentmode it takes over 50s to create the db with this data :

   1. class CreatePermissions < ActiveRecord::Migration
   2.   def self.up
   3.     create_table :permissions do |t|
   4.       t.integer :role_id, :user_id, :null => false
   5.       t.timestamps
   6.     end
   7.     #Make sure the role migration file was generated first   
   8.     Role.create(:rolename => 'administrator')
   9.     #Then, add default admin user
  10.     #Be sure change the password later or in this migration file
  11.     user = User.new
  12.     user.login = "admin"
  13.     user.email = "info@yourapplication.com"
  14.     user.password = "admin"
  15.     user.password_confirmation = "admin"
  16.     user.save(false)
  17.     user.send(:activate!)
  18.     role = Role.find_by_rolename('administrator')
  19.     user = User.find_by_login('admin')
  20.     permission = Permission.new
  21.     permission.role = role
  22.     permission.user = user
  23.     permission.save(false)
  24.   end
  25. 
  26.   def self.down
  27.     drop_table :permissions
  28.     Role.find_by_rolename('administrator').destroy   
  29.     User.find_by_login('admin').destroy   
  30.   end
  31. end

Without the data it works without any problem, does anyone know what's wrong?

Re: Restful Authentication with all the bells and whistles (new 9/05/08)

Hi folks,
could someone explain me these "link_to"-lines?
I didnt get an idea why :delete an :put work.

Maybe there is a connections to the routes.rb?

// sry i am pretty new to rails

<!-- user.html.erb -->
<tr class="<%= cycle('odd', 'even') -%>">
  <td><%= user.login -%></td>
  <td><%= user.email -%></td>
  <td><%= user.enabled ? 'yes' : 'no' -%>
    <% unless user == current_user -%>
      <% if user.enabled -%>
        [<%= link_to('disable', user_path(user.id), :method => :delete) %>]
      <% else -%>
        [<%= link_to('enable', enable_user_path(user.id), :method => :put) %>]
      <% end -%>
    <% end -%>
  </td>
  <td>[<%= link_to 'edit roles', user_roles_path(user) %>]</td>
</tr>

Re: Restful Authentication with all the bells and whistles (new 9/05/08)

Yes it is related to routes.rb. The authentication is designed restuflly, so you use DELETE to delete a resource and PUT to update a resource.

Re: Restful Authentication with all the bells and whistles (new 9/05/08)

Johnson wrote:

Yes it is related to routes.rb. The authentication is designed restuflly, so you use DELETE to delete a resource and PUT to update a resource.

but why is it "user_path" on the one hand and "enable_user_path" on the other hand?
i tought it has to be the same.

Re: Restful Authentication with all the bells and whistles (new 9/05/08)

He defined enable in the routes.rb file as :member => { :enable => :put }

This is called a "custom rest action", you have the right to add a few of them, because in general REST doesn't only mean the 7 actions provided by Rails scaffolding, this is just how DHH and his pals have decided to implement REST in Rails. A rule of a thumb is to have a maximum of 10 actions per controller, above that figure, you should consider rethinking your controller organization.

Personally I wouldn't have done it that way, but this is what is generated by the restful_authentication plugin, so it is better to stick to it for when you will update the plugin or regenerate it for other apps to start from scratch.

Re: Restful Authentication with all the bells and whistles (new 9/05/08)

This is driving me up a tree.  My work get me busier toward the end of the month.  I'll figure something out early in the month, then forget how it works later in the month.  Okay, major problem here.

From the user index page, if I click on  "edit roles", I get:

NameError in SessionController#new
uninitialized constant SessionController

Show session dump

---
flash: !map:ActionController::Flash::FlashHash
  :error: You must be logged in to access this feature.
:return_to: /landlords/4/roles
:csrf_id: 1531308b476ec125ec7fee0d2715d9ce




My Sessions Controller....

  # This controller handles the login/logout function of the site.
class SessionsController < ApplicationController
  # Be sure to include AuthenticationSystem in Application Controller instead
# include AuthenticatedSystem

  layout 'application'
  before_filter :login_required, :only => :destroy
  before_filter :not_logged_in_required, :only => [:new, :create]

  # render new.rhtml
  def new
  end

  def create
    password_authentication(params[:login], params[:password])
  end
etc...