Fetching latest commit…
Cannot retrieve the latest commit at this time
|Failed to load latest commit information.|
== Welcome to Relationships To get started: rake explain:populate # creates some objects rake explain:go # prints out some stuff This app was written in response to http://modernsage.wordpress.com/2011/02/05/rails-3-0-arel-acrobatics/ Blog post at: http://ryanangilly.com/post/3207048558/stinky-magic In that blog post, my buddy Chris is doing some stuff with Arel/AR that, in my opinion, is backwards. It's causing him to extend ActiveRecord::Base in a way that I feel is unnecessary, and potentially dangerous down the road Chris wants to do stuff like: Forum.mine.posts.comments The intent is that he wants to access all the comments owned by a post owned by a forum owned by a particular user. Working off the Forum model, he wants to scope things through the 'mine' scope, which scopes things to an authenticated user. There are two problems with this approach: First, Forum.mine is a backwards way of accessing records belonging to an authenticated user. Normally, a Rails app would authenticate a user and provide helpers at the view and controller level to access that user. You'll see this in a lot of apps as: current_user Now, the problem with Forums.mine is that in order for it to work, you have to have code inside the model that goes back out to the authentication system. Authentication is the controller's domain. It's an awkward coupling of concerns that causes your code to get all tangled up. A much more "drop through" way to retrieve objects is to have the user be at the root when going left to right. The common way to get Forums owned by a person at the controller level would be: current_user.forums The second problem is that: Forum.mine.posts.comments Doesn't make sense. Posts don't have comments. A _single_ Post has comments. The concept of Comments that belong to many Posts doesn't exist here. It's a confusion I've seen in new and experienced ActiveRecord developers alike. What is more straightforward would be this kind of accessor: current_user.forum_comments I've implemented this in this app as a series of relationships, and an accessor that does a map: class User < ActiveRecord::Base has_many :forums has_many :posts, :through => :forums def forum_comments Comment.where(:post_id => posts.map(&:id)) end end Yes, this does two queries, but that's just fine. Chris implemented an extension of ActiveRecord::Base that allows this to work: Forum.mine.posts.comments And although I don't have any examples, I'm pretty this will break down as more complication relationships are introduced. The last paragraph of Chris' post says: You can use it with a single association or with a monster hierarchy of the form A -> B -> C -> D -> E -> F ->DRY, recursive, scalable. Now that’s what I call magic. In my opinion, this is horribly dangerous. When A, B, C, D, and E grow to be a couple million rows (which is not very uncommon at all nowadays) you're gonna have a very non-scalable join to deal with. While the solution I've proposed may not look as magical, I feel that it's correct to err on the side of verbosity and explicitness when defining relationships in this way. As a final note, if you really need to do A -> B -> C -> D -> E -> F a lot, that's a sign that some denormalization may be justified. Assuming that -> denotes has_many, F would have an e_id on it. In this case, adding an a_id would allow you to go A -> F directly and much faster.