Running Multiple Factories of the Same Object in Production - ruby

At work, we're using Ruby 2.3.4, Rails 4.2.7, and FactoryGirl 4.0.0. We've run into the problem of having way too many traits in our base factories. We've started a project for replacing them and have a pattern in mind, but we need to be able to incrementally add our new factories to our production code while the original factories remain active.
Are there any reasonable ways to get this done?
This question, Running two spec folders in Rails with RSpec, seems to have the same problem, but separate branches is not a feasible solution for us.

The first example here might be what you're looking for.
On one of the latest versions of factory-bot, you can set up concurrent factories like this:
factory :orignal_class do
text 'original text'
end
factory :new_class_factory, class: OriginalClass do
text 'this will be used instead when creating new_class_factory'
end
When you invoke the second factory, it will still be of the same class as the first factory, but will instead use the fields defined in its factory over the original factory.

Related

Is it possible to use Factory Girl to update an already instanced factory?

I am trying to streamline our cukes trying to leverage the wonderful factories built into our system for unit tests.
I am setting up a #bread ||= FactoryGirl.create(:bread) in a background step.
Throughout that feature, I want to add a trait which would be called #bread ||= FactoryGirl.create(:bread, :organic) if the background step did not exist.
Since #bread already exists, is there a way for me to 'update' it with the trait?
Try something like this (I haven't tested this)
#bread.update(FactoryGirl.attributes_for(:bread, :organic)

Specify table name mid application Ruby-Datamapper

I'm wanting to dynamically create and query tables using Datamapper.
While Datamapper allows you to work with legacy tables and schemas, and in this way set the table name used this is only during initialisation, not within the application.
Is there an easy way to tell Datamapper to migrate/upgrade a Model with an assigned table name in application, and to then tell it to query this table?
This should not be a problem.
All Ruby classes can be created, and re-defined at run-time. Even initialization is at run-time. Initialization just happens to be executed first, before other code is executed.
That is why monkey-patches work so easily. It's just additional code at initialization that just re-defines classes to add extra methods, variables etc.
There is no Ruby code that is "special" in the sense that it only runs at compile time. Ruby is an interpreted language.
To dynamically create a class, see Dynamically creating class in Ruby.
Assuming you don't need to dynamically create classes from an array of strings, you can define additional methods with define_method, or call Datamapper methods at runtime to add attributes.
To define new methods in a class:
Post.send :define_method, :new_method_name do
end
To define a new property using the Datamapper property:
class Post
include DataMapper::Resource
property :title, String # the static way
end
Post.send :property, :title, String # add property the dynamic way (at run-time)
Do note that any tables or properties you define at run-time will not be available if you restart your server, unless the code that dynamically generates these are re-executed.
To update your tables at runtime, you simply do the same thing as normal, that is, call:
DataMapper.auto_upgrade!
To upgrade only a single table, you can also do:
Post.auto_upgrade!
2nd warning: If you have multiple processes, the dynamic code will need to be run in each process, or the additional table Models and Properties will not be available.
This is a problem if you have multiple worker processes, as might happen in production (eg. Nginx with multiple Unicorn workers, or multiple Mongrel workers behind a Ha_proxy).
If you have a single process server, then that is not a problem. However, if you have multiple worker processes, you must run the dynamic code to generate these extra classes and properties in EACH process to make it available.
This is actually the same for initialization, because each process goes through initialization (or if forked, inherit any initialization).
The easiest way without changing anything under the hood is to use separate databases instead of tables (assuming that any relationships will also be stored in the separate database) and open a connection to an additional repository in the block.
DataMapper.setup(:external, "adapter://username:password#hostname/dbname")
DataMapper.repository(:external) do...end

How to set a namespace in ruby at runtime?

I have an ActiveRecord based application that is used via command line utilities. Having the models namespaced in such an application is advantageous for keeping the Object namespace clean.
I'm starting to build a rails application around these ActiveRecord models and, though I have overcome some of my initial troubles with using models in a namespace, I'm finding things are more verbose than I'd like.
What I want is to programmaticaly set a namespace for my ActiveRecord classes when used in the command line utilities and to programmaticaly not set a namespace for these models when used in the Rails app.
I know that the files themselves could be altered at runtime before being required, but I'm looking for something in the Ruby language itself to accomplish this cleanly.
hard to offer a great suggestion without seeing some code, but here are two possibilities.
It sounds like you have two clients for this code. Maybe make it an engine (just a fancy gem), you can add your paths to autoload paths, then use it from the gem without all the railsy crap getting in the way.
Maybe create a constant then reopen it in the models:
in some initializer
ActualNamespace = Class.new
DynamicNamespace = ActualNamespace
in your model file
class DynamicNamespace
class MyModel
end
end
DynamicNamespace::MyModel # => ActualNamespace::MyModel
Then for your command line app
DynamicNamespace = Object
Which is the same as not having a namespace:
DynamicNamespace::MyModel # => MyModel
Now you might wind up having difficulties with some of the Rails magic, which is largely based on reflection. I don't totally know what you'll face, but I'd expect forms to start generating the wrong keys when submitting data. You can probably fix this by defining something DynamicNamespace.name or something along those lines.
Autoloading, is likely to also become an issue, but I think you can declare autoload paths somehow (I don't know for sure, but googling "rails autoloading" gives some promising results, looks like it just hooks into Ruby's autoloading -- though I think this is going away in Ruby 2.0) worst case, you can probably define a railtie to eager load the dirs for you. This is all a bit out of my league, but I'd assume you need the railties defined before the app is initialized, so you may need to require the railtie in config/application.rb
Unfortunately, at the end of the day, when you start deviating from Rails conventions, life starts getting hard, and all that magic you never had to think about breaks down so you suddenly have to go diving into the Rails codebase to figure out what it was doing.

Rails 3 generate without persistence layer support

I'm trying to create a Rails app without a persistence layer (ActiveRecord, MongoMapper, etc). I've used --skip-active-record on rails new nice_app. This has changed the config/application.rb, but when I try to create new "model" with Rails generate - rails g model nice_class - it fail like a noob with:
No value provided for required options '--orm'
So, if I skip ActiveRecord I can't use Rails generators ?
Note the tasks that get called when you run rails g model nice_class:
invoke active_record
create db/migrate/20111227183458_create_nice_classes.rb
create app/models/nice_class.rb
invoke rspec
create spec/models/nice_class_spec.rb
The first thing you notice, is that it's using ActiveRecord to generate the model. Besides that, though, it's not doing a lot: creates a file in the migrations folder (which you don't need), another file in the model folder (which you do need), and a file in the test or spec folder (which you 'should' need). You can make these yourself if you want want, they are pretty close to being empty anyway.
For specifics about models not based on ActiveRecord, take a look at Ryan Bates' "Tableless Models" Railscast available here: http://railscasts.com/episodes/193-tableless-model.
If you are going to be making these kinds of non-ActiveRecord models a lot, you can write your own generator that does exactly what you want.
Best of luck.
The models that are generated by the Rails generators are subclasses of ActiveRecord, which only really makes sense in the context of an app with an ORM. You could certainly create models that aren't subclasses of ActiveRecord (and thus not associated with any ORM), but you'd have to do that manually.

Factory Girl - what's the purpose?

What's the purpose of Factory Girl in rspec tests when I could use before(:each) blocks? It feels like the only difference between Factory Girl and a before(:each) is that the factory prepares object creation outside of the test. Is this right?
Gems like Factory Girl and Sham allow you to create templates for valid and re-usable objects. They were created in response to fixtures which where fixed records that had to be loaded into the database. They allow more customization when you instantiate the objects and they aim to ensure that you have a valid object to work with. They can be used anywhere in your tests and in your before and after test hooks.
before(:each), before(:all), after(:each) and after(:all) all aim to give you a place to do setup and teardown that will be shared amongst a test group. For example, if you are going to be creating a new valid user for every single test, then you'll want to do that in your before(:each) hook. If you are going to be clearing some files out of the filesystem, you want to do that in a before hook. If your tests all create a tmp file and you want to remove it after your test, you'll do that in your after(:each) or after(:all) hook.
The ways these two concepts differ is that Factories are not aimed at creating hooks around your tests, they are aimed at creating valid Ruby objects and records, so that you can keep your object creation flexible and DRY. Before and after hooks are aimed at setup and teardown tasks that are shared in an example group so that you can keep your setup and teardown code DRY.
FactoryGirl replaces fixtures in tests. This way, you won't have to keep the fixtures up-to-date as you change the data model. Fixtures can also tend to get unwieldy as you add more edge cases.
FactoryGirl generates data on the fly and adding and removing fields is much easier. Also, you can use it in setup just how you'd use fixtures.
Does that make it clearer?
also fixture definitions are global across your entire application. Factories can be local - so data specific to a isolated test case is in the setup for that particular context and not in a single global fixtures file.
This book covers the subject very well if you want some more reading matter

Resources