Validate uniqueness on combined fields in DataMapper - ruby

I want to be able to put entries in my database where the manufacturer will be represented multiple times but not the same combination of manufacturer and model.
So "Sony(manufacturer), Tv(model)" is okay "Sony(manufacturer), OtherTv(model)" but the third entry "Sony(manufacturer), Tv(model)" is not okay since the combination of manufacturer and model is not unique. I tried with the :key => true validation but it doesn't seem to work. And I cannot do something like validates_uniqueness_of :manufacturer AND :model I guess. So how do you do it?
class Tvs
include DataMapper::Resource
property :id, Serial
property :manufacturer, String, :key => true
property :model, String, :key => true
validates_uniqueness_of :
end

You can actually go with:
class Tvs
include DataMapper::Resource
property :id, Serial
property :manufacturer, String, :unique_index => :manufacturer_model
property :model, String, :unique_index => :manufacturer_model
validates_uniqueness_of :model, :scope => :manufacturer
end
This will also give you a unique index in the database.

Nevermind.
It seems this did the job:
class Tvs
include DataMapper::Resource
property :id, Serial
property :manufacturer, String, :unique_index => true
property :model, String, :unique_index => true
validates_uniqueness_of :model, :scope => :manufacturer
end

class Tvs
include DataMapper::Resource
property :id, Serial
property :manufacturer, String, :unique_index => :manufacturer_model
property :model, String, :unique_index => :manufacturer_model
validates_is_unique :model, :scope => :manufacturer
end
I needed to modify the example to use "validates_is_unique" to get this to work.

If you remove the property :id Serial line, you will end up with a composite key (Manufacturer, Model), that will not allow duplicate Models for a particular Manufacturer.

Related

DataMapper Associations

I was just trying to create a database with DataMapper. I am trying to associate the class User with class Post, Post2, Post3 and Post4. And I didnt get any message or changes in the Data SQLite Free, a database Mac application that I am using. Below is the code I created. Did I make any mistakes? Thanks!
require 'sinatra'
require 'data_mapper'
DataMapper::setup(:default, "sqlite3://#{Dir.pwd}/wiki2.db")
class User
include DataMapper::Resource
property :id, Serial
property :username, Text, :required => true
property :password, Text, :required => true
property :date_joined, DateTime
property :edit, Boolean, :required => true, :default => false
has n, :posts
has n, :post2s
has n, :post3s
has n, :post4s
end
class Post
include DataMapper::Resource
property :id, Serial
property :content, Text
property :created_at, DateTime
property :updated_at, DateTime
belongs_to :user
end
class Post2
include DataMapper::Resource
property :id, Serial
property :content, Text
property :created_at, DateTime
property :updated_at, DateTime
belongs_to :user
end
class Post3
include DataMapper::Resource
property :id, Serial
property :content, Text
property :created_at, DateTime
property :updated_at, DateTime
belongs_to :user
end
class Post4
include DataMapper::Resource
property :id, Serial
property :content, Text
property :created_at, DateTime
property :updated_at, DateTime
belongs_to :user
end
DataMapper.finalize.auto_upgrade!

DataMapper `has n` for different types of a model

I would like to have a model with different types of has n, for example:
class Blog
include DataMapper::Resource
property :id, Serial
has 1, :owner # of type user...
has n, :authors # of type user...
end
class User
include DataMapper::Resource
property :id, Serial
has n, :blogs # owns some number
has n, :blogs # is a member of some number
end
I don't, however, want to use the Discriminator, since then I need to make new Owner or Author objects of old User objects and that would be ridiculous.
How can I best achieve this?
Try this:
class User
include DataMapper::Resource
property :id, Serial
has n, :blog_authors, 'BlogAuthor'
has n, :authored_blogs, 'Blog', :through => :blog_authors, :via => :blog
has n, :blog_owners, 'BlogOwner'
has n, :owned_blogs, 'Blog', :through => :blog_owners, :via => :blog
end
class Blog
include DataMapper::Resource
property :id, Serial
has n, :blog_authors, 'BlogAuthor'
has n, :authors, 'User', :through => :blog_authors
has 1, :blog_owner, 'BlogOwner'
end
class BlogAuthor
include DataMapper::Resource
belongs_to :blog, :key => true
belongs_to :author, 'User', :key => true
end
class BlogOwner
include DataMapper::Resource
belongs_to :blog, :key => true
belongs_to :owner, 'User', :key => true
end

Why is one of my tables not being populated if I use DataMapper's "has n" and "belongs_to" methods?

