Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mongoid compatibility #80

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 37 additions & 5 deletions lib/seed-fu.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
require 'active_record'
require 'active_support/core_ext/module/attribute_accessors'
require 'seed-fu/railtie' if defined?(Rails) && Rails.version >= "3"

module SeedFu
autoload :VERSION, 'seed-fu/version'
autoload :Seeder, 'seed-fu/seeder'
autoload :ActiveRecordExtension, 'seed-fu/active_record_extension'
autoload :ModelExtension, 'seed-fu/model_extension'
autoload :BlockHash, 'seed-fu/block_hash'
autoload :Runner, 'seed-fu/runner'
autoload :Writer, 'seed-fu/writer'
Expand All @@ -30,7 +29,40 @@ def self.seed(fixture_paths = SeedFu.fixture_paths, filter = nil)
end
end

# @public
class ActiveRecord::Base
extend SeedFu::ActiveRecordExtension
# Don't try to require active_record in if this is being loaded inside a Rails
# app. Inside a Rails app, we'll assume ActiveRecord has been already been
# required if it is being used (in the config/application.rb file).
#
# This is to prevent this gem from requiring ActiveRecord in a non-ActiveRecord
# Rails app. This helps compatibility with other gems that may try to establish
# ActiveRecord connections if the class is defined.
if(!defined?(Rails))
begin
require 'active_record'
rescue LoadError
end
end

# Since Mongoid isn't pre-loaded in the same way ActiveRecord is by
# config/application.rb inside Rails apps, try to see if it exists regardless
# of Rails environment.
begin
require 'mongoid'
rescue LoadError
end

if(defined?(ActiveRecord::Base))
# @public
class ActiveRecord::Base
extend SeedFu::ModelExtension
end
end

if(defined?(Mongoid::Document))
# @public
module Mongoid::Document
module ClassMethods
include SeedFu::ModelExtension
end
end
end
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module SeedFu
module ActiveRecordExtension
module ModelExtension
# Load some seed data. There are two ways to do this.
#
# Verbose syntax
Expand Down
30 changes: 19 additions & 11 deletions lib/seed-fu/runner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,27 @@ def run
def run_file(filename)
puts "\n== Seed from #{filename}" unless SeedFu.quiet

ActiveRecord::Base.transaction do
open(filename) do |file|
chunked_ruby = ''
file.each_line do |line|
if line == "# BREAK EVAL\n"
eval(chunked_ruby)
chunked_ruby = ''
else
chunked_ruby << line
end
if(defined?(ActiveRecord::Base) && ActiveRecord::Base.connected?)
ActiveRecord::Base.transaction do
parse_file(filename)
end
else
parse_file(filename)
end
end

def parse_file(filename)
open(filename) do |file|
chunked_ruby = ''
file.each_line do |line|
if line == "# BREAK EVAL\n"
eval(chunked_ruby)
chunked_ruby = ''
else
chunked_ruby << line
end
eval(chunked_ruby) unless chunked_ruby == ''
end
eval(chunked_ruby) unless chunked_ruby == ''
end
end

Expand Down
41 changes: 33 additions & 8 deletions lib/seed-fu/seeder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ module SeedFu
# It is not recommended to use this class directly. Instead, use `Model.seed`, and `Model.seed_once`,
# where `Model` is your Active Record model.
#
# @see ActiveRecordExtension
# @see ModelExtension
class Seeder
# @param [ActiveRecord::Base] model_class The model to be seeded
# @param [Array<Symbol>] constraints A list of attributes which identify a particular seed. If
Expand All @@ -32,21 +32,41 @@ def initialize(model_class, constraints, data, options = {})
# Insert/update the records as appropriate. Validation is skipped while saving.
# @return [Array<ActiveRecord::Base>] The records which have been seeded
def seed
records = @model_class.transaction do
@data.map { |record_data| seed_record(record_data.symbolize_keys) }
records = []
if(defined?(ActiveRecord::Base) && @model_class <= ActiveRecord::Base)
@model_class.transaction do
records = seed_records
end
else
records = seed_records
end
update_id_sequence
records
end

private

def seed_records
@data.map { |record_data| seed_record(record_data.symbolize_keys) }
end

def validate_constraints!
unknown_columns = @constraints.map(&:to_s) - @model_class.column_names
column_names = []
if(defined?(ActiveRecord::Base) && @model_class <= ActiveRecord::Base)
column_names = @model_class.column_names
elsif(defined?(Mongoid) && Mongoid.models.include?(@model_class))
column_names = @model_class.fields.keys

