Design Decisions

Hi All,

I am doing some research on how people start with their Rails app.
What design decisions are made and how is it build.

For example:

  • do you use scaffolding and go from there? Or do you create everything
    from scratch?

  • are you using multiple controllers? Or do you put everything in one?

  • do you use migrate?

  • how do you use migrate? Do you call migrate your self or do you use
    the migration file that comes with the generation of the model?

  • when you use authentication, do you have one authentication controller
    that you share with multiple apps (if you have multiple apps)?

  • do you keep scalability in mind when building an app? How?

  • anything else that you can think of… :wink:

I am interested to see what the different approaches might be.

Thanx!!

Mischa

Mischa Peters wrote:

Hi All,

I am doing some research on how people start with their Rails app.
What design decisions are made and how is it build.

For example:

  • do you use scaffolding and go from there? Or do you create everything
    from scratch?

In my latest app, there are public facing controllers, and there are
admin controllers tucked in a directory called “admin”. I created all
the public facing controllers and views first, from scratch, and then I
generated scaffolds for most of the admin controllers. If a controller
exists primarliy for CRUD over single type of data, then I will start
with scaffold, otherwise, from scratch.

  • are you using multiple controllers? Or do you put everything in one?

Definately multiple controllers. A controller for each different type
of interaction with the site.

  • do you use migrate?

Absolutely.

  • how do you use migrate? Do you call migrate your self or do you use
    the migration file that comes with the generation of the model?

If I am creating a new table for a new model, I will make the model
first and use the generated migration as a base. If I am editing an
exsiting table, obviously I have to create a migration stand alone.

  • when you use authentication, do you have one authentication controller
    that you share with multiple apps (if you have multiple apps)?

Hasn’t come up, yet.

  • do you keep scalability in mind when building an app? How?

Getting to work is more important than getting it work fast. Especially
when you know you wont be hitting performance bottle necks for at least
6 months after launch which is plenty of time optomize.

  • anything else that you can think of… :wink:

I try to stick as close the Rails “Golden Path” as I can. I find it
keeps me happy.

I am interested to see what the different approaches might be.

Thanx!!

Mischa

On Mon, Apr 24, 2006 at 10:14:09AM +0200, Mischa Peters wrote:
} I am doing some research on how people start with their Rails app.
} What design decisions are made and how is it build.

High-level requirements first, which get clarified and detailed
throughout
subsequent development. This is true even (particularly?) for my own,
personal projects; I write developer notes in the doc directory and keep
them up to date. Data model next, which shakes out a lot of the
ambiguities
in the requirements. This is half personal preference and half
unpleasant
experiences with other approaches. Thereafter…

} For example:
} - do you use scaffolding and go from there? Or do you create
everything
} from scratch?

I found scaffolding instructive when I was learning how to use Rails.
For
nearly any interesting application (i.e. that isn’t just a Web-based
FileMaker app) there is a many-to-many mapping between controllers and
models rather than the one-to-one mapping that scaffolding assumes.

Controllers are about functionality. The data model is there to support
the
desired functionality, but it is not, itself, functionality. The
important
thing here is that controllers sit on top of the data model, rather than
simply exposing it.

} - are you using multiple controllers? Or do you put everything in one?

For the same reasons that we don’t want one big main() function or one
big
object, we don’t want one big controller. The last four or five decades
of
programming have taught us to break problems down into smaller problems
and
solve them modularly. Rails does not change that wisdom.

} - do you use migrate?

Hell, no. I value my data integrity, and regardless of what DHH says I
will
damned well have integrity constraints expressed in and enforced by my
database. Unless and until migrating supports foreign key constraints,
unique constraints, and arbitrary check constraints I will be managing
my
database schema with SQL, thank you.

} - how do you use migrate? Do you call migrate your self or do you use
} the migration file that comes with the generation of the model?

N/A

} - when you use authentication, do you have one authentication
controller
} that you share with multiple apps (if you have multiple apps)?

In some cases, if apps are related enough that they should share
account/authentication then they should probably be a single app with
mostly independent controllers. When you start scaling to lots of
individual apps and it starts looking like a suite of apps with “single
sign-on” then it’s probably time to move to a centralized authentication
mechanism with an independent authentication application accessible to
the
individual apps via web services or something similar.

} - do you keep scalability in mind when building an app? How?

Sort of. The data model is a big part of it. If you can design a good
database schema in (or close to) one of the established normal forms,
you
have a good start. Keep an eye on how many data records you need to
accomplish any given task (read: controller action), and how many
different
tasks modify (reading is less of a concern) the same records. Some rules
of
thumb:

  • Store a bare minimum in the session hash. Particularly, do not store
    records, just ids.

  • Make it easy for the client to cache. This means reusing as much as
    possible various static resources such as images, JavaScript
    libraries,
    and stylesheets. Remember that anything you generate probably won’t be
    cached on the client, even if it’s cached in Rails.

  • Don’t send anything to the client you don’t have to. Anything you send
    probably has to be read from the database, and it definitely has to be
    rendered as ERB and sent over the wire.

  • Don’t send redundant data to the client. If you look at the JavaScript
    that RJS and the various AJAX helpers produce you will find that it is
    pretty redundant. If you find that you are using a lot of it on the
    same
    page, you might want to push the similar stuff into a JavaScript
    library
    (see the point about client caching) and write your own helpers that
    use
    it for your specific purposes.

  • Use Rails’ builtin caching (duh).

} - anything else that you can think of… :wink:

