开发者

DataMapper - why "has" and "belongs_to"?

I'm just getting started with DataMapper and I'm trying to figure out why you need to specify a has and a belongs_to.

For instance, look at the example on the DataMapper website. Isn't this redundant? If Post has n comments, then doesn't Comment automatically belongs_to post? Why do I have to specify this开发者_StackOverflow中文版?

class Post
  include DataMapper::Resource

  property :id, Serial

  has n, :comments
end

class Comment
  include DataMapper::Resource

  property :id,     Serial
  property :rating, Integer

  belongs_to :post  # defaults to :required => true

  def self.popular
    all(:rating.gt => 3)
  end
end


You specify both sides of the relationship only when you want to use the methods generated by the extra specification. It's completely optional: If you never need to get to the Post from the Comment (e.g. @comment.post), you won't have to specify the belongs_to relation in Comment.

One advantage is that your instances are a bit cleaner because in Comment the additional methods are not autogenerated. On the other hand, if you need them, those extra methods would not bother you.

See also the documentation about associations in ActiveRecord.


That gives you the methods to access the relational object easily. Such as @post.comments @comment.post. I see what you mean, applying has_many could imply the belongs_to. Though given the developer overhead to add the belongs_to, is probably better than adding more system overhead to dynamically add the methods to the right class.

Another thing would be when using the has_many relation ship through another has_many relationship. That would cause odd belong_to relationships, and would probably cause issues with the SQL.

For example:

class User < ActiveRecord::Base
  has_many :roles, :through => :roles_users
  has_many :roles_users
end

The RolesUser being a join table that has belongs_to for the both the user and the role models. Implying the belongs to in this case would then add a belongs_to to the role model to a user. Nor does this not make sense, it also wouldnt work due to the lack of the database column being there. Of course this could be adjusted when the through option is there, but again this would highly raise the complexity of the code when it's not needed. As Daan said in his answer, you do not need both for it to work, it's optional.


I'd like to add to these good answers that if you have required dm-constraints (directly or via data_mapper) and use auto_migrate!, then belongs_to will automatically add foreign key constraints at the database level, whereas has alone will not do this.

e.g.:

require 'data_mapper'

class Post
  include DataMapper::Resource
  property :id, Serial
end

class Comment
  include DataMapper::Resource
  property :id, Serial

  belongs_to :post
end

Produces this (via MySQL adapter):

 ~ (0.140343) CREATE TABLE comments (id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
post_id INT(10) UNSIGNED NOT NULL, PRIMARY KEY(id)) ENGINE = InnoDB
CHARACTER SET utf8 COLLATE utf8_general_ci

 ~ (0.234774) CREATE INDEX index_comments_post ON comments (post_id)

 ~ (0.433988) ALTER TABLE comments ADD CONSTRAINT comments_post_fk
FOREIGN KEY (post_id) REFERENCES posts (id) ON DELETE NO ACTION ON UPDATE NO ACTION

If you use has n, :comments within Post but choose not to include belongs_to :post within Comment, the post_id column in the comments table will still be created and indexed, but no foreign key constraint will be added.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