-
-
Save hovsater/6213677 to your computer and use it in GitHub Desktop.
Seeda.definitions do | |
# A simple seed | |
seed { Category.create! name: "Example Category" } | |
# Seeds can be defined in groups | |
define :users do | |
# Seeds can be named for later reference | |
seed(:john) { User.create! name: "John Doe" } | |
seed(:jane) { User.create! name: "Jane Doe" } | |
end | |
# Seeds can have dependencies | |
define :posts, [:users] do |users| | |
seed { users(:john).posts.create! title: "A post" } | |
seed { users(:jane).posts.create! title: "Another post" } | |
end | |
end |
I like how this cleans up the multiple calls to User.create!
, which is great if you change the class name to Member
or something else more descriptive or humane. A lot of people have objections to the word "User" as a class name representing people using your app.
This could easily be implemented. Blocks become Procs, which have an arity
attribute, so you could branch on block.arity
being 0 or 1. Run instance_exec
or class_exec
if it's 0 (class_exec
would be best unless you plan on being able to pass in non-Class objects to define
) and yield model_class.new
if it's 1.
I do wonder if {class,instance}_exec
would be too much magic here, though. For example, this line:
seed { create! name: "John Doe" }
When someone first looks at that, they might think create!
was a method on the definition. Maybe seed { model.create! foo: 'bar' }
might be better and the block is simply evaluated in the context of the current object, with model
being the class/object passed into define
.
Don't get me wrong, I love that kind of magic. I used instance_exec
everywhere in Perpetuity at first. But when explaining the gem to other people, I found I was having to justify that magic a lot, which I thought was kind of a UX smell. And it turned out, using yield
in the query DSL was much better anyway (gave it a more Enumerable-like API).
I don't have much to add other than I like the direction you're heading. There was a WONDERFUL baby that got thrown out with the bathwater called FixJour a few years ago. The thing I liked about it was that you could build complicated nested objects by default, E.g. build :user
would return a User
with an associated default Profile
, but if you specified a profile object in the build call, it would seamlessly override the default. This let you do things like spec a user with a nil/missing profile just by calling build :user, profile: nil
, etc.
Anyway, my point is you might want to look at FJ, but if not, please do consider making it easy to override seeds from the test suite UNLESS OF COURSE that's sort of not your point in creating Seeda in the first place. :-)
@jgaskins I feel the same way. I do love the magic that class_exec
and instance_exec
provide, but I don't think it's worth it if people having a hard time understanding what context the methods are executed in. At first thought, I don't think the magic happening here is too confusing, but on the other hand, a new user to gem might think so.
I guess it's a decision that have to be made on whether to use yield
or class_exec
and instance_exec
.
One thought that popped into mind was to convert the name of the definition into singular and then use it like so: seed { user.create! foo: bar }
but I think that is too much trouble of converting the name into singular as well as the confusion with the seed syntax that takes an argument.
@dbrady I will definitely look into FixJour and see if I can get some inspiration!
One idea that could increase the value of Seeda would be to apply your idea about context.
How about something like this: