Search code examples
rubysinatrasequel

How to implement Active Record like 'find' method in Sinatra and Sequel?


I am building a simple Sinatra app for training purposes.

I am using the Sequel gem and don't want to use Active Record.

My files are:

/models/idea.rb:

class Idea
  attr_reader :id, :title, :description

  def initialize(input)
    @id = input[:id]
    @title = input[:title]
    @description = input[:description]
  end

  def save
    Idea.data.insert(title: title, description: description)
  end

  def self.create_table
    database.create_table? :ideas do
      primary_key :id
      String :title, size: 25
      Text :description
    end
  end

  def self.data
    verify_table_exists
    database[:ideas]
  end

  def self.database
    @database ||= Sequel.sqlite('./db/idea_box.sqlite3')
  end

  def self.all
    data.order(Sequel.desc(:id)).collect do |row|
      Idea.new(row)
    end
  end

  def self.verify_table_exists
    @table_exists ||= (create_table || true)
  end

  def self.find(params)
    data.where(id: params)
  end
# I also tried this:
#
#  def self.find(params)
#    data.where(id: params).collect do |row|
#      Idea.new(row)
#    end
#  end

  end
end

/views/edit.haml:

%h1 Edit idea
%form{action:"/#{@idea.id}", method: "post"}
  %input{type: "hidden", name: "_method", value: "put"}
  %input{type: "text", name: "idea_name", value: "#{@idea.title}"}
  %br
  %textarea{name: "idea_description", value: "#{@idea.description}"}
  %br
  %input{type: "submit", value: "Submit"}

application.rb:

require './models/idea'


Bundler.require

helpers do
  def title
    if @title
      "#{@tile} -- IdeaBox"
    else
        "IdeaBox"
    end
  end

  def delete_idea_button(idea_id)
    haml :_delete_idea_button, locals: {idea_id: idea_id}
  end
end



get '/' do
  @ideas = Idea.all
  haml :index
end

not_found do
  haml :error
end

post '/create' do


  idea = Idea.new(title: params['idea_name'], description: params['idea_description'])
  idea.save

  redirect to('/')
end

get '/edit/:id' do
  @idea = Idea.find(params[:id])
  @title = "Edit form"
  haml :edit
end

put ':id' do
  @idea = Idea.find(params[:id])
  @title = "Edit form"
  haml :edit
end

Solution

  • Just the find method will work when you use something like this:

    def self.find(params)
      record = data[id: params]
      if record.nil?
        nil
        # or raise an exception...
      else
        self.new(record)
      end
    end
    

    But you also have to reimplement some features that Active Record already has, for example some kind of persisted? method to check if the record is already present in the database and update the record instead of creating a new one.

    With your current implementation of save it will create a new record each time you call it. It may also be better if you don't set the id yourself but let the auto_increment of your database handle that.