Search code examples
ruby-on-railsrubysinatradatamappervirtual-attribute

Virtual Attributes with Sinatra and Datamapper


I am converting a Rails app to Sinatra. The application relied on ActiveRecord which supports virtual attributes, however, I am struggling to find similar support in DataMapper.

In Rails, I used an algorithm to generate scores and sort records based on a score. Virtual attributes were at the heart of this process. Does anyone know how to replicate this functionality in Sinatra/DM?

I am open to any workarounds. Refactoring can come later, as I am only interested in functionality at the moment.

In theory the solution would work something like this:

require 'sinatra'
require 'data_mapper'
require 'haml'

DataMapper::setup(:default,"sqlite3://#{Dir.pwd}/example.db")

class Link
  include DataMapper::Resource
  property :id, Serial
  property :title, Text
  property :url, String
  property :points, Integer, :default => 0
  property :created_at, Time

  attr_accessor :score

  def calculate_score
    time_elapsed = (Time.now - self.created_at) / 3600
    self.score = (self.points-1) / (time_elapsed+2)**1.8 
  end
end

DataMapper.finalize.auto_upgrade!

get '/hot' do
    @links = Link.all :order => :score.desc 
    haml :index 
end

Solution

  • I have not used datamapper, but I think this code will give you the needed functionality: changes include, new class method on Link all_sorted_desc and call that in the 'get' request

    require 'sinatra'
    require 'data_mapper'
    require 'haml'
    
    DataMapper::setup(:default,"sqlite3://#{Dir.pwd}/example.db")
    
    class Link
      include DataMapper::Resource
      property :id, Serial
      property :title, Text
      property :url, String
      property :points, Integer, :default => 0
      property :created_at, Time
    
      attr_accessor :score
    
      def calculate_score
        time_elapsed = (Time.now - self.created_at) / 3600
        self.score = (self.points-1) / (time_elapsed+2)**1.8 
      end
    
      def self.all_sorted_desc
        self.all.each { |item| item.calculate_score }.sort { |a,b| a.score <=> b.score }.reverse 
      end
    end
    
    DataMapper.finalize.auto_upgrade!
    
    get '/hot' do
        @links = Link.all_sorted_desc 
        haml :index 
    end