Skip to content

Instantly share code, notes, and snippets.

@stevenharman
Created December 11, 2011 01:41
Show Gist options
  • Select an option

  • Save stevenharman/1457584 to your computer and use it in GitHub Desktop.

Select an option

Save stevenharman/1457584 to your computer and use it in GitHub Desktop.
When wrapping AR behind an intentional interface, go explicit or generic/idiomatic?
# This is a record, as in a vinyl.
class Record < ActiveRecord::Base
belongs_to :user
belongs_to :album
# explicitly stating what is needed
def from_library_for_album(collector, album)
where(user_id: collector).where(album_id: album)
end
# or, if we go more generic/idiomatic
def from_library(collector, options={})
album = options.fetch(:album) { false }
status = options.fetch(:status) { :mint }
records = where(user_id: collector)
records = records.where(album_id: album) if album
records = records.where(status: status) if status
records
end
end
class Album < ActiveRecord::Base
has_many :records
belongs_to :artist
end
class User < ActiveRecord::Base
has_many :records
end
# I prefer to keep AR as a private interface used only w/in the Model.
class Library
def initialize(collector, fetch_records=Record)
@collector = collector
@fetch_records = fetch_records
end
def fetch_records_for_album(album)
fetch_records.from_library_for_album(collector, album)
# ... or ...
fetch_records.from_library(collector, album: album)
# and what about more params?
fetch_records.from_library_for_album_in_mint_condition(collector, album)
# ... or ...
fetch_records.from_library(collector, album: album, condition: :mint)
end
end
class LibrariesController < ApplicationController
def album
library = Library.new(current_user)
@album = Album.find(params[:id])
@records = library.fetch_records_for_album(@album)
end
end
@hkarthik
Copy link

There's some great discussion here, wish I could make it to CodeMash this year to partake in the booze filled continuation.

I agree AR definitely leaves a lot to be desired when it comes to separation of concerns. It's true that if you follow the idiomatic rules, things can remain quite testable purely because of the powerful stubbing capabilities in Ruby and RSpec. You don't have to wrap everything in a testable abstraction like we were all used to doing with C#.

But there are definitely things that still feel weird with AR and don't work quite as well if you try to build any abstraction layers around it. I'd consider Sequel as a possible alternative to using an ORM, although its really raw by comparison.

Or just try using MongoDB and get out of relational mapping all together. For side projects, I think its probably the best way to go.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment