Create JSON from 2 associated Datamapper models - ruby

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.

Related

Ruby datamapper associations

I am just learning Ruby and datamapper, I have read the docs about associations from the official DataMapper site, but I still have two problems.
First whenever I add associated object, I can not see it when displaying all objects.
I have test class like:
class Test
include DataMapper::Resource
property :id, Serial
property :name, String
has 1, :phonen, :through => Resource
end
And then phonen class like:
class Phonen
include DataMapper::Resource
property :id, Serial
property :number, String
belongs_to :test
end
Then I am creating those 2 objects
#test = Test.create(
:name => "Name here"
)
#phone = Phonen.create(
:number => "Phone number"
)
#test.phonen = #phone
#test.save
And I want to display them like that (I want to return json)
get '/' do
Test.all.to_json
end
What am I doing wrong? maybe its something with the to_json...
I honestly don't know..
But I have one additional question to this topic, lets say I managed to connect those two classes, if I display JSON will I get Phonen { } or just inside class { }?
I know its probably very easy question, but I can't figure it out. That's why I decided to ask you guys. Thanks for help
Test.all
Is returning an active record association in array form, not a hash, when you try to convert to json it's failing.
You can try:
render json: Test.all
As asked in this question:
Ruby array to JSON and Rails JSON rendering

One-to-one DataMapper association

I'm very new to DataMapper, and I'm trying to create models for the following scenario:
I've got a number of users (with a user name, password etc.), who can also be players or referees or both (so Single Table Inheritance is not an option). The base models would be:
class User
include DataMapper::Resource
property :id, Serial
# Other user properties go here
end
class Player
include DataMapper::Resource
property :id, Serial
# Other player properties go here
# Some kind of association goes here
end
class Referee
include DataMapper::Resource
property :id, Serial
# Other referee properties go here
# Some kind of association goes here
end
DataMapper.finalize
I'm not sure, though, what kinds of associations to add to Player and Referee. With belongs_to :user, multiple players can be associated with the same user, which doesn't make sense in my context. In RDBMS terms I guess what I want is a unique constraint on the foreign key in the Players and Referees tables.
How do I accomplish this in my DataMapper model? Do I have to perform the check myself in a validation?
There are different ways you could do this. Here's one option:
class User
include DataMapper::Resource
property :id, Serial
# Other properties...
has 1, :referee, :required => false
has 1, :player, :required => false
end
class Referee
include DataMapper::Resource
# DON'T include "property :id, Serial" here
# Other properties...
belongs_to :user, :key => true
end
class Player
include DataMapper::Resource
# DON'T include "property :id, Serial" here
# Other properties...
belongs_to :user, :key => true
end
Act on the referee/player models like:
u = User.create(...)
u.referee = Referee.create(...)
u.player = Player.create(...)
u.player.kick_ball() # or whatever you want to call
u.player.homeruns
u.referee.flag_play() # or whatever.
See if this works. I haven't actually tested it but it should be good.
The previous answer works other than :required => false is not recognized for has 1 properties.
It's also confusing because for has n properties, you can use new right on the property or otherwise treat it as a collection. In your example, you would be tempted to code
u = User.create ...
u.referee.create ...
But that fails in the case of has 1 because the property is a single value, which begins life as nil and so you have to use the method the previous answer indicates. Also, having to explicitly make the belongs_to association into the key is a little confusing.
It does seem to execute validations and have the right association actions (so u.save will also save the referred-to Referee). I just wish it were more consistent between has n and has 1.

DataMapper - create new value for relational DB

I have a relational DB defined as follows. How can I enter a new value, where B belongs to A. The code given below doesn't seem to work.
Thanks
class A
include DataMapper::Resource
property :id, Serial, :key => true
property :name, String
belongs_to :b
end
class B
include DataMapper::Resource
property :id, Serial, :key => true
property :name, String
has n, :as
end
Create new value
# Create new value
post '/create' do
a = A.new
b = B.new
b.attributes = params
b.belongs_to = a #problem is here
b.save
redirect("/info/#{a.id}")
end
#belongs_to is a model (class) method and you use it to declare ManyToOne relationship.
In your example you should use "<<" method like this:
b.as << a
That will add "a" instance to "as" collection and associate both resources.
[...] How can I enter a new value, where B belongs to A. The code given below doesn't seem to work.
Your code implies you're after A belonging to B, but your question is the reverse so I'll show how to do that, i.e., B belongs to A.
class A
include DataMapper::Resource
property :id, Serial, :key => true
property :name, String
has n, :bs # A has many B's
end
class B
include DataMapper::Resource
property :id, Serial, :key => true
property :name, String
belongs_to :a, :required => false # B has only 1 A
end
Note your has and belongs_to are reversed here. I also added required => false to the belongs_to side because DataMapper will silently refuse to save your model if ever don't have b.a before calling saveā€”once you're comfortable with it you can remove the required false if you desire.
Here are two ways you can use that model:
# Create new value
post '/create' do
a = A.new
a.save
b = B.new
b.attributes = params
b.a = a
b.save
redirect("/info/#{a.id}")
end
This example is generally the same as yours, but I added a save call for A. Note this may not be necessary, I'm not in a good place to test this particular case; in the past I've found DataMapper will save some related objects automatically but not others so I've developed the habit of always saving explicitly to prevent confusion.
# Create new value
post '/create' do
a = A.create
b = a.bs.create(params)
redirect("/info/#{a.id}")
end
In the second example I call create on the many-side of the relationship, this makes a new B, associates it with "a", sets the params given, and saves it immediately. The result is the same as the previous example.
If you're just getting familiar with DataMapper, you may find it helpful to add the following to your app:
DataMapper::Model.raise_on_save_failure = true
This will cause DataMapper to give you errors and backtraces in cases like the above, more info here.

Correct way to make a DataMapper association

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.

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

Resources