Security is important, and not something that one slaps on later. It’s
an
integral part of the system.

  • Never eval anything that came from the client.

  • Never create records directly from params (despite all the examples to
    the contrary).

  • Never use string substitution (e.g. “#{params[:foo]”) with data from
    the
    client, particularly in model find() calls.

  • Never rely on JavaScript for validation. It’s nice for the user, but
    always validate on the server.

  • Never assume that requests are coming from submissions from pages your
    app rendered.

Accessibility is important. (This is most relevant for the visually
impaired, but there are implications for certain kinds of physical
impairments as well.) It is also federally mandated for all governmental
websites (in the U.S.). One can also be sued for discrimination if a
site
is not accessible.

  • All image tags should have alternate text (i.e. img tags need a useful
    alt attribute). This also happens to be a standard requirement of
    modern
    HTML, even though nearly all graphical browsers will render img tags
    without alt attributes.

  • JavaScript should not be required to use your app. There are
    situations
    in which this requirement doesn’t make sense (e.g. your app’s central
    purpose has to do with graphical manipulation, etc.), but the vast
    majority of applications are text-based. There is nothing wrong with
    enhancing pages with JavaScript, just so long as they are still usable
    without it.

  • In case it isn’t obvious, AJAX is JavaScript so the previous point
    applies to it as well.

  • See WCAG 2 Overview | Web Accessibility Initiative (WAI) | W3C for more info.

Here’s the short overview of my development process, in order:

  • requirements (updated and maintained throughout development)

  • data model (schema and models, validation checks in both and
    scalability
    in mind)

  • functionality (controllers with security and scalability in mind)

  • views (with accessibility and scalability in mind)

I didn’t mention testing since I consider it part of the development
process. Use the framework for unit, functional, and integration tests
that
Rails provides throughout the development process; ideally, by the end
of
development the requirements and sets of tests will be nearly
identically
complete specifications of the system.

} I am interested to see what the different approaches might be.
} Thanx!!
} Mischa
–Greg

Hello Gregory !

2006/4/24, Gregory S. [email protected]:

  • Never create records directly from params (despite all the examples to
    the contrary).

  • Never use string substitution (e.g. “#{params[:foo]”) with data from the
    client, particularly in model find() calls.

I quite agree with not eval’ing and substituting, but creating records
from params ? What do you do then ? Remember that ActiveRecord::Base
escapes SQL meaningful characters, so this is not as big a security
risk as you make it seem, in my opinion.

But of course, challenge my perhaps misinformed opinion !

Have a nice day !

On Mon, Apr 24, 2006 at 01:40:45PM -0400, Francois B. wrote:
} Hello Gregory !
}
} 2006/4/24, Gregory S. [email protected]:
} > - Never create records directly from params (despite all the
examples to
} > the contrary).
} >
} > - Never use string substitution (e.g. “#{params[:foo]”) with data
from the
} > client, particularly in model find() calls.
}
} I quite agree with not eval’ing and substituting, but creating records
} from params ? What do you do then ? Remember that ActiveRecord::Base
} escapes SQL meaningful characters, so this is not as big a security
} risk as you make it seem, in my opinion.
}
} But of course, challenge my perhaps misinformed opinion !

I don’t mean you shouldn’t use specific params values in record
creation.
Something like Foo.new(params[:bar], params[:baz]) is fine, though you
should do some sanity checking. The problem is with Foo.new(params) (or
Foo.new(params[:foo] where :foo is a hash of nested values).

If you have a model that has columns that don’t get set until some later
date (e.g. subscription_date is null for unsubscribed members, a
specific
date for subscribed members) you can wind up with columns being set
automatically by a malicious user who adds inappropriate parameters to
the
request.

} Have a nice day !
} Fran??ois Beausoleil
–Greg

On Apr 24, 2006, at 10:59 AM, Gregory S. wrote:

} I quite agree with not eval’ing and substituting, but creating
records
} from params ? What do you do then ? Remember that
ActiveRecord::Base
} escapes SQL meaningful characters, so this is not as big a security
} risk as you make it seem, in my opinion.
}
} But of course, challenge my perhaps misinformed opinion !

I’m pretty sure this only happens if you use the placeholder
functionality:

Model.find(:all, :conditions => [‘column = ?’,params[:value]])

as opposed to:

Model.find(:all, :conditions => “column = #{params[:value]}”)

which I believe does invite SQL injection, so don’t do that (if I’m
correct!) :slight_smile:

specific
date for subscribed members) you can wind up with columns being set
automatically by a malicious user who adds inappropriate parameters
to the
request.

