casecommons / with_model Goto Github PK
View Code? Open in Web Editor NEWDynamically build an Active Record model (with table) within a test context
Home Page: http://www.casebook.net
License: MIT License
Dynamically build an Active Record model (with table) within a test context
Home Page: http://www.casebook.net
License: MIT License
Travis CI is reporting some problems when running against the latest Rails master (which will eventually become Active Record 5)
Here are the failures: https://travis-ci.org/Casecommons/with_model/jobs/43477610
I did a git bisect on rails and found that the first commit that causes the problems is rails/rails@a975407
Obviously Rails master is nowhere near stable, so this isn't a pressing issue, but I do want to track my progress at getting to the bottom of this. We may need to change how with_model does some things, or perhaps even report an issue back up to the Rails team.
Right now we are pointing people to the spec to see example usage. But as the spec gets more and more complicated it no longer emphasizes the common use cases. We should write up a quick README.
Great library, very useful! I did however run into one problem.
While trying to test an ActiveRecord model with has_secure_password:
https://github.com/rails/rails/blob/master/activemodel/lib/active_model/secure_password.rb
I am getting the following error:
Failures:
I created a failing spec here:
https://github.com/namick/with_model/commit/861a1a4eef042db411f26a95aea46742d525dc77
I am not sure if it is something I am doing wrong or just an edge case... If you can point me in the right direction as to why this might be happening, im happy to fix it and give you a pull request on it.
Cheers
I'm trying to write a dummy model to test that callbacks are used properly, but with_model
throws an error:
NoMethodError:
undefined method `_run_before_save_callbacks' for #<Dummy id: nil, created_at: nil, updated_at: nil>
# /home/fletch/.rvm/gems/ruby-2.1.7/gems/activemodel-4.2.4/lib/active_model/attribute_methods.rb:433:in `method_missing'
# /home/fletch/.rvm/gems/ruby-2.1.7/gems/activesupport-4.2.4/lib/active_support/callbacks.rb:81:in `run_callbacks'
I don't know if it's digging too deep into re-implementing the underlying details of ActiveRecord, but it would be nice to be able to use with_model
to test callbacks as well.
See ryanb/cancan#476
Hello,
Regarding the following part of the code:
with_model/lib/with_model/model.rb
Line 59 in 481e96b
This call has a side effect on our project: all the models that inherit ActiveRecord::Base
are not available in the ActiveRecord::Base.descendants
list after the upgrade to Rails 7.
I temporary handle the side effect by overriding the following line:
ActiveSupport::DescendantsTracker.clear([ActiveRecord::Base])
ActiveSupport::DescendantsTracker.clear([@model])
Is there a reason to clear all models related to ActiveRecord::Base
and not only the current model?
Regards
The error: ActiveRecord::RecordNotUnique: Mysql2::Error: Duplicate entry 'FakeRecord-1' for key 'index_entities_on_entityable'
I have a table with a polymorphic unique relationship:
create_table :entities do |t|
t.references :entityable, null: false, polymorphic: true, index: { unique: true }
end
I've implemented the logic for this relationship in a Concern (called Entityable
). This involves creating an associated Entity
automatically on creation of a model which includes Entityable
:
before_validation -> { Entity.create!(entityable: self) if entity.nil? }, on: :create
I'm using with_model to test this Concern outside of an existing model:
class EntityableTest < ActiveSupport::TestCase
with_model :FakeRecord do
table do |t|
t.string :name
end
model do
include Concerns::Entityable
end
end
def test_something
record = FakeRecord.create!(name: 'test')
# assert that this creates an Entity correctly...
end
end
Here, the test passes on the first run, but on subsequent runs, calling FakeRecord.create!
gives the error ActiveRecord::RecordNotUnique: Mysql2::Error: Duplicate entry 'FakeRecord-1' for key 'index_entities_on_entityable'
. It seems that what's happening is a FakeRecord
with ID of 1
is trying to be created, and an index entry already exists for that.
This is strange to me for 2 reasons:
Regardless, it would seem that the fix for this would be incrementing model IDs rather than restarting from 1
each time. In the meantime, it seems impossible to effectively test unique indexes via with_model
.
Please let me if there is any need for clarification. Thanks!
At the moment, it seems to create table on every example (unless I am missing something).
It would be nice to have an option to do it once per with_table declaration, purely to make it faster.
Otherwise, thank you very much for a great gem. I also quite like how it adds the documentation aspect to the spec. Like here for instance:
describe DomainNameValidator do
with_model :site do
table do |t|
t.string :host_name
end
model do
validates :host_name, domain_name: true
end
end
...
with_model
block shows what the table should have in order to use this custom validation and how to use it. Me like!
Hello,
Using jenkins on our setup we get the following errors (rake spec)
An error occurred in an after hook
NameError: constant Object::Voucher not defined
occurred at /var/lib/jenkins/jobs/project/workspace/vendor/bundle/ruby/2.1.0/gems/with_model-1.1.0/lib/with_model/constant_stubber.rb:18:in `remove_const'
F
An error occurred in an after hook
NameError: constant Object::Voucher not defined
occurred at /var/lib/jenkins/jobs/project/workspace/vendor/bundle/ruby/2.1.0/gems/with_model-1.1.0/lib/with_model/constant_stubber.rb:18:in `remove_const'
F
An error occurred in an after hook
NameError: constant Object::Voucher not defined
occurred at /var/lib/jenkins/jobs/project/workspace/vendor/bundle/ruby/2.1.0/gems/with_model-1.1.0/lib/with_model/constant_stubber.rb:18:in `remove_const'
The Voucher is with_model object:
with_model :voucher do
table do |t|
t.string :ticket
end
model do
attr_accessor :validation_hash
validates :ticket, ticket: true
end
end
Any idea/solution? Thanks
❯ ruby -v
ruby 3.1.0p0 (2021-12-25 revision fb4df44d16) [arm64-darwin21]
❯ rspec --backtrace
An error occurred while loading ./spec/active_record_behaviors_spec.rb.
Failure/Error: ActiveRecord::Base.establish_connection(adapter: adapter, database: ':memory:')
NoMethodError:
super: no superclass method `descendants' for ActiveRecord::Base:Class
# /Users/grant/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/activerecord-7.0.0/lib/active_record/dynamic_matchers.rb:22:in `method_missing'
# /Users/grant/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/activesupport-7.0.0/lib/active_support/descendants_tracker.rb:90:in `descendants'
# /Users/grant/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/activesupport-7.0.0/lib/active_support/callbacks.rb:923:in `block in define_callbacks'
# /Users/grant/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/activesupport-7.0.0/lib/active_support/callbacks.rb:920:in `each'
# /Users/grant/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/activesupport-7.0.0/lib/active_support/callbacks.rb:920:in `define_callbacks'
# /Users/grant/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/activemodel-7.0.0/lib/active_model/validations.rb:50:in `block in <module:Validations>'
# /Users/grant/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/activesupport-7.0.0/lib/active_support/concern.rb:136:in `class_eval'
# /Users/grant/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/activesupport-7.0.0/lib/active_support/concern.rb:136:in `append_features'
# /Users/grant/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/activesupport-7.0.0/lib/active_support/concern.rb:133:in `include'
# /Users/grant/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/activesupport-7.0.0/lib/active_support/concern.rb:133:in `block in append_features'
# /Users/grant/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/activesupport-7.0.0/lib/active_support/concern.rb:133:in `each'
# /Users/grant/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/activesupport-7.0.0/lib/active_support/concern.rb:133:in `append_features'
# /Users/grant/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/activerecord-7.0.0/lib/active_record/base.rb:309:in `include'
# /Users/grant/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/activerecord-7.0.0/lib/active_record/base.rb:309:in `<class:Base>'
# /Users/grant/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/activerecord-7.0.0/lib/active_record/base.rb:282:in `<module:ActiveRecord>'
# /Users/grant/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/activerecord-7.0.0/lib/active_record/base.rb:15:in `<top (required)>'
# ./spec/spec_helper.rb:29:in `require'
# ./spec/spec_helper.rb:29:in `<top (required)>'
# <internal:/Users/grant/.rbenv/versions/3.1.0/lib/ruby/3.1.0/rubygems/core_ext/kernel_require.rb>:85:in `require'
# <internal:/Users/grant/.rbenv/versions/3.1.0/lib/ruby/3.1.0/rubygems/core_ext/kernel_require.rb>:85:in `require'
# ./spec/active_record_behaviors_spec.rb:3:in `<top (required)>'
# /Users/grant/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rspec-core-3.10.1/lib/rspec/core/configuration.rb:2112:in `load'
# /Users/grant/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rspec-core-3.10.1/lib/rspec/core/configuration.rb:2112:in `load_file_handling_errors'
# /Users/grant/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rspec-core-3.10.1/lib/rspec/core/configuration.rb:1615:in `block in load_spec_files'
# /Users/grant/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rspec-core-3.10.1/lib/rspec/core/configuration.rb:1613:in `each'
# /Users/grant/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rspec-core-3.10.1/lib/rspec/core/configuration.rb:1613:in `load_spec_files'
# /Users/grant/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rspec-core-3.10.1/lib/rspec/core/runner.rb:102:in `setup'
# /Users/grant/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rspec-core-3.10.1/lib/rspec/core/runner.rb:86:in `run'
# /Users/grant/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rspec-core-3.10.1/lib/rspec/core/runner.rb:71:in `run'
# /Users/grant/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rspec-core-3.10.1/lib/rspec/core/runner.rb:45:in `invoke'
# /Users/grant/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/rspec-core-3.10.1/exe/rspec:4:in `<top (required)>'
# /Users/grant/.rbenv/versions/3.1.0/bin/rspec:25:in `load'
# /Users/grant/.rbenv/versions/3.1.0/bin/rspec:25:in `<main>'
We're getting an error when we have cache_classes = true
on CI with Rails 7.0.1:
RuntimeError:
DescendantsTracker.clear was disabled because config.cache_classes = true
# /home/circleci/app/vendor/bundle/ruby/2.7.0/gems/activesupport-7.0.1/lib/active_support/descendants_tracker.rb:119:in `clear'
# /home/circleci/app/vendor/bundle/ruby/2.7.0/gems/with_model-2.1.6/lib/with_model/model.rb:59:in `cleanup_descendants_tracking'
# /home/circleci/app/vendor/bundle/ruby/2.7.0/gems/with_model-2.1.6/lib/with_model/model.rb:38:in `destroy'
# /home/circleci/app/vendor/bundle/ruby/2.7.0/gems/with_model-2.1.6/lib/with_model.rb:53:in `block in setup_object'
I made you a lil repro script. The child without foreign key is created just fine, the child with foreign key hits an exception.
require "bundler/inline"
gemfile do
source "https://rubygems.org"
gem "sqlite3"
gem "combustion"
gem "with_model"
gem "minitest"
end
require "combustion"
require "minitest/autorun"
require "with_model"
# A hack to override some Combustion behavior
module Bundler
def self.require(*)
# noop
end
end
ENV['DATABASE_URL'] = "sqlite3::memory:"
ENV['RAILS_ENV'] = "test"
Combustion.initialize! :active_record, database_reset: false, load_schema: false do
config.enable_reloading = true
end
WithModel.runner = :minitest
class ForeignKeysSpec < Minitest::Spec
extend WithModel
with_model :Parent do
model do
has_many :children
has_many :children_with_foreign_key, class_name: "ChildWithForeignKey"
end
end
with_model :Child do
table do |t|
t.references :parent
end
model do
belongs_to :parent
end
end
with_model :ChildWithForeignKey do
table do |t|
t.references :parent, foreign_key: true
end
model do
belongs_to :parent
end
end
it "creates a child without a foreign key" do
parent = Parent.create!
child = parent.children.create!
assert_equal parent, child.parent
end
it "creates a child with a foreign key" do
parent = Parent.create!
assert_raises ActiveRecord::StatementInvalid do
parent.children_with_foreign_key.create!
end
end
end
After upgrading to Rails 4.2.1 we are experiencing the following error:
An error occurred in an after hook
NameError: constant Object::Presenter not defined
occurred at /Users/foo/.rvm/gems/ruby-2.1.5@foo-rails4/gems/with_model-1.2.1/lib/with_model/constant_stubber.rb:18:in `remove_const'
I haven't had a chance to look into the root cause of this issue but wanted to bring it to your attention right away.
We've been migrating a project that uses with_mocks
in its specs to Rails 5 from 4.2, and are finding that the autogenerated names for indices are now frequently longer than the character limit for our underlying database (PG9.6). This may not be a bug in with_mocks
per se, if it's just a result of changes upstream in ActiveRecord, but documenting this behavior would be helpful for future users.
Manually specifying a shorter index name addresses the issue for now.
Breaking example:
require "rails_helper"
describe "index issue" do
with_model :MidsizeNameChild do
table do |t|
t.belongs_to :midsize_name_parent
end
model do
belongs_to :midsize_name_parent
end
end
with_model :MidsizeNameParent do
model do
has_many :midsize_name_children
end
end
let(:instance) { MidsizeNameParent.create }
describe "try to instantiate" do
it "is an example" do
instance
end
end
end
Produces: Index name 'index_with_model_midsize_name_children_39923_70337190696860_on_midsize_name_parent_id' on table 'with_model_midsize_name_children_39923_70337190696860' is too long; the limit is 63 characters
(though UUID will vary)
Working example:
require "rails_helper"
describe "index issue" do
with_model :MidsizeNameChild do
table do |t|
t.belongs_to :midsize_name_parent,
index: { name: "shorter_index_name" }
end
model do
belongs_to :midsize_name_parent
end
end
with_model :MidsizeNameParent do
model do
has_many :midsize_name_children
end
end
let(:instance) { MidsizeNameParent.create }
describe "try to instantiate" do
it "is an example" do
instance
end
end
end
(passes)
The problem here is that posts is referenced in the second context before it is defined so the Post class that is referenced is the one from the previous context. You can verify this by looking at the object ids.
context "when the model has a circular nested attribute reference" do
with_model :blog do
table {}
model do
has_many :posts
accepts_nested_attributes_for :posts
end
end
with_model :post do
table do |t|
t.integer :blog_id
end
model do
puts self.object_id
belongs_to :blog
accepts_nested_attributes_for :blog
end
end
subject { Post.to_xsd }
it "should generate a valid XSD" do
validate_xsd(subject)
end
end
context "when the model has a nested reference that references another nested reference" do
with_model :blog do
table {}
model do
has_many :posts
has_many :readers
accepts_nested_attributes_for :posts
accepts_nested_attributes_for :readers
end
end
with_model :post do
table do |t|
t.integer :blog_id
end
model do
puts self.object_id
belongs_to :blog
has_many :readers
accepts_nested_attributes_for :blog
accepts_nested_attributes_for :readers
end
end
with_model :reader do
table do |t|
t.integer :blog_id
t.integer :post_id
end
end
subject { Post.to_xsd }
it "should generate a valid XSD" do
validate_xsd(subject)
end
end
end
Hey there!
Any plans on releasing a new version? The latest release is not compatible with Rails 6 and master
is #28.
Right now the tests don't pass.
There are problems sometimes when the model block is not specified.
Currently, the gem has a dependency on activerecord < 6.1. With the release of rails 6.1.0.rc1, it'd be good to make a new release of with_model that allows activerecord 6.1 :)
I get the following error while running guard and RSpec 2.12.2
Failure/Error: Unable to find matching line from backtrace
NoMethodError:
undefined method `stub_const' for #<RSpec::Core::ExampleGroup::Nested_1:0x007fd11c8f7498>
Any idea?
There seem to be a couple of sticky points to full minitest support. Namely:
a) The Minitest setup
block executes before with_model so the class is not accessible. In Minitest, this block is similar to before(:all)
in RSpec so used widely in initializing the test scenario.
b) There's a hard-coded call to before in the with_model
block, which isn't supported by Minitest. It's possible to get around it with a extend Minitest::Spec::DSL
but that seems a bit unfortunate.
Any directions on how best to resolve? I'm happy to submit a PR, just looking for guidance and perhaps willingness to persevere on a solution.
In pg_search we reused a model name between two sibling contexts, and it seems that the local var for the second test was picking up the first model.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.