I''m a newbie to rails, and really to the whole DRY and MVC thing as well, except where I accidentally fell into things doing it my own way in the past. I''ve got a fairly complex DB structure I want to create an interface for using Rails. Getting simple tables to display, edit, save, not too much problem there. But where I''m having trouble is figuring out where to place some code I have had to write to get info from multiple tables into one view. For example, for a list view of "projects" (main table), I have this code in the list.rhtml: <% odd_or_even = 0 for project in @projects @project_translations = ProjectTranslation.find(project.id) @business_unit = BusinessUnit.find(project.business_unit_id) @requestor = User.find(project.requester_user_id) @vendor_projects = VendorProject.find_by_project_translation_id(@project_translations.id) @vendor = Vendor.find(@vendor_projects.vendor_id) odd_or_even = 1 - odd_or_even %> This code I would probably need in other views as well. For the list that customers see, for individual record views, etc. The question is: where *should* I be putting that code? In the controller? In the model? and how, exactly? I have another question semi-related to this about how ids work and why I have to do find all the time, but I''ll post that in a different thread. Micah -- Posted via http://www.ruby-forum.com/.
On Feb 25, 2006, at 3:11 PM, Micah Bly wrote:> I''ve got a fairly complex DB structure I want to create an > interface for > using Rails. Getting simple tables to display, edit, save, not too > much > problem there. But where I''m having trouble is figuring out where to > place some code I have had to write to get info from multiple tables > into one view. For example, for a list view of "projects" (main > table), > I have this code in the list.rhtml: > > <% > odd_or_even = 0 > for project in @projects > @project_translations = ProjectTranslation.find(project.id) > @business_unit = BusinessUnit.find(project.business_unit_id) > @requestor = User.find(project.requester_user_id) > @vendor_projects = VendorProject.find_by_project_translation_id > (@project_translations.id) > @vendor = Vendor.find(@vendor_projects.vendor_id) > odd_or_even = 1 - odd_or_even > %> > > This code I would probably need in other views as well. For the list > that customers see, for individual record views, etc. The question is: > where *should* I be putting that code? In the controller? In the > model? > and how, exactly?You''re not using associations, and you''re not following naming conventions. Once you get everything together, you''ll be able to say things like: project.project_tranlations project.business_unit project.requestor project.project_tranlations.vendor_projects project.project_tranlations.vendor_projects.vendor -- -- Tom Mornini
Micah, 1/ replace "odd_or_even" by TextHelper.cycle 2/ It looks like your model could be enriched, to have Rails do the hard work or finding related records. In other words, remove all the "find"s in your views by adding "has_one", "has_many" and "belongs_to" in your models. (Tip: when you see "belongs_to :x", think "references :x", or "points_to :x") Example: if you add class Project < ActiveRecord::Base has_one :translation end class Translation < ActiveRecord::Base belongs_to :project end this code @project_translation = ProjectTranslation.find(project.id) would become @project_translation = project.translation 3/ I''m puzzled by code like this @project_translations = ProjectTranslation.find(project.id) - Why the plural on the left side, whey you''re obviously fetching 1 record? - How come the project and the translation share the same id? Normally, you don''t handle ids explicitely (? is this a legacy project/db)? Alain
Tom Mornini wrote:> You''re not using associations, and you''re not following naming > conventions. > > Once you get everything together, you''ll be able to say things like: > > project.project_tranlations > project.business_unit > project.requestor > project.project_tranlations.vendor_projects > project.project_tranlations.vendor_projects.vendorWell, that''s what I thought I should be able to, it''s what I was going to make the other post about. I *think* I''ve followed the db naming conventions pretty closely... Everything has an ''id'' field that''s an int, foreign key fields are named with the table name + "_id". I also set up in the models, all the has_one, has_many, belongs_to, etc. things. I should have said that I did try the above reference style, but got error messages. I''ll revert a few versions and check out exactly what those errors were. Micah -- Posted via http://www.ruby-forum.com/.
Alain Ravet wrote:> Micah, > > 1/ replace "odd_or_even" by TextHelper.cycle >Sadly, I don''t even know what that is. I''ll do some digging, thanks for the hint!> 2/ It looks like your model could be enriched, to have Rails do the hard > work or finding related records. In other words, remove all the "find"s > in your views by adding "has_one", "has_many" and "belongs_to" in your > models. > (Tip: when you see "belongs_to :x", think "references :x", or "points_to > :x") > > Example: if you add > > class Project < ActiveRecord::Base > has_one :translation > end > class Translation < ActiveRecord::Base > belongs_to :project > end > > this code > @project_translation = ProjectTranslation.find(project.id) > > would become > @project_translation = project.translationhmm. That''s what *I* thought it should be doing too... (see above reply).> 3/ I''m puzzled by code like this > @project_translations = ProjectTranslation.find(project.id) > > - Why the plural on the left side, whey you''re obviously fetching 1 > record?Well, this isn''t complete yet. The reason is that there can be 1+ project_translations for any project. Or if you named it differently, a "project" has one source language, and n number of target languages, each of which could be done by a separate vendor, have separate leveraging, cost, deadlines, etc.> - How come the project and the translation share the same id? Normally, > you don''t handle ids explicitely (? is this a legacy project/db)?This is a test set of data (a migration from existing data source), and each project in this test set only has one target language, so when the insert happened, the projects and project_translations ids ended up being 1:1. That won''t be the case in production. I think I''ll revert a few versions back and see what error messages I was getting and try to sort out what''s going wrong with my models. I was getting frustrated and wanted to make it show me SOMETHING. Thanks help, Micah -- Posted via http://www.ruby-forum.com/.
On 2/25/06, Micah Bly <mbly@inter-l.com> wrote:> Alain Ravet wrote: > > Micah, > > > > 1/ replace "odd_or_even" by TextHelper.cycle > > > > Sadly, I don''t even know what that is. I''ll do some digging, thanks for > the hint!hint #2 :) http://api.rubyonrails.com/classes/ActionView/Helpers/TextHelper.html#M000430
Pat Maddox wrote:> hint #2 :) > http://api.rubyonrails.com/classes/ActionView/Helpers/TextHelper.html#M000430Alain and Pat, Thanks for that one, it works like a charm! --- Ok, I did some reverting, and these are the types of errors I get: undefined method `vendor_projects'' for ProjectTranslation:Class 32: vendor_projects = project.project_translations.vendor_projects and if I go back to manually finding for vendor_projects there, just to get past that, I get this nil error from the vendor_projects.vendor_id: You have a nil object when you didn''t expect it! The error occured while evaluating nil.vendor_id 35: vendor = Vendor.find(vendor_projects.vendor_id) If I did everything the way I *think* I should be doing it, I''d have something like this: for project in @projects project_translations = project.project_translations bu_name = project.business_unit.name requester = User.find(project.requester_user_id) # ^ still haven''t solved this one because i don''t use "user_id" as the field name here (I have 3 users referenced in this table) vendor_projects = project.project_translations.vendor_projects vendor = vendor_projects.vendor But that doesn''t work for me yet. If you''re still reading, here''s how I have the Classes set up: class Project < ActiveRecord::Base has_many :project_translations has_many :users has_one :language class ProjectTranslation < ActiveRecord::Base belongs_to :project has_one :language has_many :vendor_projects class User < ActiveRecord::Base belongs_to :project belongs_to :project_translation class Vendor < ActiveRecord::Base belongs_to :vendor_projects class VendorProject < ActiveRecord::Base belongs_to :project_translations has_many :vendor_invoices has_many :vendor_scope_changes has_one :vendor I''m not sure I have the Project>has_many :users thing right... it''s really 3 relationships, but all are has_one relationships. (3 fields, can only be 1 users for each of them). -- Posted via http://www.ruby-forum.com/.
Just wanted to thank everyone for the suggestions. I did get the above mess cleaned up and working in what I hope is a more Railed manner. In my view, I now have just this: for project in @projects project_hash = project.list_hash list_hash is a method in the Project class that gets the data I need from the various tables, does some calculations, sum(), avg(), etc, and returns it in a hash that the view can use, as here: <td class="grid"><%= number_to_currency(project_hash["vendor_estimate"]) %></td> I made an effort to keep anything that formatted a number, out of the Project class, and into the view helpers. I believe that''s the right Rails thing to do. Except for 3 connection.select_value() calls to get avg and sum, there''s no more sql in the method at all, no find_by... Micah -- Posted via http://www.ruby-forum.com/.