The Universal email_token

Activation_code, password_reminder_token and more to come.

Strange code:

before_create :make_activation_token

def make_activation_code
  self.activation_code = Digest::SHA1.hexdigest( ...)
end

def forgot_password
  ...
  password_reset_token=Digest::SHA1.hexdigest(...)
end
#and so on...

Let the mailman handle the postbox keys
Stay with a simple email token. It is updated every time we send any activation/reset/verification mail so no user can perform two action with the same token or say ‘find’ an old token and then request a password reset.

#user.rb
def update_email_token
  update_attribute(:email_token,Digest::SHA1.hexdigest(..)
end

#user_mailer.rb
def setup_email(user)
  user.update_email_token
  ...
end

Generic + Smart – link_to_s link_to_edit link_to_destroy

Building on my work in Separate Rights Management from Controllers i killed all linking-view-logic.

Example

before:
(movie.online? or movie.owner_id==current_user.id) ?
  link_to(movie,movie) : ''
(movie.owner_id==current_user.id) ?
  link_to('edit',movie) : ''

after:
link_to_s(movie)
link_to_edit(movie)

Code

#app/helpers/link_helper.rb
module LinkHelper
  def is_record?(something)
    something.kind_of?(ActiveRecord::Base)
  end

  def can_write?(obj)
    user = current_user || User.new
    user.can_write?(obj)
  end

  def can_read?(obj)
    user = current_user || User.new
    user.can_read?(obj)
  end

  #can we build a link ?
  #true if it is an id / path
  #false if it is an record and i cannot reda/write it
  def is_linkable?(object,rw)
    raise ":r or :w" unless [:r,:w].include? rw
    return false unless object
    return true unless is_record?(object)
    return rw == :r ? can_read?(object) : can_write?(object)
  end

  def link_to_s(object,options={})
    return "" unless is_linkable?(object,:r)
    link_to(object.to_s,object,options)
  end

  def link_to_edit(path_or_object,options={})
    return "" unless is_linkable?(path_or_object,:w)
    if is_record?(path_or_object)
      path_or_object = edit_polymorphic_path(path_or_object)
    end
    link_to("edit",path_or_object,options)
  end

  def link_to_destroy(path_or_object,options={})
    return "" unless is_linkable?(path_or_object,:w)
    link_to( 'X', path_or_object, options.merge(:class=>'destroy'))
  end
end

Please drop a comment if you can think of enhancements, if i can find more uses/methods i will build a new link-helper-plugin 🙂

XHR Redirects

All my ‘Ajax’ requests, use simple xhr when they want to load html, and not .js ,which imo is a misuse since requesting .js should yield a json response.

The first thing i always do is define a xhr layout, which usually is nil. Who ever thought that any xhr request should ever respond with stylesheets and javascript?

layout proc {|controller| controller.request.xhr? ? nil :  'application' }

Working this way i came to some limitations of the xhr approach:

  • cannot easily request from the browser
  • cannot redirect

Redirect an xhr ?

When a user requests something in a Lightbox, it is render using xhr. When the requested resource is not accessible by this user, he should see a login screen. This can be done with a normal redirect, which the JS Framework(at least jQuery does) uses to render the login page inside the lightbox.

Sounds good? But does not work…

Redirects will have the default layout, since they are no longer xhr request, which messes up the lightbox.

Xhr redirects

With this xhr redirect plugin the problem should go away.

_xhr=1

The plugin uses an added parameter _xhr to signal if a request is xhr or not, so now one can also request a page with _xhr=1 and see the actual xhr response.

Generic Fixture Selection

I have done a lot of generic test writing in the last months, and one thing that always resurfaced was:

item = send(@obj.class.to_s.underscore.pluralize,:one)
item = send(@item_name.to_s.pluralize.:one)
...

What does it do ? It load the fixture :one for this objects class, since i always keep a fixture :one and :two around to make generic tests less painful. But all this send madness was unreadable, so i factored out some fixture calling.

#spec/spec_helper.rb OR test/test_helper.rb

#helper for generic fixture calling
#fixture 'user','one' = users('one')
#fixture @user,'one' = users('one')
#fixture User,'one' = users('one')
def fixture(singular,name)
  klas = input_to_class(singular)
  fixture = find_fixture(klas,name)
  raise "fixtures for #{klas} not loaded!" unless fixture
  fixture
end

def find_fixture(klas,name)
  table = klas.to_s.underscore.pluralize
  return send(table,name) if respond_to? table
  false
end

def input_to_class(val)
  return val if val.kind_of? Class
  return val.class if val.kind_of? ActiveRecord::Base
  return val.to_s.classify.constantize
end

Fixing GetText Gem

Update:Fast Gettext gem has resolved all major problems of GetText 😉

Update: gettext 1.92.0 has fixed this issue, update if you can…

Just got a surprising:
NoMethodError (undefined method `file_exists?’ for File:Class):
gettext/rails.rb:281

281c281
<       return render_file_without_locale(localized_path, use_full_path, local_assigns) if file_exists?(localized_path)
---
>       return render_file_without_locale(localized_path, use_full_path, local_assigns) if (respond_to?(:finder) ? finder.file_exists?(localized_path) : file_exists?(localized_path))

put it in a gettext.patch and then:

sudo patch /usr/lib/ruby/gems/1.8/gems/gettext-1.91.0/lib/gettext/rails.rb < gettext.patch

Cause of failure: file_exists?(=cached checking if a file exists) was moved to finder in Rails 2.1
Alternatively one could monkeypatch rails to make it work for Rails 2.1