Form stuffing is the general term of this, and Rails can protect
against it
via:

attr_accessible
attr_protected


– Tom M.

On 4/24/06, Gregory S. [email protected] wrote:

} - do you use migrate?

Hell, no. I value my data integrity, and regardless of what DHH says I will
damned well have integrity constraints expressed in and enforced by my
database. Unless and until migrating supports foreign key constraints,
unique constraints, and arbitrary check constraints I will be managing my
database schema with SQL, thank you.

execute “MY SQL TO CREATE A CONSTRAINT”

Then you can still use migrations, which are extremely convenient.
fwiw, my development process for a model goes like

  1. Code tests and model without any constraints or AR validations
  2. Add in validations and tests for those validations
  3. Add constraints and make sure the tests still pass

Works for me.

Pat

Gregory,

Isn’t this mitigated by the use of attr_accessible and attr_protected?

Cheers,

Ed

On Apr 24, 2006, at 1:23 PM, Pat M. wrote:

managing my
database schema with SQL, thank you.

Do other apps manipulate the same DB?

If not, you’re wasting your time on this.

Don’t get angry, I used to feel the same way as you do.

But…then I started to think about it. The world is changing, and
perhaps
allowing several applications to manipulate the same DB is just not
the way
to go anymore.

One app per DB with applications integrating via web services is the
future.

Easy to write and maintain, easier to keep development moving quickly
(no
need to synchronize DB updates with multiple applications so long as the
web service interface doesn’t change!)

Not using migrations is such a loss. I understand that many people still
need to work with integration databases, but if you’re not one of those,
think it through before determining you’re certain that the previously
correct way to do it still is the correct way to do it.


– Tom M.

Mischa Peters wrote:

Hi All,

I am doing some research on how people start with their Rails app.
What design decisions are made and how is it build.

For example:

  • do you use scaffolding and go from there? Or do you create everything
    from scratch?

The scaffolding avoids some typing and potential spelling mistakes. So I
use it.

  • are you using multiple controllers? Or do you put everything in one?

Multiple of course. At the very least I seperate between admin and view.

  • do you use migrate?

Yes.

  • how do you use migrate? Do you call migrate your self or do you use
    the migration file that comes with the generation of the model?

For incremental changes I migrate myself. When I generate a model I use
the migration file. :slight_smile:

  • when you use authentication, do you have one authentication controller
    that you share with multiple apps (if you have multiple apps)?

I use the same controller, but different apps use it in different ways.

  • do you keep scalability in mind when building an app? How?

Not much in the terms of scalability, except for the basic logic of
programming for efficiency. I do everything Gregory mentioned for
security.

  • anything else that you can think of… :wink:

I am interested to see what the different approaches might be.

I suspect you will find that many Rails developers use the same basic
approach.

-Adam

But…then I started to think about it. The world is changing, and perhaps
allowing several applications to manipulate the same DB is just not the way
to go anymore.

For small, self-contained web applications, perhaps. For a set of
rails applications which interact via WS, certainly. For many, many
applications out there, particularly in business applications where
nothing starts from scratch? Probably not.

One app per DB with applications integrating via web services is the
future.

Generally people who try and tell me what “the future” is turn out to
be wrong. The few people who actually know tend not to realize or
announce it.

On Mon, Apr 24, 2006 at 11:27:02AM -0700, Tom M. wrote:
} On Apr 24, 2006, at 10:59 AM, Gregory S. wrote:
}
} >} I quite agree with not eval’ing and substituting, but creating
} >records
} >} from params ? What do you do then ? Remember that
} >ActiveRecord::Base
} >} escapes SQL meaningful characters, so this is not as big a security
} >} risk as you make it seem, in my opinion.
[…]
} Model.find(:all, :conditions => “column = #{params[:value]}”)
}
} which I believe does invite SQL injection, so don’t do that (if I’m
} correct!) :slight_smile:

Yes, that’s the substitution I was referring to.

} >I don’t mean you shouldn’t use specific params values in record
} >creation.
} >Something like Foo.new(params[:bar], params[:baz]) is fine, though
you
} >should do some sanity checking. The problem is with Foo.new(params)
} >(or
} >Foo.new(params[:foo] where :foo is a hash of nested values).
} >
} >If you have a model that has columns that don’t get set until some
} >later
} >date (e.g. subscription_date is null for unsubscribed members, a
} >specific
} >date for subscribed members) you can wind up with columns being set
} >automatically by a malicious user who adds inappropriate parameters
} >to the
} >request.
}
} Form stuffing is the general term of this, and Rails can protect
} against it
} via:
}
} attr_accessible
} attr_protected

I had forgotten about that. Okay, change that rule of thumb to
“Rigorously
define attr_accessible and attr_protected for all models.”

} – Tom M.
–Greg

I find that although I have a controller for each model, the methods for
the
controllers keep growing and growing. How do you keep everything
organized
and easy to work with in a single controller?