How to generate Rails models from database schemas

Scott & Colin ~

Perhaps this conversation has reached the end of its useful life. But
in
case there still is anything left to be learned, let me respond to a
couple
of your comments.

“Why on earth would you keep re-generating scaffolds over and over???”
[Scott]

Because generators, when they work, are easier and more reliable than
manually updating code. Rails obviously has a powerful set of
generators
for jump-starting development. That’s one big reason why I’m spending
all
this time evaluating it (vs other platforms like Django). This whole
thread
is trying to understand the powers and limits of the Rails generators,
specifically in the somewhat-Rails-nonstandard scenario where the DB
schema
exists independently of the Rails app, so the requirement is to tailor
(and
re-tailor) the Rails objects to fit the DB schema, with as much
automagic
support as possible. Of course, the job of generators rapidly becomes
harder when you ask them to update objects that have been modified
manually
since they were originally generated. But some generators can go
farther
into update-land than others, and I’m trying to understand where Rails
is
on this dimension.

“The only thing you have to do now is to add the new field to the
view. Everything else is handled automatically. All you are
achieving by running the generator is adding that field to the view.”

Not so, from my experiments. Running “rake db:schema:dump” added the
field
to schema.rb, and the output from *scaffold *indicates that it edited a
total of 8 different files for me, namely:

conflict      test/fixtures/toys.yml
   force      test/fixtures/toys.yml
conflict    app/controllers/toys_controller.rb
   force    app/controllers/toys_controller.rb
conflict      app/views/toys/index.html.erb
   force      app/views/toys/index.html.erb
conflict      app/views/toys/show.html.erb
   force      app/views/toys/show.html.erb
conflict      app/views/toys/_form.html.erb
   force      app/views/toys/_form.html.erb
conflict      test/controllers/toys_controller_test.rb
   force      test/controllers/toys_controller_test.rb
conflict      app/views/toys/index.json.jbuilder
   force      app/views/toys/index.json.jbuilder
conflict      app/views/toys/show.json.jbuilder
   force      app/views/toys/show.json.jbuilder

Not only did the generator update all these files for me, but it
actually *knew
*which files had to be updated so that my app could handle the new
database
column - another huge advantage for a newbie like me, who would
otherwise
have to spend hours figuring that out.

Were not all of these 9 edits necessary to weave the new database column
into my app?

So, what’s the best approach: Run 3 simple console commands, or
manually
locate and edit 9 files (and debug the edits)?

I guess I see a lot more value in the Rails generators than you guys do.
And I’m still looking to see if they have still further powers
(especially
in update-land) that I haven’t discovered yet.

On Jun 5, 2015, at 2:25 PM, kenatsun [email protected] wrote:

Were not all of these 9 edits necessary to weave the new database column into my
app?

Actually, no, not at all.

So, what’s the best approach: Run 3 simple console commands, or manually locate
and edit 9 files (and debug the edits)?

The generators are not going to put them into your views located where
you need them and styled the way your app needs them. The generators are
not going to be able to write the actual tests for them. The generators
are not going to have a clue how they fit with your application’s logic
and what might need to be done with them in your models or controllers.


Scott R.
[email protected]
http://www.elevated-dev.com/
https://www.linkedin.com/in/scottribe/
(303) 722-0567 voice

On 5 June 2015 at 04:19, kenatsun [email protected] wrote:

