Trouble linking one-to-one models in DataMapper

2019-08-02 23:48发布

问题:

Using PostgreSQL and DataMapper to build a Sinatra app, running into some problems with DataMapper (I'm very new to it, used to Rails/AR). For every Account created, it can either be an Artist, Venue, or Fan. Only one, no combining.

When the user signs up, I can create the Account instance fine, but I'm having trouble creating the account's has 1 Artist or Venue or Fan instance (for ease of conversation, we'll use Artist as the belonging model).

Here's my current model declarations:

class Account
    include DataMapper::Resource

    property :id,           Serial
    ...

    has 1, :artist, :required => false
    has 1, :venue, :required => false
    has 1, :fan, :required => false
end

class Artist
    include DataMapper::Resource

    # no ID
    ...

    belongs_to :account, :key => true
end

class Venue
    include DataMapper::Resource

    # no ID
    ...

    belongs_to :account, :key => true
end

class Fan
    include DataMapper::Resource

    # no ID
    ...

    belongs_to :account, :key => true
end

And here's how I'm trying to go about the sign up process:

account = Account.create(
    ...
)

account.Artist = Artist.create(:bio => "test")

This is currently giving me next error:

undefined method `Artist=' for #<Account:0x007ff2af289840>

回答1:

I guess you should use lowercase letter in referring model:

account.artist = Artist.create(:bio => "test")

This line:

has 1, :artist, :required => false

Add a relation, by which you can refer from Account to Artist.

Updated

This answer has exactly your model and seems like it worked. There is DataMapper.finalize thing, i guess you made it.



回答2:

After a lot of frustration, I figured this out. i hope my answer helps anyone else out, as I couldn't find anything on the internet that outlined this (maybe I'm just bad at searching).

Per @zishe's updated answer, I followed the structure he linked to, like thus:

class Account
    include DataMapper::Resource

    property :id,           Serial
    ...

    has 1, :artist
    has 1, :venue
    has 1, :fan
end

class Artist
    include DataMapper::Resource

    # no ID
    ...

    belongs_to :account, :key => true
end

And for creating associated records:

a = Account.create(...)
a.artist = Artist.create(...)

Creating the parent record, the Account, worked fine, but the belonged record, Artist, was not created nor was an error reported. After some frustration, I stumbled upon dm-noisy-failures, which I 'gem installed' and required in my app. Note to other data_mapper noobs, that gem is a must have, and I personally think it's an extremely awry decision on datamapper's part to hide errors the way it does. Thanks to dm-noisy-failures, my error was made clear to me. The solution was to manually tell data_mapper the ID of the parent record when creating the Artist record, like thus:

a = Account.create(...)
a.artist = Artist.create(:account_id => a.id)

Worked like a charm. Thank you @zishe (point given) and contributors of the linked answer.

UPDATE: so now i really feel like an idiot. tucked away in DataMapper's Associations documentation under the subheader Adding To Associations (contrary to my comment below) is an example that explains exactly how to do 1-to-1 relationships. i completely overlooked this. sorry everyone, ashamed.