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

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

Related

Get associated records with Datamapper using Sinatra

I am currently working on a small backend, managing events with associated locations. Unfortunately, it's my first time i work with Ruby/Sinatra/Datamapper. After 3 hours trying to find a solution, i have to write this post.
I have defined two Resources:
class Event
include DataMapper::Resource
property :id, Integer, :key => true
property :name, Text
property :description, Text
has 1, :location
end
class Location
include DataMapper::Resource
property :id, Integer, :key => true
property :name, Text
property :latitude, Float
property :longitude, Float
belongs_to :event
end
This is my route to list all events:
get "/events/" do
#events = Event.all
content_type :json
#events.to_json
end
Is there a easy way the get the location as a parameter in the output of the associated event object?
Thank you very much for your support!
require 'rubygems'
require 'sinatra'
require 'dm-core'
require 'dm-migrations'
require 'dm-sweatshop' # for fixtures
require 'json'
DataMapper::Logger.new($stdout, :debug)
DataMapper.setup(:default, 'sqlite::memory:')
class Event
include DataMapper::Resource
property :id, Serial # will automatically become an auto-increment key
property :name, String # defaults to being max 50 char length
property :description, Text, :lazy => false # defaults to true
belongs_to :location # instead of one-to-one relation, which are rarely useful
end
class Location
include DataMapper::Resource
property :id, Serial
property :name, String
property :latitude, Float # perhaps decimal with less precision would suffice
property :longitude, Float
has n, :events
end
DataMapper.finalize.auto_migrate!
# Define some fixtures to have some data to play around with
def rand_float(min, max); rand * (max - min) + min end
Location.fix {{
:name => /\w+/.gen,
:latitude => rand_float(40.0, 43.0),
:longitude => rand_float(4.8, 5.4)
}}
Event.fix {{
:name => /\w+/.gen,
:description => /[:sentence:]/.gen[5..100],
:location => Location.pick
}}
100.of { Location.gen; Event.gen }
# Search events by properties of its association
get "/events/:location_name" do |location_name|
#events = Event.all(Event.location.name => location_name)
#events.to_json
end
# Return both objects in the same array
get "/events/" do
#events = Event.map {|e| [e, e.location] }
#events.to_json
end
Finally found the answer by myself when i took a deeper look at the to_json options
#events.to_json(:relationships=>{:location=>{}})

How can I resolve the IllegalContextError when attempting to save a datamapper model?

When I try to this code, I get an IllegalContextError at the "self.save..." line. Can you tell me what I'm doing wrong?
I would just call the create method on Player without messing around with initialize, but I want a related week object to be created as part of the initialization.
require 'data_mapper'
DataMapper::setup(:default, "sqlite3://#{Dir.pwd}/prod.db")
class Player
include DataMapper::Resource
property :name, String, :key => true
property :sport, String
has n, :weeks
def initialize(name, sport, week)
self.save(:name => name, :sport => sport)
self.weeks.create(:id => "#{name}#{week}", :score => 0)
end
end
class Week
include DataMapper::Resource
property :id, String, :key => true
property :week, Integer
property :score, Integer
belongs_to :player
end
DataMapper.finalize.auto_migrate!
Player.new("jack", "golf", 5)
I understand that this is probably not the best way, so before you shoot my method down, please provide a better solution. I will probably accept your answer :)
It seems like the IllegalContextError is originating from the data_mapper validators.
The data_mapper docs on validators doesn't provide much info for a newbie to understand context AND in relation to validators.
Here is my hacky workaround. I override the validators by using the bang operator (!). The solution is as follows.
require 'data_mapper'
DataMapper::setup(:default, "sqlite3://#{Dir.pwd}/prod.db")
class Player
include DataMapper::Resource
property :name, String, :key => true
property :sport, String
has n, :weeks
def initialize(name, sport, week)
self[:name] = name
self[:sport] = sport
self[:week] = week
self.save!
self.weeks.create(:id => "#{name}#{week}", :score => 0)
end
end
class Week
include DataMapper::Resource
property :id, String, :key => true
property :week, Integer
property :score, Integer
belongs_to :player
end
DataMapper.finalize.auto_migrate!
Player.new("jack", "golf", 5)

Datamapper's hooks won't work

Can't understand why hooks don't work. I have the following model:
class DirItem
include DataMapper::Resource
# property <name>, <type>
property :id, Serial
property :dir_cat_id, Integer, :required => true
property :title, String, :required => true
property :price, Integer, :default => 0
belongs_to :dir_cat
has n, :dir_photos
has n, :dir_field_values
before :destroy do
logger.debug "==============DESTROYING ITEM ##{id}, TITLE
#{title}"
dir_field_values.destroy
dir_photos.destroy
end
end
When I call destroy method either from my app or irb, it returns false. The errors hash is empty, the log message doesn't print and the record won't delete.
This hook works for me (ruby 1.9.2 / DM 1.0.2):
require 'rubygems'
require 'dm-core'
require 'dm-migrations'
# setup the logger
DataMapper::Logger.new($stdout, :debug)
# connect to the DB
DataMapper.setup(:default, 'sqlite3::memory:')
class DirItem
include DataMapper::Resource
# property <name>, <type>
property :id, Serial
property :dir_cat_id, Integer, :required => true
property :title, String, :required => true
property :price, Integer, :default => 0
has n, :dir_photos
before :destroy do
dir_photos.destroy
end
end
class DirPhoto
include DataMapper::Resource
property :id, Serial
belongs_to :dir_item
end
DataMapper.finalize.auto_migrate!
#i = DirItem.create(:title => 'Title', :dir_cat_id => 1)
#i.dir_photos.create
#i.dir_photos.create
#i.dir_photos.create
#i.destroy
The DM logger reveals that each of the dir_photos are destroyed before the dir_item is. Instead of using hooks, you might want to look into using dm-constraints though. With something like:
has n, :dir_photos, :constraint => :destroy
you can be sure that all the dir_photos will be destroyed when the dir_item is destroyed, and this will also be enforced by database level foreign key constraints.

App Engine Jruby DataMapper List Property

How to use list/array as property in DataMapper on Jruby on Google AppEngine?
This will work like has..and..belongs..to..many, without a join table...
class Person
include DataMapper::Resource
property :id, Serial
property :name, String, :nullable => false
property :project_ids, List
timestamps :at
# project should be flagged as archived, not deleted
def projects
Project.all(:id => project_ids)
end
end
class Project
include DataMapper::Resource
property :id, Serial
property :name, String, :nullable => false
property :archived, Boolean, :default => false
# the join table is bolted onto the person model
def people
Person.all(:project_ids => id)
end
end

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