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 -- Posted via http://www.ruby-forum.com/.
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-- Posted via http://www.ruby-forum.com/.
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
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 ! -- Fran?ois Beausoleil http://blog.teksol.info/
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
Gregory, Isn''t this mitigated by the use of attr_accessible and attr_protected? Cheers, Ed On 4/24/06, Gregory Seidman <gsslist+ror@anthropohedron.net> wrote:> 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 > > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >
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!) :-)> 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 -- -- Tom Mornini
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
On Apr 24, 2006, at 1:23 PM, Pat Maddox wrote:> 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.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
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 -- Posted via http://www.ruby-forum.com/.
> 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.
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? On 4/24/06, Gregory Seidman <gsslist+ror@anthropohedron.net> wrote:> > 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 > > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >-------------- next part -------------- An HTML attachment was scrubbed... URL: http://wrath.rubyonrails.org/pipermail/rails/attachments/20060425/9b5c69ae/attachment-0001.html
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