I am unable to determine why I am getting a name error here. I'm new to DataMapper, but trying to associations down. Any help is appreciated.
User:
class User
include DataMapper::Resource
property :id, Serial, :key => true
property :first_name, String
property :last_name, String
property :company, String
property :city, String
property :country, String
property :mobile_number, Integer
property :email_address, String
property :shahash, String
property :isRegistered, Boolean
belongs_to :event, :required => true
end
DataMapper.auto_upgrade!
Event:
class Event
include DataMapper::Resource
property :id, Serial, :key => true
property :name, String
property :occuring, DateTime
has n, :user
end
DataMapper.auto_upgrade!
I think the problem is you're calling DataMapper.auto_upgrade! after each model definition. When you call it after just defining one model, there's no child model there. Instead, you should define and/or require all your models and then do:
DataMapper.finalize # set up all relationships properly
# and do a basic model sanity check
DataMapper.auto_upgrade! # create database table if it doesn't exist
Add an init file in your models directory and move all of your your DataMapper.finalize statements to it (i.e. remove the finalize statement from your individual model files)
app/models/init.rb
require_relative 'file_name'
require_relative 'another_model_file_name'
DataMapper.finalize
Then in your application file require the init file
require_relative 'models/init'
Related
I am new to using DataMapper and simply want to add a property from one class, to a table in another. I have two classes, as seen below: I would like to add the 'handle' property from the class 'user', as a column in the table for 'peep'. I have required all the relevant gems (not included below) but am struggling with the DataMapper syntax. I have tried variants of has n, :user and belongs to etc, but all result in a 'user_id has NULL values' errors.
Class 'user':
class User
include DataMapper::Resource
property :id, Serial
property :email, String, format: :email_address, required: true, unique: true
property :handle, String, required: true
end
Class 'peep':
class Peep
include DataMapper::Resource
property :id, Serial
property :peep_content, String
property :created_at, DateTime
end
Seems duplicated with your another question:Data Mapper Associations - what code?
But here is my answer, when the association keys are not conventional id or ..._id, you have to specify it explicitly when you add the association, to let DataMapper know how to query the relation for you.
Doc: http://datamapper.org/docs/associations.html Customizing Associations section.
class User
...
has n, :peeps, 'Peep',
:parent_key => [ :handle ], # local to this model (User)
:child_key => [ :user_handle ] # in the remote model (Peep)
end
class Peep
...
belongs_to :user, 'User',
:parent_key => [ :handle ], # in the remote model (Peep)
:child_key => [ :user_handle ] # local to this model (User)
end
Using Sinatra and DataMapper. This is my first time trying to use more than two model classes. Not sure what is causing the error. Thanks.
The error:
NameError: Cannot find the child_model ContactNote for Contact in contact_notes
The models:
class Contact
include DataMapper::Resource
property :id, Serial
property :fullname, Text, :required => true
property :email, Text
property :phone, Text
has n, :contact_notes
has n, :projects
end
class Contact_Note
include DataMapper::Resource
property :id, Serial
property :contact_content, Text, :required => true
property :created_at, DateTime
property :updated_at, DateTime
belongs_to :contact
end
class Project
include DataMapper::Resource
property :id, Serial
property :project_name, Text, :required => true
property :created_at, DateTime
property :updated_at, DateTime
belongs_to :contact
has n, :project_notes
end
class Project_Note
include DataMapper::Resource
property :id, Serial
property :project_content, Text, :required => true
property :created_at, DateTime
property :updated_at, DateTime
belongs_to :project
end
Datamapper makes expectations on class names based on ruby conventions. It expects your contact notes to be in a ContactNote class, while you've named it Contact_Note, hence the error it can't find ContactNote.
I have 2 classes called User and Gig and also a joining table Usergig.
class Usergig
include DataMapper::Resource
property :id, Serial
belongs_to :user
belongs_to :gig
end
class Gig
include DataMapper::Resource
property :id, Serial
property :gigname, String
property :gigtext, Text
has n, :usergigs
has n, :users, :through => :usergigs
end
class User
include DataMapper::Resource
property :id, Serial
property :username, String
property :realname, String
has n, :usergigs
has n, :gigs, :through => :usergigs
end
And when i try to run:
post '/gig/add' do
user = User.get(1)
gig = user.gigs.create(:gigname => params[:gig_gigname], :gigtext => params[:gig_gigtext])
end
I get the error:
NoMethodError at /gig/add
undefined method `include?' for nil:NilClass
I've googled for about two hours now and read the DataMapper documentation.
Anyone know what i'm doing wrong?
In Usergig try the following:
belongs_to :user, :key => true
belongs_to :gig, :key => true
You forgot to call DataMapper.finalize...this is what you need to call after all your models are loaded. Rails does this for you, in Sinatra you must call it manually.
I am having trouble with associations in the following code.
The error I'm getting is a comment on the last line of code.
Edit: I simplified the code...
require 'rubygems'
require 'data_mapper' # requires all the gems listed above
require 'pp'
DataMapper.setup(:default, 'sqlite:///Users/chris/Dropbox/HawkEye-DB Test/store.sqlite')
class Manufacturer
include DataMapper::Resource
property :id, Serial
property :name, String
has n, :products
end
class Product
include DataMapper::Resource
property :id, Serial
property :name, String
belongs_to :manufacturer
has 1, :productoptionset
end
class Productoptionset
include DataMapper::Resource
property :id, Serial
property :name, String
belongs_to :product
end
DataMapper.auto_migrate!
# Make some manufactureres
gortex = Manufacturer.create(:name => 'Gortex')
garmin = Manufacturer.create(:name => 'Garmin')
gps = garmin.products.create(:name => 'GPS Unit')
samegps = Product.get(1)
pp samegps.productoptionset.create # undefined method `create' for nil:NilClass (NoMethodError)
create is a class method (kind of like a static method in Java) so it can't be called on instances (or non instances in this case) :)
You could create your objects like this
class Manufacturer
include DataMapper::Resource
property :id, Serial
property :name, String
has n, :products
end
class Product
include DataMapper::Resource
property :id, Serial
property :manufacturer_id, Integer
property :name, String
belongs_to :manufacturer
has 1, :productoptionset
end
class Productoptionset
include DataMapper::Resource
property :id, Serial
property :product_id, Integer
property :name, String
belongs_to :product
end
DataMapper.auto_migrate!
# Make some manufactureres
gortex = Manufacturer.create(:name => 'Gortex')
garmin = Manufacturer.create(:name => 'Garmin')
garmin.products << Product.create(:name => 'GPS Unit')
samegps = Product.get(1)
samegps.productoptionset = Productoptionset.create(:name => "MyProductoptionset")
The has 1 creates an accessor productoptionsetwhich is initially nil rather than a collection. That nil has no method create. The collection has.
You can create and associate the ProductOptionSet via
Productoptionset.create(:name => 'Foo', :product => gps)
I am working with DataMapper and Sinatra to create a simple app. Here's the structure:
The app has Accounts. Each account has users and campaigns. Each user has comments that should be related to a specific campaign.
Comments should ideally have a user_id and a campaign_id to relate them both.
How can I relate the 2 together? Here's the code that I have which does not work:
class Account
include DataMapper::Resource
property :id, Serial
property :mc_username, String, :required => true
property :mc_user_id, String, :required => true
property :mc_api_key, String, :required => true
property :created_at, DateTime
property :updated_at, DateTime
has n, :users
has n, :campaigns
end
class User
include DataMapper::Resource
property :id, Serial
property :name, String, :required => true
property :email, String, :required => true
property :is_organizer, Integer
property :created_at, DateTime
property :updated_at, DateTime
belongs_to :account, :key => true
has n, :comments
end
class Campaign
include DataMapper::Resource
belongs_to :mailchimpaccount, :key => true
has n, :comments
property :id, Serial
property :cid, String
property :name, String
property :current_revision, Integer
property :share_url, Text, :required => true
property :password, String
property :created_at, DateTime
property :updated_at, DateTime
end
class Comment
include DataMapper::Resource
belongs_to :campaign, :key => true
belongs_to :user, :key => true
property :id, Serial
property :at_revision, Integer
property :content, Text
property :created_at, DateTime
end
With this code, I can't save a comment since I can't figure out how to associate it to a campaign and a user at the same time. I can't really get my head around wether I should even try to relate them at all using DataMapper.
I would love to know if this code is correct, how I can go about creating a comment that is related to both. If not, what structure and associations would be optimal for this scenario?
Thanks so much for the help!
What you're doing seems reasonable, I think you just need to get rid of the :key => true options since you don't really want those associations to be part of the comment's primary key.
You should probably start by looking at these datamapper docs on properties.
Alex is right, what you have there is a composite primary key. This would be ok if you only wanted each user to have one comment per campaign, but this is probably not the case but you do want to make sure that the comment is associated to a user and a campaign so use required => true, like so:
class Comment
include DataMapper::Resource
property :id, Serial
belongs_to :campaign, :required => true
belongs_to :user, :required => true
property :at_revision, Integer
property :content, Text
property :created_at, DateTime
end
Also your key in the campaign model may be problematic:
class Campaign
include DataMapper::Resource
belongs_to :mailchimpaccount, :key => true
#......
You probably just want to make that required too.
So it seems that my thinking was correct. I can relate a comment to both a user and a campaign in this way:
# Get a user and a campaign first that we can relate to the comment
user = User.get(user_id)
campaign = Campaign.get(campaign_id)
comment = Comment.new
comment.content = "The comment's content"
user.comments << comment # This relates the comment to a specific user
campaign.comments << comment # This now relates the comment to a specific campaign
comment.save # Save the comment
Dangermouse's suggestion to replace the :key => true option with :required => true also helped clean up the schema. Thanks!