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
Related
Here is my question.
I have 2 associated Datamapper models:
class Task
include DataMapper::Resource
property :id, Serial
property :date, Date
property :amount, Float
belongs_to :project, :required => true
end
class Project
include DataMapper::Resource
property :id, Serial
property :name, String, :required => true
property :desc, Text
belongs_to :company
has n, :tasks
end
My goal is to created JSON that will contain task date, amount and project name, that should be matched by project_id. At the moment JSON generation has following look:
Task.all.to_json(:only => [:date, :amount, :project_id])
I can access project_id from Task model, but have no idea how to add respective project name from Project model for every task. In SQL it looks like join:
select tasks.date, tasks.amount, projects.name from tasks
inner join projects
on tasks.project_id = projects.id;
Can you suggest correct way to create final JSON, using Datamapper way, but not SQL?
Thank you.
I have found solution for my problem. Here it is:
# create new structure to store merged result
Task_entry = Struct.new(:date, :amount, :pname)
# array to get results from database
all_task_items = Array.new
# run through result and fill the array with required data
Task.all.each do |task|
task_item = Task_entry.new(task.date, task.amount, task.project.name)
all_task_items << task_item
end
all_task_items.to_json # generate json
It works for me well. Hope it can be helpful.
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=>{}})
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)
I want to have a table of users. These users shall have n contacts and n messages..
My code is:
...
class User
include DataMapper::Resource
property :id, Serial, :key => true
property :nickname, String
has n, :contacts
has n, :messages
end
class Contact
include DataMapper::Resource
belongs_to :user
property :id, Serial, :key => true
property :authgiven, String
has 1, :user
end
class Message
include DataMapper::Resource
belongs_to :user
property :id, Serial, :key => true
property :data, String
end
#apply models (validation etc.)
DataMapper.finalize
...
There are no errors initializing DataMapper, but when I try to create a new User or whatever, save always returns false... Can someone please point out what is wrong?
I'm quite new to DataMapper, it always worked for me with simple tables without relationships, so I believe it has to do with the way I declared the 1:n relationship...
Hey you should remove that has 1, :user line from Contact model and you should be good.
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.