1st: I am a newbie to Rails & to pure OO. Q: I want to use rails for creating a "master-detail" form. page layout will allow users to type in an "expense report header" and as many "expense report lines" as they need to. I understand how to wrap the final submit action using "transaction" to ensure the inserts to the database happen within the same commit cycle. But how should I model the "expense report" (which consists of 1 expense report header and N expense report lines) in rails? should there be an MVC for the "expense report"? i admit i get a little lost in rails generated MVC once i am dealing with master-detail. for an app requiring action on only a single table at a time, i''m golden. p.s. Thank you! -- Posted via http://www.ruby-forum.com/.
On 12/20/05, Dave Stephens <drstephe-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> 1st: I am a newbie to Rails & to pure OO. > Q: I want to use rails for creating a "master-detail" form. page layout > will allow users to type in an "expense report header" and as many > "expense report lines" as they need to. I understand how to wrap the > final submit action using "transaction" to ensure the inserts to the > database happen within the same commit cycle. But how should I model the > "expense report" (which consists of 1 expense report header and N > expense report lines) in rails? should there be an MVC for the "expense > report"? i admit i get a little lost in rails generated MVC once i am > dealing with master-detail. for an app requiring action on only a single > table at a time, i''m golden.table: expense_reports id other_stuff table: expense_items id expense_report_id other_stuff ExpenseReport < ActiveRecord::Base has_many :expense_items end ExpenseItem < ActiveRecord::Base belongs_to :expense_report end Put the View junk for Expense Items in a partial, and render it on a collection in some action. In the controller, have the form submit to, let''s say, create_report. def create_report report = ExpenseReport.new(params[:expense_report]) # Only one of these params[:expense_item].each do |key, val| report.expense_items << ExpenseItem.new(val) end # report.expense_items is now a collection of all the items. # You still need to check everything with object.valid?, and decide where to send the user. # When you''ve verified everything, you can call report.save, and everything will be saved. end
p.s. I am willing to write a nice, well documented article on how to do a master-detail form on rails if someone is kind enough to show me how!! -- Posted via http://www.ruby-forum.com/.
I have a related question: Lets suppose that we have the code below:>In the controller, have the form submit to, let''s say, create_report. > >def create_report > report = ExpenseReport.new(params[:expense_report]) # Only one of these > params[:expense_item].each do |key, val| > report.expense_items << ExpenseItem.new(val) > end > # report.expense_items is now a collection of all the items. > # You still need to check everything with object.valid?, and decide >where to send the user. > # When you''ve verified everything, you can call report.save, and >everything will be saved. >end > >And lets suppose that we want to revalidate some of the ExpenseItems. eg Consider an accounting app, we might have a nice UI which lets people type in an approx name for each item and then we popup a number of search boxes which tries to find the exact item name from the DB, correcting spelling etc and making sure each entry is standardised (means you can type in a few letters for each product for speed and then pick the exact items from a list on the next screen) How can we stash all this data once we have recovered it while we go to the search screen to correct each item. We will then redirect back to the main create_report page before saving. Does this make sense? Picture some invoicing app for a small business which for speed lets you type in the details for each line, rather than picking from some huge list, but then we need to make sure that the lines are all standardised and match the descriptions in the DB, so one by one we offer a search box to let the user choose the nearest item. How to code this in Rails? (It''s the stashing of the params that I am unsure about) Thanks Ed W
On 12/20/05, Ed W <lists-XJavvHiACVh0ubjbjo6WXg@public.gmane.org> wrote:> I have a related question: > > Lets suppose that we have the code below: > > >In the controller, have the form submit to, let''s say, create_report. > > > >def create_report > > report = ExpenseReport.new(params[:expense_report]) # Only one of these > > params[:expense_item].each do |key, val| > > report.expense_items << ExpenseItem.new(val) > > end > > # report.expense_items is now a collection of all the items. > > # You still need to check everything with object.valid?, and decide > >where to send the user. > > # When you''ve verified everything, you can call report.save, and > >everything will be saved. > >end > > > > > > And lets suppose that we want to revalidate some of the ExpenseItems. > eg Consider an accounting app, we might have a nice UI which lets people > type in an approx name for each item and then we popup a number of > search boxes which tries to find the exact item name from the DB, > correcting spelling etc and making sure each entry is standardised > (means you can type in a few letters for each product for speed and then > pick the exact items from a list on the next screen) > > How can we stash all this data once we have recovered it while we go to > the search screen to correct each item. We will then redirect back to > the main create_report page before saving. > > Does this make sense? Picture some invoicing app for a small business > which for speed lets you type in the details for each line, rather than > picking from some huge list, but then we need to make sure that the > lines are all standardised and match the descriptions in the DB, so one > by one we offer a search box to let the user choose the nearest item. > How to code this in Rails? (It''s the stashing of the params that I am > unsure about) >Yep, I do something similar in one system, with Ajax searches for individual demographics (name, date of birth, etc, etc). I decided to just stuff an array of the relevant objects into the session, ordered the same way they were on the page. session[:current_blahs] = [] params[:blah].each etc etc session[:current_blahs] << blah end That let me use the helpers that support the :index => option, and preserve the order of things during edits and whatnot. Things are simplified greatly if you can make the users click on the items they want to manipulate. Unfortunately in my case, I had to allow the users to, say, add 5 new items to the bottom of the list all at once, which made it ''fun.'' If each item has a ''Remove'' button, and there''s an ''Add'' button that they have to click 5 times to add 5 more entries, you''re pretty much home free. --Wilson.
Wilson Bilkovich wrote: ...> # When you''ve verified everything, you can call report.save, and > everything will be saved. > endthanks wilson, i will give this a go! -- Posted via http://www.ruby-forum.com/.
On Tue, 20 Dec 2005 14:01:11 -0500 Wilson Bilkovich <wilsonb-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> On 12/20/05, Dave Stephens <drstephe-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > 1st: I am a newbie to Rails & to pure OO. > > Q: I want to use rails for creating a "master-detail" form. page layout > > will allow users to type in an "expense report header" and as many > > "expense report lines" as they need to. I understand how to wrap the > > final submit action using "transaction" to ensure the inserts to the > > database happen within the same commit cycle. But how should I model the > > "expense report" (which consists of 1 expense report header and N > > expense report lines) in rails? should there be an MVC for the "expense > > report"? i admit i get a little lost in rails generated MVC once i am > > dealing with master-detail. for an app requiring action on only a single > > table at a time, i''m golden. > > table: expense_reports > id > other_stuff > > table: expense_items > id > expense_report_id > other_stuff > > ExpenseReport < ActiveRecord::Base > has_many :expense_items > end > > ExpenseItem < ActiveRecord::Base > belongs_to :expense_report > end > > Put the View junk for Expense Items in a partial, and render it on a > collection in some action. > > In the controller, have the form submit to, let''s say, create_report. > > def create_report > report = ExpenseReport.new(params[:expense_report]) # Only one of these > params[:expense_item].each do |key, val| > report.expense_items << ExpenseItem.new(val) > end > # report.expense_items is now a collection of all the items. > # You still need to check everything with object.valid?, and decide > where to send the user. > # When you''ve verified everything, you can call report.save, and > everything will be saved. > endHi, this discussion reminds me of another related problem I have. I''ve already developped master-detail type form like Dave detailed elaborately. To create a new master-detail ( like an invoice ) is ok, but how about edit/update an invoice which has already recorded in the tables. there can be collision possibilities that two or more ppl might edit the details of the same master-detail invoice and result in some inconsitencies. creating/updating of master-detail type data is a kind of long transaction compared to that of single master table, so risks are higher. I know Web/DB app cannot have a [Perfect] transaction locking ''cause there is no ''active'' session though, is there any workaround to minimize/avoid such an inconsistency? So far I don''t develop edit feature to master-detail type transaction, but I realize soon the oprator ladies will claim me that why they can''t be updated. Thanks in advance, -- Hiroshi Takagi <gollum-u1eKKkw+WM0gE89CWYshPg@public.gmane.org>
There is where optimistic locking comes in handy. Check out: http://api.rubyonrails.com/classes/ActiveRecord/Locking.html On 12/20/05, Hiroshi Takagi <gollum-u1eKKkw+WM0gE89CWYshPg@public.gmane.org> wrote:> Hi, > > this discussion reminds me of another related problem I have. > I''ve already developped master-detail type form like Dave detailed > elaborately. To create a new master-detail ( like an invoice ) is ok, > but how about edit/update an invoice which has already recorded in the > tables. > there can be collision possibilities that two or more ppl might edit the > details of the same master-detail invoice and result in some > inconsitencies. > creating/updating of master-detail type data is a kind of long > transaction compared to that of single master table, so risks are higher. > > I know Web/DB app cannot have a [Perfect] transaction locking ''cause > there is no ''active'' session though, is there any workaround to > minimize/avoid such an inconsistency? > > So far I don''t develop edit feature to master-detail type transaction, > but I realize soon the oprator ladies will claim me that why they can''t > be updated. > > Thanks in advance,
On Tue, 20 Dec 2005 20:18:41 -0600 Cuong Tran <cuong.tran-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> There is where optimistic locking comes in handy. Check out: > > http://api.rubyonrails.com/classes/ActiveRecord/Locking.htmlThank you, Cuong! its a great help to me. All what I have to do is add a column named lock_version and rescue ActiveRecord::StaleObjectError with some Transaction. Thanks again! -- Hiroshi Takagi <gollum-u1eKKkw+WM0gE89CWYshPg@public.gmane.org>
Hi>Yep, I do something similar in one system, with Ajax searches for >individual demographics (name, date of birth, etc, etc). I decided to >just stuff an array of the relevant objects into the session, ordered >the same way they were on the page. >session[:current_blahs] = [] >params[:blah].each etc etc > session[:current_blahs] << blah >end > >I can see multiple ways it might be tackled using the session, but doesn''t this have problems with a single user logged into the app multiple times through different browser windows? I''m not entirely sure how sessions work, but I thought that you ended up sharing a session between multiple browser windows under some circumstances? Compare with the approach of finding a way to serialise the data and shove it in some hidden fields on the next view and grab it out again later...? (Trivial way to do this might be to have two form partials, one that you use for create and edit with all the fields visible, and another where the fields are all hidden which is used to add-on to the next form in order to port the fields forward easily. Does the second approach have any hidden problems compared with the session, and what problems will the session approach have with a user and multiple windows? Thanks Ed W
On 12/21/05, Ed W <lists-XJavvHiACVh0ubjbjo6WXg@public.gmane.org> wrote:> Hi > > >Yep, I do something similar in one system, with Ajax searches for > >individual demographics (name, date of birth, etc, etc). I decided to > >just stuff an array of the relevant objects into the session, ordered > >the same way they were on the page. > >session[:current_blahs] = [] > >params[:blah].each etc etc > > session[:current_blahs] << blah > >end > > > > > > I can see multiple ways it might be tackled using the session, but > doesn''t this have problems with a single user logged into the app > multiple times through different browser windows? I''m not entirely sure > how sessions work, but I thought that you ended up sharing a session > between multiple browser windows under some circumstances? > > Compare with the approach of finding a way to serialise the data and > shove it in some hidden fields on the next view and grab it out again > later...? (Trivial way to do this might be to have two form partials, > one that you use for create and edit with all the fields visible, and > another where the fields are all hidden which is used to add-on to the > next form in order to port the fields forward easily. > > Does the second approach have any hidden problems compared with the > session, and what problems will the session approach have with a user > and multiple windows? >Hrm. That''s very true, and luckily I haven''t run into that yet. Another approach might be to store a hash in the session that uses the primary keys of your domain object as the key. If you can guarantee that the user isn''t editing one "expense report" in two different windows, that would work. Interesting. I''ll need to think about this some more.
Hi , I tried the same Expense report problem in rails .The code is Controller class ExpensereportController < ApplicationController def index end def create_report report = ExpenseReport.new(params[:expense_report]) params[:expense_item].each do |key, val| report.expense_items << ExpenseItem.new(val) end report.save end def add_new_item end end View is <html> <head> <title>Expsense Report</title> </head> <body> <form action="/ajax/save_items" method="post"> <ul id="my_list"> <input type="text" id="expense_report_name" name="expense_report[name]" > <%= render(:partial => ''expense_items'', :collection => report.expense_items ) %> </ul> <%= submit_tag ''Update'' %> </form> </body> </html> Partial is <% @expense_item = expense_items %> <%= text_field ''expense_item'', ''notes'', ''index'' => 1 %> <br> <%= text_field ''expense_item'', ''notes'', ''index'' => 2 %><br> But I am getting the following error :: LoadError in <controller not set>#<action not set> Already loaded file ''./script/../config/../app/controllers/expensereport.rb'' but ''Expensereport'' was not set, perhaps you need to rename ''./script/../config/../app/controllers/expensereport.rb''? RAILS_ROOT: ./script/../config/.. Please let me know whats the issue here. Bye , Rathish -- Posted via http://www.ruby-forum.com/.
In create_report, try calling it: @expense_report instead of ''report''. It needs to be an instance variable, and the name of your text field is expense_report, not report. You will need to update this name in the render(:partial) call, as well. I''m not sure if this is part of the problem, but try naming your controller ExpenseReportController, rather than ExpensereportController. Finally, in the partial form, ''index'' should be the same for every loop through the partial. Doing this:> <%= text_field ''expense_item'', ''notes'', ''index'' => 1 %> <br> > <%= text_field ''expense_item'', ''notes'', ''index'' => 2 %><br>..will create a pair of items with index ''1'' and ''2'' for every entry in the collection you pass to render(:partial). Unless that''s what you want, you should change those to be variables. --Wilson. On 12/22/05, Naroor Rathish <hi_naroor-/E1597aS9LQAvxtiuMwx3w@public.gmane.org> wrote:> Hi , > I tried the same Expense report problem in rails .The code is > Controller > > class ExpensereportController < ApplicationController > > def index > > end > def create_report > report = ExpenseReport.new(params[:expense_report]) > params[:expense_item].each do |key, val| > report.expense_items << ExpenseItem.new(val) > end > report.save > end > > > def add_new_item > > end > end > > View is > <html> > <head> > <title>Expsense Report</title> > </head> > <body> > > <form action="/ajax/save_items" method="post"> > <ul id="my_list"> > <input type="text" id="expense_report_name" > name="expense_report[name]" > > > <%= render(:partial => ''expense_items'', :collection => > report.expense_items ) %> > > </ul> > <%= submit_tag ''Update'' %> > </form> > </body> > </html> > > Partial is > > <% @expense_item = expense_items %> > <%= text_field ''expense_item'', ''notes'', ''index'' => 1 %> <br> > <%= text_field ''expense_item'', ''notes'', ''index'' => 2 %><br> > > But I am getting the following error :: > > LoadError in <controller not set>#<action not set> > Already loaded file > ''./script/../config/../app/controllers/expensereport.rb'' but > ''Expensereport'' was not set, perhaps you need to rename > ''./script/../config/../app/controllers/expensereport.rb''? > RAILS_ROOT: ./script/../config/.. > > Please let me know whats the issue here. > > Bye , > Rathish > > -- > Posted via http://www.ruby-forum.com/. > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails >