Skip to content

Instantly share code, notes, and snippets.

@csexton
Created June 18, 2014 19:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save csexton/f8feaca701b7ad3ab0a7 to your computer and use it in GitHub Desktop.
Save csexton/f8feaca701b7ad3ab0a7 to your computer and use it in GitHub Desktop.
class ModelSeeder
attr_reader :logger, :seeded
def initialize(logger: STDOUT)
@logger = logger
@seeded ||= Hash.new
end
def make(klass, id, opts)
log "Seeding #{klass.model_name} ##{id} #{find_seed_name(opts)}"
track_seeded_model klass, id, find_and_update(klass, id, opts)
end
private
def log(msg)
logger.puts msg if logger
end
def find_and_update(klass, id, opts)
model = klass.find_or_initialize_by id: id
model.update!(opts)
end
def find_seed_name(opts)
opts.fetch(:name) { opts.fetch(:description) { } }
end
def track_seeded_model(klass, id, model)
key = "#{klass}_#{id}"
if seeded.has_key? key
raise "Already seeded a #{klass} with the id #{id}"
else
seeded[key] = model
end
model
end
end
require 'spec_helper'
describe ModelSeeder do
class FakeModel
def self.model_name
""
end
def self.find_or_initialize_by(opts)
self.new
end
def update!(opts)
end
end
it "prevents adding duplicate seeds" do
seeder = ModelSeeder.new
stub_const("SpecModel", FakeModel)
expect {
seeder.make SpecModel, 1, {name: "first"}
seeder.make SpecModel, 1, {name: "first again"}
}.to raise_error
end
end
@cupakromer
Copy link

Here's a few suggestions:

class ModelSeeder
  def make(klass, id, opts)
    log "Seeding #{klass.model_name} ##{id} #{find_seed_name(opts)}"
    track_seeded_model klass, id, find_and_update(klass, id, opts)
  end

  private

  def find_seed_name(opts)
    # part of the semantic meaning of fetch is to say, I need this thing, or I
    # should really have it. Here it doesn't look like we care at all really.
    # So it's just a lot cleaner to not use fetch.
    opts[:name] || opts[:description]
  end

  def track_seeded_model(klass, id, model)
    key = "#{klass}_#{id}"

    # No point having an else if you raise
    if seeded.has_key?(key)
      raise "Already seeded a #{klass} with the id #{id}"
    end

    seeded[key] = model
  end
end

describe ModelSeeder do
  class FakeModel
    def self.model_name
      name    # Classes have names ;-)
    end

    def self.find_or_initialize_by(opts)
      self.new
    end

    def update!(opts)
    end
  end

  it "prevents adding duplicate seeds" do
    seeder = ModelSeeder.new(logger: nil)

    seeder.make FakeModel, 1, {name: "first"}
    expect {
      seeder.make SpecModel, 1, {name: "first again"}
    }.to raise_error "Already seeded a FakeModel with the id 1"
  end

end

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