# Allow the aliased "id" field when the internal "_id" field is
# present.
column_names << "id" if(column_names.include?("_id"))
end

unknown_columns = @constraints.map(&:to_s) - column_names
unless unknown_columns.empty?
raise(ArgumentError,
"Your seed constraints contained unknown columns: #{column_list(unknown_columns)}. " +
"Valid columns are: #{column_list(@model_class.column_names)}.")
"Valid columns are: #{column_list(column_names)}.")
end
end

Expand Down Expand Up @@ -76,16 +96,21 @@ def seed_record(data)
end

def find_or_initialize_record(data)
@model_class.where(constraint_conditions(data)).take ||
@model_class.new
if(defined?(ActiveRecord::Base) && @model_class <= ActiveRecord::Base)
record = @model_class.where(constraint_conditions(data)).take
elsif(defined?(Mongoid) && Mongoid.models.include?(@model_class))
record = @model_class.where(constraint_conditions(data)).first
end

record || @model_class.new
end

def constraint_conditions(data)
Hash[@constraints.map { |c| [c, data[c.to_sym]] }]
end

def update_id_sequence
if @model_class.connection.adapter_name == "PostgreSQL" or @model_class.connection.adapter_name == "PostGIS"
if(defined?(ActiveRecord::Base) && @model_class <= ActiveRecord::Base && (@model_class.connection.adapter_name == "PostgreSQL" or @model_class.connection.adapter_name == "PostGIS"))
return if @model_class.primary_key.nil? || @model_class.sequence_name.nil?

quoted_id = @model_class.connection.quote_column_name(@model_class.primary_key)
Expand Down
2 changes: 1 addition & 1 deletion lib/seed-fu/writer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class Writer
# @option options [Fixnum] :chunk_size (100) The number of seeds to write before generating a
# `# BREAK EVAL` line. (Chunking reduces memory usage when loading seeds.)
# @option options [:seed, :seed_once] :seed_type (:seed) The method to use when generating
# seeds. See {ActiveRecordExtension} for details.
# seeds. See {ModelExtension} for details.
# @option options [Array<Symbol>] :constraints ([:id]) The constraining attributes for the seeds
def initialize(options = {})
@options = self.class.default_options.merge(options)
Expand Down
3 changes: 2 additions & 1 deletion seed-fu.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ Gem::Specification.new do |s|
s.summary = "Easily manage seed data in your Active Record application"
s.description = "Seed Fu is an attempt to once and for all solve the problem of inserting and maintaining seed data in a database. It uses a variety of techniques gathered from various places around the web and combines them to create what is hopefully the most robust seed data system around."

s.add_dependency "activerecord", [">= 3.1"]
s.add_dependency "activesupport", [">= 3.1"]

s.add_development_dependency "activerecord", [">= 3.1"]
s.add_development_dependency "mongoid"
s.add_development_dependency "rspec", "~> 2.0"
s.add_development_dependency "pg", '~> 0'
s.add_development_dependency "mysql2", '~> 0'
Expand Down
6 changes: 6 additions & 0 deletions spec/connections/mongoid.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Mongoid.logger.level = Logger::DEBUG
Moped.logger.level = Logger::DEBUG
Mongoid.logger = Logger.new(File.expand_path("../../../debug.log", __FILE__))
Moped.logger = Logger.new(File.expand_path("../../../debug.log", __FILE__))

Mongoid.load!(File.expand_path("../mongoid.yml", __FILE__), "test")
9 changes: 9 additions & 0 deletions spec/connections/mongoid.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
test:
sessions:
default:
database: seed_fu_test
hosts:
- localhost:27017
options:
max_retries: 1
retry_interval: 0
24 changes: 12 additions & 12 deletions spec/seeder_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
s.title = "Peon"
end

bob = SeededModel.find_by_id(-2)
bob = SeededModel.find(-2)
bob.first_name.should == "Bob"
bob.last_name.should == "Bobson"

Expand All @@ -38,7 +38,7 @@
s.title = "Peon"
end

bob = SeededModel.find_by_id(5)
bob = SeededModel.find(5)
bob.first_name.should == "Bob"
bob.last_name.should == "Bobson"
end
Expand All @@ -60,13 +60,13 @@

SeededModel.count.should == 2

SeededModel.find_by_login("bob").first_name.should == "Bob"
SeededModel.where(:login => "bob").first.first_name.should == "Bob"
SeededModel.seed(:title, :login) do |s|
s.login = "bob"
s.title = "Peon"
s.first_name = "Steve"
end
SeededModel.find_by_login("bob").first_name.should == "Steve"
SeededModel.where(:login => "bob").first.first_name.should == "Steve"
end

it "should be able to create models from an array of seed attributes" do
Expand All @@ -76,9 +76,9 @@
{:login => "harry", :title => "Noble", :first_name => "Harry"}
])

SeededModel.find_by_login("bob").first_name.should == "Steve"
SeededModel.find_by_login("frank").first_name.should == "Francis"
SeededModel.find_by_login("harry").first_name.should == "Harry"
SeededModel.where(:login => "bob").first.first_name.should == "Steve"
SeededModel.where(:login => "frank").first.first_name.should == "Francis"
SeededModel.where(:login => "harry").first.first_name.should == "Harry"
end

it "should be able to create models from a list of seed attribute hashes at the end of the args" do
Expand All @@ -88,9 +88,9 @@
{:login => "harry", :title => "Noble", :first_name => "Harry"}
)

SeededModel.find_by_login("bob").first_name.should == "Steve"
SeededModel.find_by_login("frank").first_name.should == "Francis"
SeededModel.find_by_login("harry").first_name.should == "Harry"
SeededModel.where(:login => "bob").first.first_name.should == "Steve"
SeededModel.where(:login => "frank").first.first_name.should == "Francis"
SeededModel.where(:login => "harry").first.first_name.should == "Harry"
end

it "should update, not create, if constraints are met" do
Expand All @@ -110,7 +110,7 @@
s.title = "Peon"
end

bob = SeededModel.find_by_id(1)
bob = SeededModel.find(1)
bob.first_name.should == "Robert"
bob.last_name.should == "Bobson"
end
Expand All @@ -132,7 +132,7 @@
s.title = "Peon"
end

bob = SeededModel.find_by_id(1)
bob = SeededModel.find(1)
bob.first_name.should == "Bob"
bob.last_name.should == "Bobson"
end
Expand Down
66 changes: 45 additions & 21 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,39 +11,63 @@
puts "Using #{ENV["DB"]} to run the tests."
require File.dirname(__FILE__) + "/connections/#{ENV["DB"]}.rb"

ActiveRecord::Schema.define :version => 0 do
create_table :seeded_models, :force => true do |t|
t.column :login, :string
t.column :first_name, :string
t.column :last_name, :string
t.column :title, :string
if ENV['DB'] == 'mongoid'
class SeededModel
include Mongoid::Document
field :login, :type => String
field :first_name, :type => String
field :last_name, :type => String
field :title, :type => String

validates_presence_of :title
attr_protected :first_name if self.respond_to?(:protected_attributes)
attr_accessor :fail_to_save

before_save { false if fail_to_save }
end

create_table :seeded_model_no_primary_keys, :id => false, :force => true do |t|
t.column :id, :string
class SeededModelNoPrimaryKey
include Mongoid::Document
end

create_table :seeded_model_no_sequences, :id => false, :force => true do |t|
t.column :id, :string
class SeededModelNoSequence
include Mongoid::Document
end
else
ActiveRecord::Schema.define :version => 0 do
create_table :seeded_models, :force => true do |t|
t.column :login, :string
t.column :first_name, :string
t.column :last_name, :string
t.column :title, :string
end

execute("ALTER TABLE seeded_model_no_sequences ADD PRIMARY KEY (id)") if ENV['DB'] == 'postgresql'
end
create_table :seeded_model_no_primary_keys, :id => false, :force => true do |t|
t.column :id, :string
end

class SeededModel < ActiveRecord::Base
validates_presence_of :title
attr_protected :first_name if self.respond_to?(:protected_attributes)
attr_accessor :fail_to_save
create_table :seeded_model_no_sequences, :id => false, :force => true do |t|
t.column :id, :string
end

before_save { false if fail_to_save }
end
execute("ALTER TABLE seeded_model_no_sequences ADD PRIMARY KEY (id)") if ENV['DB'] == 'postgresql'
end

class SeededModelNoPrimaryKey < ActiveRecord::Base
class SeededModel < ActiveRecord::Base
validates_presence_of :title
attr_protected :first_name if self.respond_to?(:protected_attributes)
attr_accessor :fail_to_save

end
before_save { false if fail_to_save }
end

class SeededModelNoPrimaryKey < ActiveRecord::Base

class SeededModelNoSequence < ActiveRecord::Base
end

class SeededModelNoSequence < ActiveRecord::Base

end
end

RSpec.configure do |config|
Expand Down