Created
December 11, 2011 01:41
-
-
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 file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # 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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.