Sinatra with Datamapper throws undefined method `add_domain_type' for Psych:Module (NoMethodError) - ruby

I'm working on a pretty simple sinatra + datamapper app, and it was launching and working just fine yesterday. I attempted to introduce some seed data into the db, and started getting this strange error on launch. I reverted back to pre-seed code, and the error persists. I've noticed that commenting out the include DataMapper::Resource in my model makes the app run again. here's the error:
/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/dm-serializer-1.2.2/lib/dm-serializer/to_yaml.rb:15:in included': undefined methodadd_domain_type' for Psych:Module (NoMethodError) ... Any ideas?
#app.rb:
require 'sinatra'
require 'pry'
require_relative 'models'
helpers do
def content_path(file)
File.join("images", file)
end
end
get '/' do
#photos = Photo.all
erb :index
end
models.rb
require 'data_mapper'
DataMapper::setup(:default, "sqlite3://#{Dir.pwd}/db/photos.db")
class Photo
include DataMapper::Resource
property :id, Serial
property :created_at, DateTime
property :title, String
property :body, Text
property :filename, String
property :description, Text
property :width, String
property :height, String
end
DataMapper.finalize
Photo.auto_upgrade!
EDIT: It appears that upgrading ruby to 2.2.0 and reinstalling the gems solved the problem

Related

Use Geocoder with Sinatra and DataMapper

I'm attempting to use the Geocoder gem with a DataMapper model in a Sinatra application.
environment.rb:
require 'rubygems'
require 'bundler/setup'
require 'dm-core'
require 'dm-timestamps'
require 'dm-validations'
require 'dm-aggregates'
require 'dm-migrations'
require 'dm-types'
require 'geocoder'
require 'sinatra' unless defined?(Sinatra)
# load models
$LOAD_PATH.unshift("#{File.dirname(__FILE__)}/lib")
Dir.glob("#{File.dirname(__FILE__)}/lib/*.rb") { |lib| require File.basename(lib, '.*') }
DataMapper.setup(:default, (ENV["DATABASE_URL"] || "sqlite3:///#{File.expand_path(File.dirname(__FILE__))}/#{Sinatra::Base.environment}.db"))
DataMapper.finalize
DataMapper.auto_upgrade!
lib/location.rb:
class Location
include DataMapper::Resource
include Geocoder::Model::Base
property :id, Serial
property :address, String, :required => true
# geocoder gem
geocoded_by :address, :latitude => :lat, :longitude => :lng
# geocoder
after_validation :geocode, :if => :address_changed?
end
When I attempt to start an IRB session, an exception is generated:
irb> require './environment'
NameError: uninitialized constant Geocoder::Model
...
What am I not understanding?
First up, it looks like the Geocode gem won't have direct support for Datamapper, as per this issue.
Second, when you include a module inside a class, the methods are available to the instance of the class, and not at the class level. For example:
module Name
def name
puts "Module"
end
end
class SomeClass
include Name
end
SomeClass.new.name # => "Module"
This works because when you include a module, that module gets added to the ancestor chain of that class. Any methods that get sent to the instance which are not available on the instance are forwarded to the ancestors. However, there's another method called extend which adds the methods at a class-level rather than at instance level:
# module definition same as before
class SomeClass
extend Name
name # works!
end
Inorder to get class-level inclusion, there is another way (which is what the Geocoder gem uses for supported models:
# module code same as before
module Name
def name
puts "Module"
end
def self.included(klass)
klass.extend(self)
end
end
The included hook is provided for models which can be overridden to do something when the include Name step executes. Since there's no Datamapper specific module that is not executing this step, you see that error.

How do I export data from CSV to DataMapper in Sinatra?

I'm building a simple web application using Sinatra.
I have an external text file and would like to parse it using CSV. Then I would like to export the data and create a database using DataMapper. I'm stuck on how to accomplish this.
This is what I have so far:
require 'sinatra'
require 'csv'
require 'data_mapper'
CSV.foreach("words.txt") do |row|
puts row[0]
end
DataMapper::setup(:default, "sqlite3://#{Dir.pwd}/scrabble.db")
class Letters
include DataMapper::Resource
property :id, Serial
property :content, Text, :required => true
property :created_at, DateTime
property :updated_at, DateTime
end
Can anyone point me to the right direction?
if you itterate through a list of words, you need to do like that:
require 'sinatra'
require 'csv'
require 'data_mapper'
DataMapper::setup(:default, "sqlite3://#{Dir.pwd}/scrabble.db")
class Letters
include DataMapper::Resource
property :id, Serial
property :content, Text, :required => true
property :created_at, DateTime
property :updated_at, DateTime
end
CSV.foreach("words.txt") do |row|
Letters.create(content: row[0])
end

Firefox can't establish a connection to the server at localhost:4567

I created a simple ruby/sinatra application following a tutorial from tutsplus. I have done everything as instructed but when I go to "localhost:4567", I don't see what I expect, instead I am greeted with the error message:
"Firefox can't establish a connection to the server at localhost:4567"
Is there something I need to do to this port?
EDIT:
With some help i figured I should have used port 9393. But now i get this error: error
and this is the code in my recall.rb app:
require 'rubygems'
require 'sinatra'
require 'datamapper'
DataMapper::setup(:default, "sqlite3://#{Dir.pwd}/recall.db")
class Note
include DataMapper::Resource
property :id, Serial
property :content, Text, :required => true
property :complete, Boolean, :required => true, :default => false
property :created_at, DateTime
property :updated_at, DateTime
end
DataMapper.finalize.auto_upgrade!
get '/' do
#notes = Note.all :order => :id.desc
#title = 'All Notes'
erb :home
end
EDIT again:
SOLVED using
require data_mapper
According to the png file you posted in your other comment, your Webrick server is saying it started up on port 9393. So you should try accessing the app via http://localhost:9393.
Remember to start your server with shotgun recall.rb.

In Ruby/Sinatra, Datamapper's .all works but .get doesn't?

I am trying to take data from a path in Sinatra, and use it to look up a particular record using Datamapper. The Datamapper docs seem to indicate that.
get "/test/:test_path" do
test_get = Intake.get( params[:test_path] )
# Do stuff
erb :blah_blah_blah
end
should find any records associated with the symbol :test_path
This does not work. test_get gets nil.
Meanwhile, what does work is
get "/test/:test_path" do
test_all = Intake.all(:test_path => params[:test_path] )
# Do stuff
erb :blah_blah
end
My two questions are:
What am I doing wrong with the .get() call in Datamapper?
Is the .all(:name => value) method slower than .get(), or does it not matter which I use?
Here's a Sinatra script pared down to demonstrate the behavior.
#!/usr/bin/env ruby
require 'rubygems'
require 'sinatra'
require 'dm-core'
require 'dm-timestamps'
DataMapper.setup(:default, {:adapter => 'yaml', :path => 'db'})
class Intake
include DataMapper::Resource
property :id, Serial
property :created_at, DateTime
property :test_path, String
end
get "/test/:test_path" do
test_all = Intake.all(:test_path => params[:test_path] )
puts 'test_all:' test_all.inspect
test_get = Intake.get( params[:test_path] )
puts 'test_get:' test_get.inspect
"Hello World!"
end
#get only does a lookup based on primary key, with is the id. So
Intake.get(params[:test_path])
looks for something with id params[:test_path], which will fail. Use
Intake.first(test_path: params[:test_path])

Chained aggregate call across association in DataMapper (ruby)

I am working on a simple budget app using Sinatra and DataMapper in Ruby.
I want to get the sum of all transactions across all income accounts within the last 30 days.
Something like Account.income_accounts.account_entries.sum(:amount, :transaction_date.gte => Date.today - 30) should work. Instead, the limiting condition on transaction_date is getting ignored, returning the sum of the amount for all entries for all income accounts.
Given the following:
class Account
include DataMapper::Resource
has n, :account_entries
property :id, Serial
property :name, String
property :acct_type, String
def self.income_accounts
all(:acct_type => 'Income')
end
end
class AccountEntry
include DataMapper::Resource
belongs_to :account
property :id, Serial
property :account_id, Integer
property :description, String
property :amount, BigDecimal
property :transaction_date, DateTime
end
I am properly requiring dm-aggregates. I am new to DataMapper. If it matters, I am using a sqlite3 database. I really don't want to resort to using ruby to sum the results. It also feels wrong to resort to executing raw SQL for this type of simple aggregate query.
Can anyone shed some light on this? I would love to be pointed in the right direction regarding chained finders in DataMapper, particularly with aggregates. My spelunking into the API and the DataMapper site hasn't yielded a solution as of yet.
I just wrote a small stand-alone script to test your example, and it appears to return the correct results. Please note I am using edge extlib, dm-core, and dm-more all installed from git:
#!/usr/bin/env ruby -Ku
# encoding: utf-8
require 'rubygems'
require 'dm-core'
require 'dm-aggregates'
DataMapper::Logger.new($stdout, :debug)
DataMapper.setup(:default, 'sqlite3::memory:')
class Account
include DataMapper::Resource
property :id, Serial
property :name, String
property :acct_type, String
has n, :account_entries
def self.income_accounts
all(:acct_type => 'Income')
end
end
class AccountEntry
include DataMapper::Resource
property :id, Serial
property :description, String
property :amount, BigDecimal
property :transaction_date, Date
belongs_to :account
end
DataMapper.auto_migrate!
account = Account.create(
:name => 'Test Account',
:acct_type => 'Income'
)
5.times do |n|
account.account_entries.create(
:description => "Account Entry #{n}",
:amount => 1.00,
:transaction_date => Date.today
)
end
puts Account.income_accounts.account_entries(:transaction_date.gte => Date.today - 30).sum(:amount).to_s('F') # => 5.0
Can you run the above program and let me know what it returns for you? If you get something other than 5.0, try updating to the latest packages and retry.
DateTime uses second as it's base unit Date.today - 30 is 30 seconds ago. Try Date.today - 30.days
Did you try DateTime.now-30 or maybe even Time.now-30*3600*24 instead of Date.today-30 ?
User error. I mucked around with to_s on DateTime to use the time formats in strftime. When removed, the chained aggregate worked as anticipated.

Resources