Well, it would be nice to do in one step what I thought required four! So let
me try…

  1. Add another attribute toys.size to the schema (this looks different from
    the previous step 1 only because I have replaced my SQLite DB with a PostgreSQL
    one, named sunward_x:

    If step 1 is all that’s needed, I should be able to bring up any toys page an
    see the new size column, right? But I don’t:

As far as I can tell, at this point the app does indeed seem to be oblivious to
the change in the DB schema. If so, certainly something more needs to be done to
update the app.

The only thing you have to do now is to add the new field to the
view. Everything else is handled automatically. All you are
achieving by running the generator is adding that field to the view.
Rails does know about the new field, it is just that the view has not
asked for it to be displayed.

Colin

All of the changes were to files that specifically mentioned the model’s
attributes (aka the table’s columns), and all the changes consisted of
adding a mention of the new column. For example, the auto-edit of
show.json.jbuilder when I added the *size *attribute changed

json.extract! @toy, :id, :name, :color, :price, :created_at, :updated_at

to

json.extract! @toy, :id, :name, :color, :price, :size, :created_at, :
updated_at

On 5 June 2015 at 21:25, kenatsun [email protected] wrote:


Were not all of these 9 edits necessary to weave the new database column
into my app?

Diff the files and see what the changes were.

Colin

On 5 June 2015 at 22:21, kenatsun [email protected] wrote:

:updated_at
Did the generator add the validations for that attribute?

Did it add the code in the toy.rb that implements the business logic
involving that attribute?

Did it add the attribute to the views that do not just consist of the
simplistic tables and so on generated by the controller?

Did it add the required tests to make sure that all the uses of the
attribute are correct?

So is it worth the hassle of messing about with the generator just for
the few minor changes that it did make?

Colin

Comments inserted below.

Did the generator add the validations for that attribute?

Did it add the code in the toy.rb that implements the business logic
involving that attribute?

Did it add the attribute to the views that do not just consist of the
simplistic tables and so on generated by the controller?

Did it add the required tests to make sure that all the uses of the
attribute are correct?

For the Rails generators and their options that I have discovered so
far,
the answer to all these questions is, obviously, No.

Could there be generators that do some of these things? Yes.

*Are *there generators (or other tools) in the Rails World that do some
of
these things? That’s what I’m trying to find out in this thread.

So is it worth the hassle of messing about with the generator just for
the few minor changes that it did make?

As you develop an app starting with from a generated set of objects, the
answer at first is clearly Yes. As you manually modify the objects
produced by prior runs of the generator, at some point the answer
crosses
over into No. How soon you reach that point depends on the amount and
kind
of manual modifications you have made, vs the power of your generators
to
synthesize (or to help you synthesize) their new outputs with the
manual
refinements.

The synthetic abilities of the Rails generator that I’ve tried so far
(basically scaffold and whatever it invokes) seem to be limited to:

  1. Detecting whether an object that it is about to generate already
    exists.
  2. If so, detecting whether the existing and new versions of the object
    are
    identical.
  3. If the versions are not identical, showing you a diff between them.
  4. Giving you a choice between keeping the old version or replacing it
    *entirely
    *with the new version.

I haven’t yet found any help from Rails tools with synthesizing the old
(manually modified) and the new (generated) versions of a particular
object. I’ll mention just two possibilities:

  1. Even a tool that compares two files textually and helps you merge
    them by picking line-by-line between the two versions would be a
    significant help.
  2. Better yet would be a “smart generator” - perhaps better called a
    synthesizer rather than a generator - that knows the structure of
    Rails objects and uses that knowledge to make (or at least suggest)
    syntheses of old and new object versions that preserve the
    functionality of
    both. For example, to address one of Colin’s questions, suppose a
    “validates
    :name, presence: true” validation had been added to the Toy model
    before
    the new “size” column was added to the database. A synthesizer would
    recognize a validation declaration, and it would know that a
    validation
    declaration on one attribute is independent of the existence of
    another
    attribute, so it would leave the validation in place *and *add the
    new
    attribute to all the Rails objects where it is relevant. Or, more
    cautiously, the synthesizer would *suggest *this synthesis to the
    developer and let the developer decide. A suite of synthesizers that
    worked like this would extend the value of running
    generators/synthesizers
    waaay deep into the Rails development process. And such synthesizers
    are
    especially doable in Rails because they can exploit the fact - which
    even
    us newbies can see and appreciate - that Rails is a highly
    structured, and
    well-structured, system.

Sorry to get into sermonizing. All I really want from this thread is to
learn if any tools or facilities that provide additional
generating/synthesizing functionality currently exist in the Rails
World.

~ Thanks yet again
~ Ken

On Jun 6, 2015, at 4:31 PM, kenatsun [email protected] wrote:

Did it add the required tests to make sure that all the uses of the

• Even a tool that compares two files textually and helps you merge them by
picking line-by-line between the two versions would be a significant help.
• Better yet would be a “smart generator” - perhaps better called a
synthesizer rather than a generator - that knows the structure of Rails objects
and uses that knowledge to make (or at least suggest) syntheses of old and new
object versions that preserve the functionality of both. For example, to address
one of Colin’s questions, suppose a “validates :name, presence: true” validation
had been added to the Toy model before the new “size” column was added to the
database. A synthesizer would recognize a validation declaration, and it would
know that a validation declaration on one attribute is independent of the
existence of another attribute, so it would leave the validation in place and add
the new attribute to all the Rails objects where it is relevant. Or, more
cautiously, the synthesizer would suggest this synthesis to the developer and let
the developer decide. A suite of synthesizers that worked like this would extend
the value of running generators/synthesizers waaay deep into the Rails development
process. And such synthesizers are especially doable in Rails because they can
exploit the fact - which even us newbies can see and appreciate - that Rails is a
highly structured, and well-structured, system.
Sorry to get into sermonizing. All I really want from this thread is to learn
if any tools or facilities that provide additional generating/synthesizing
functionality currently exist in the Rails World.

I don’t know of any within the true meaning of “generator” that do all
that you have outlined here. But there are systems that ape the Django
admin view (RailsAdmin etc) that introspect your database and build an
interface to modify it on the fly. This is similar to how the Scaffold
system in Rails worked in versions less than 1 (and maybe a few minors
after 1). The problem with these systems that I have encountered is that
they have a well-formed opinion of how any type of field should be
represented, and in what order, and they build you an 80% solution in no
time at all. If you’re happy with what they give you, then you’re
completely set. But if you want something even a little bit off the
tracks they’ve laid, then you have a whole world of work to fake them
into giving it to you.

Rails took a different path after that first foray into
scaffolding-by-introspection, and decided that they would make it really
cheap and easy to get a static file, and then let you modify it later as
you go. I believe the thinking was that there was no way a professional
would not exert themselves to make a truly custom application if that
was what they were being paid to do.

One thing you might try is after you’ve made significant changes, try
making a new stunt-double app with the generator, with the new version
of your schema. Then copy the relevant files over to your actual working
app. You’ll be able to cherry-pick which parts of the new code make
sense, so you don’t have the generator overwrite something you spent
time customizing.

Walter

Thanks Walter ~

Comments interspersed below.

On Sunday, June 7, 2015 at 11:38:12 AM UTC-4, Walter Lee D. wrote:

they’ve laid, then you have a whole world of work to fake them into giving
it to you.

I have some experience with Django, and it fits with what you’re saying.
I’m pretty sure that Rails is ahead of Django in its ability to to the
kind
of generation/synchronization I’m looking for. For example, as far as I
know, Django’s schema-to-model generator (inspectdb) generates only
models
(not controllers or views); and it can only “introspect” the whole DB
and
generate models for all of its tables (as opposed to Rails where you can
run the generators table-by-table). BTW if any Django experts are
listening in and I have sold Django short, please steer me straight.

One thing you might try is after you’ve made significant changes, try
making a new stunt-double app with the generator, with the new version of
your schema. Then copy the relevant files over to your actual working app.
You’ll be able to cherry-pick which parts of the new code make sense, so
you don’t have the generator overwrite something you spent time
customizing.

Good idea. Could use a “file compare and merge” tool to do the
synthesis.

Another thing that’s emerging from this discussion is the interaction
between a platform’s generator abilities and the optimal design of the
apps
that you build with it. There’s a lot to be gained if the objects it
generates are “good enough” for your purposes, even if they aren’t
exactly
what you would create if starting from a blank slate, because you can
the
time and effort saved to writing custom code where it really matters or
simply to getting done earlier. (For example, I hear that the generated
Django “admin interface” was inspired by the fact that Django’s original
purpose was to build online newspapers. The data-entry people were
basically the paper’s reporters, who could do fine with plain-vanilla
entry
forms; the designer/developer creativity could be devoted to the
read-only
pages, to attract and serve the readers/customers.) So, it’s valuable
to
understand what kinds of automagic your platform can and can’t do, and
proceed accordingly.

~ Ken