Dave
Dave

Reputation: 23

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

Upvotes: 0

Views: 251

Answers (2)

Yuri Gadow
Yuri Gadow

Reputation: 1813

[...] 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.

Upvotes: 3

solnic
solnic

Reputation: 5743

#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.

Upvotes: 3

Related Questions