I am getting to grips with DataMapper on sqlite3 at the moment. I have to models defined which are creating two tables: "companies" and "apps".
Each app belongs to a company and each company many apps. I want to represent this relationship in my models but I add the "has n" and "belongs_to" methods to each class, the App class stops working when call #create on a bunch of apps, they are not inserted into the database.
If I don't have the associations methods then everything works fine.
This is my DataMapper code:
DataMapper::setup(:default, "sqlite3://#{Dir.pwd}/app.db")
class Company
include DataMapper::Resource
property :id, Serial
property :company_name,
property :company_id, Text, :unique => true
has n, :apps
end
class App
include DataMapper::Resource
property :id, Serial
property :app_id, Integer
property :bundle_id, Text
property :game_name, Text
property :company_name, Text
property :created_at, DateTime
property :rank, Integer
belongs_to :company
end
DataMapper.finalize.auto_upgrade!
puts 'Database and tables created'
This is the code I am using to populate my tables
companies_in_chart.each do |company|
#add_company = Company.create(
:company_name => company["company_name"],
:company_id => company["company_id"]
)
end
puts "Inserted companies into database"
apps_arr.each do |app|
#new_app = App.create(
:app_id => app["app_id"],
:bundle_id => app["bundle_id"],
:game_name => app["game_name"],
:company_name => app["company_name"],
:created_at => app["DateTime"],
:rank => app["rank"]
)
end
puts "Inserted apps into database"
EDIT: New code
#Set up database and apps table
DataMapper::setup(:default, "sqlite3://#{Dir.pwd}/app.db")
class Company
include DataMapper::Resource
property :id, Serial
property :company_name, Text, :required => true, :lazy => false
property :company_id, Text, :required => true, :lazy => false, :unique => true
has n, :apps
end
class App
include DataMapper::Resource
property :id, Serial
property :app_id, Integer, :required => true
property :bundle_id, Text, :required => true, :lazy => false
property :game_name, Text, :required => true, :lazy => false
property :company_id, Text, :required => true, :lazy => false
property :created_at, DateTime
property :rank, Integer
belongs_to :company
end
DataMapper.finalize.auto_upgrade!
puts 'Database and tables created'
#Insert apps and companies into database
apps_arr.each do |app|
# Creates a new company based on app entry if the company does
# not exist in the companies table
#add_company = Company.create(
:company_name => app["company_name"],
:company_id => app["company_id"]
)
#add_app = App.create(
:app_id => app["app_id"],
:bundle_id => app["bundle_id"],
:game_name => app["game_name"],
:company_id => app["company_id"],
:created_at => app["DateTime"],
:rank => app["rank"]
)
end
puts "Inserted app and companies into database"
#company = Company.first
ap #company # => #<Company #id=1 #company_name="Rovio Entertainment Ltd" #company_id="rovio">
ap #company.apps # => [] --I was hoping it would return all of Rovio's apps in the database
apps not created cause you have to attach a company when creating app.
if you want to add apps not attached to any company, use this in you App model:
belongs_to :company, :required => false
to attach a company when creating app:
#Insert apps and companies into database
apps_arr.each do |app|
# Creates a new company based on app entry if the company does
# not exist in the companies table
company = Company.first_or_create(
:company_name => app["company_name"],
:company_id => app["company_id"]
)
app = App.first_or_create(
:company => company, # you missed this
:app_id => app["app_id"],
:bundle_id => app["bundle_id"],
:game_name => app["game_name"],
:company_id => app["company_id"],
:created_at => app["DateTime"],
:rank => app["rank"]
)
end
puts "Inserted app and companies into database"
I successfully replicated your code on CIBox and it runs perfectly.
See the code and live demo here
As you can see, it creates a company and attach it to created app.
Company.first.apps returns created app, so associations works correctly.

Datamapper two associations at the same time

Lets say I have a post, this post should have a certian amount of comments, and these comments should be created by certian users. So these are my datamapper models:
class User
include DataMapper::Resource
property :id, Serial
property :name, String,
property :password, String
has n, :post
end
class Post
include DataMapper::Resource
property :id, Serial
property :text, Text
property :created_at, DateTime
belongs_to :user
end
class Comment
include DataMapper::Resource
property :text, Text,
property :created_at, DateTime
belongs_to :post
belongs_to :user
end
So let's say user x creates a post and user y wants to create a comment to this post. How do I do this then? I need something like this:
user = User.get(sessions[:user_id])
post = Post.get(params[:post_id])
comment = post.user.Comment.new {
:text => "Bla",
[...]
}
[...]
comment.save
[...]
So basicly the Model Post should be associated with the Model Comment and the Model Post, how do I realize this?
comment = Comment.create :post => post, :user => user, :text => 'Foo'

Don't work behaviors in Datamapper

I work with Sinatra. This is my models.
class Post
include DataMapper::Resource
property :id, Serial
property :title, String
property :body, Text
property :posted, Boolean, :default => true
has n, :comments
has n, :tags
end
class Comment
include DataMapper::Resource
property :id, Serial
property :user, String
property :body, Text
property :posted, Boolean, :default => false
belongs_to :post
end
class Tag
include DataMapper::Resource
property :id, Serial
property :tag, String
property :weight, Integer, :default => 1
belongs_to :post
end
Create a post
tags = params[:tags].split(' ')
post = Post.new(:title=>params[:title],:body=>params[:body])
tags.each { |tg|
post.tags << Tag.create(:tag=>tg)
}
redirect '/admin' if post.save
But no tags. What do I need to fix?
If you use one-to-many relation, you should create tags with :post set to post:
tags.each { |tg|
Tag.create(:tag => tg, :post => post)
}

Resources