Last active
October 29, 2018 04:57
-
-
Save arthurnn/ad5aa2b6811dfddaf94fa35aed84a73c to your computer and use it in GitHub Desktop.
Load ActiveRecord fixtures from a block instead of a yml file
This file contains 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
require 'minitest/autorun' | |
require 'active_record' | |
ActiveRecord::Base.logger = Logger.new(STDOUT) | |
conn = { adapter: 'sqlite3', database: ':memory:' } | |
ActiveRecord::Base.establish_connection(conn) | |
class User < ActiveRecord::Base | |
connection.create_table :users, force: true do |t| | |
t.string :username | |
t.timestamps | |
end | |
end | |
class ExampleTest < ActiveSupport::TestCase | |
include ActiveRecord::TestFixtures | |
include GitHub::Fixtures | |
fixtures do | |
@user = User.create!(username: "dhh") | |
end | |
setup do | |
# make sure username is reset | |
assert_equal "dhh", @user.username | |
end | |
test "save!" do | |
@user.username = "arthurnn" | |
@user.save! | |
assert_equal "arthurnn", @user.username | |
end | |
test "update!" do | |
@user.update!(username: 'arthurnn2') | |
assert_equal 'arthurnn2', @user.username | |
end | |
end |
This file contains 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
require 'active_support/all' | |
module GitHub | |
module Fixtures | |
extend ActiveSupport::Concern | |
included do | |
include ActiveSupport::Callbacks | |
define_callbacks :fixtures | |
prepend BlockFixtures | |
class << self | |
prepend BlockFixtures::ClassMethods | |
end | |
end | |
module BlockFixtures | |
module ClassMethods | |
# Public: Declare fixtures for all tests in the test class. | |
# | |
# &block - Block that creates fixture data. The database will be rolled back | |
# to this state between tests. | |
# | |
# Returns nothing. | |
def fixtures(*args, &block) | |
set_callback(:fixtures, :before, *args, &block) | |
end | |
end | |
# When reloading the instance variables saved by the fixtures block, | |
# ActiveRecord::Fixtures will invoke a `find` method in that instance. | |
# This is a class that implements the `find` method, so we reload | |
# the persisted object into different test runs. | |
class InlineFixtureSet | |
def initialize(object) | |
@object = object | |
end | |
def model_class | |
@object.class | |
end | |
def find | |
if model_class.respond_to?(:find) | |
if model_class.respond_to?(:unscoped) | |
model_class.unscoped.where(:id => @object.id).first! | |
else | |
model_class.find(@object.id) | |
end | |
else | |
@object | |
end | |
rescue ActiveRecord::RecordNotFound | |
warn "Record #{@object.inspect} not found" | |
nil | |
end | |
end | |
# Private: Method called from ActiveRecord::Fixtures module. | |
# This method is reponsible for loading the fixtures into the database. | |
# And also to track the instance variables so the next run can load them. | |
# see https://github.com/rails/rails/blob/65b62f652ca564c3904e2d32d25e079090f3c78c/activerecord/lib/active_record/fixtures.rb#L894 | |
def load_fixtures(*) | |
fixtures_loaded = {} | |
# before loading the fixtures we need to cleanup the database | |
enlist_fixture_connections.each do |conn| | |
conn.tables.each do |table| | |
conn.delete "DELETE FROM #{table}" | |
end | |
end | |
before = instance_variables | |
# Enable the instantiation of fixtures for the next runs, | |
# so we don't need to eval the fixtures block again. | |
self.class.use_instantiated_fixtures = true | |
run_callbacks :fixtures | |
(instance_variables - before).each do |ivar| | |
fixtures_loaded[ivar[1..-1]] = InlineFixtureSet.new(instance_variable_get(ivar)) | |
end | |
{fixtures: fixtures_loaded} | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment