Forum: Ruby on Rails Design Decisions

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
84e21933eac0d84dc6b37efa36855361?d=identicon&s=25 Mischa Peters (j0rdan)
on 2006-04-24 10:14
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... ;)

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

Thanx!!

Mischa
D0cd6b10e01bacb976b3b815a9c660bc?d=identicon&s=25 Alex Wayne (Guest)
on 2006-04-24 10:57
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... ;)

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
675475d0b65710be6d992eb5eb2c61c2?d=identicon&s=25 Gregory Seidman (Guest)
on 2006-04-24 14:59
(Received via mailing list)
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... ;)

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 http://www.w3.org/WAI/intro/wcag.php 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
3dd4b52a0946bd698b1d1635a46ea3a3?d=identicon&s=25 François Beausoleil (fbeausoleil)
on 2006-04-24 19:42
(Received via mailing list)
Hello Gregory !

2006/4/24, Gregory Seidman <gsslist+ror@anthropohedron.net>:
> - 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 !
675475d0b65710be6d992eb5eb2c61c2?d=identicon&s=25 Gregory Seidman (Guest)
on 2006-04-24 20:00
(Received via mailing list)
On Mon, Apr 24, 2006 at 01:40:45PM -0400, Francois Beausoleil wrote:
} Hello Gregory !
}
} 2006/4/24, Gregory Seidman <gsslist+ror@anthropohedron.net>:
} > - 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
41e1579600683eed6c00af9a425268e6?d=identicon&s=25 Edward Frederick (Guest)
on 2006-04-24 20:22
(Received via mailing list)
Gregory,

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

Cheers,

Ed
59de94a56fd2c198f33d9515d1c05961?d=identicon&s=25 Tom Mornini (Guest)
on 2006-04-24 20:28
(Received via mailing list)
On Apr 24, 2006, at 10:59 AM, Gregory Seidman 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!) :-)

> 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 Mornini
42172acdf3c6046f84d644cb0b94642c?d=identicon&s=25 Pat Maddox (pergesu)
on 2006-04-24 22:26
(Received via mailing list)
On 4/24/06, Gregory Seidman <gsslist+ror@anthropohedron.net> 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
59de94a56fd2c198f33d9515d1c05961?d=identicon&s=25 Tom Mornini (Guest)
on 2006-04-24 22:44
(Received via mailing list)
On Apr 24, 2006, at 1:23 PM, Pat Maddox 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 Mornini
6ec1e89eef5ce09fbfa56be5b6dd17b5?d=identicon&s=25 Adam Bloom (admanb)
on 2006-04-24 22:54
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. :)

> - 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... ;)
>
> 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
E146c40bd510d1f1e455723485159670?d=identicon&s=25 Brian L. (Guest)
on 2006-04-25 00:27
(Received via mailing list)
> 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.
61b70c2f195b0e669a8e25000148d9dd?d=identicon&s=25 Eden Brandeis (Guest)
on 2006-04-25 07:18
(Received via mailing list)
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?
675475d0b65710be6d992eb5eb2c61c2?d=identicon&s=25 Gregory Seidman (Guest)
on 2006-04-25 13:29
(Received via mailing list)
On Mon, Apr 24, 2006 at 11:27:02AM -0700, Tom Mornini wrote:
} On Apr 24, 2006, at 10:59 AM, Gregory Seidman 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!) :-)

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 Mornini
--Greg
This topic is locked and can not be replied to.