Forum: Ruby on Rails Help with DRY: too much code in my view

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.
Micah B. (Guest)
on 2006-02-26 01:11
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
Tom M. (Guest)
on 2006-02-26 01:46
(Received via mailing list)
On Feb 25, 2006, at 3:11 PM, Micah B. wrote:

> 	<%
>
> 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 M.
Alain R. (Guest)
on 2006-02-26 01:52
(Received via mailing list)
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
Micah B. (Guest)
on 2006-02-26 04:28
Tom M. 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.vendor

Well, 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
Micah B. (Guest)
on 2006-02-26 04:35
Alain R. 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.translation

hmm. 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
Pat M. (Guest)
on 2006-02-26 04:39
(Received via mailing list)
On 2/25/06, Micah B. <removed_email_address@domain.invalid> wrote:
> Alain R. 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/Help...
Micah B. (Guest)
on 2006-02-26 05:59
Pat M. wrote:

> hint #2 :)
> http://api.rubyonrails.com/classes/ActionView/Help...

Alain 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).
Micah B. (Guest)
on 2006-02-26 22:13
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
This topic is locked and can not be replied to.