Forum: Ruby on Rails Newb question:

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.
(Guest)
on 2007-07-24 08:49
(Received via mailing list)
Hi all,

Another newb online... trying belongs_to and has_one constructs for
the first time.

table Location defined as:
  nickname, street, city, ... , contact_id

the model includes "belongs_to :contact"

table Contact defined as:
  name, title, ... , location_id

the model includes "has_one :location"

When I build a list_contacts view, I assume
h(contact.location.nickname) will make the connection. However Rails
returns nil for contact.location. (Verified the linkage is present,
thanks to script/console.) Seems like I'm missing something very
simple, but I'm stumped. Ideas?

Best,
Brian
Austin, Texas
Jean N. (Guest)
on 2007-07-24 09:02
removed_email_address@domain.invalid wrote:
>
> When I build a list_contacts view, I assume
> h(contact.location.nickname) will make the connection. However Rails
> returns nil for contact.location. (Verified the linkage is present,
> thanks to script/console.) Seems like I'm missing something very
> simple, but I'm stumped. Ideas?
>
> Best,
> Brian
> Austin, Texas

Can you post your controller code for list_contacts? If you have
'dereferenced' your scaffold code also make sure you have an instance
variable that holds the information for your contact in the controller
or else your view wont have anything to display.

Also, maybe you just left this out, but contact.location is nil but is
just contact nil also?

Lastly, your table should be named w/ pluralizes names.

Ex: 'create table Contacts ...' and 'create table Locations...' not the
singular version you posted in your original mail. Remember models are
singular and the db tables they are tied to are pluralized.

I'll assume that you posted just pseudo code but I had to mention it
just in case.

Hope this, at the least, kicks off a direction for a solution to your
problem.
(Guest)
on 2007-07-24 09:17
(Received via mailing list)
Hello Jean,
I appreciate the reply. As requested:

controller:
========
def list_contacts
  @contact_pages = Paginator.new self, Contact.count, 60, params[:page]
  @contacts = Contact.find :all, :order => params['order'] ||
'lastname',
        :limit => @contact_pages.items_per_page,
        :offset => @contact_pages.current.offset
end

view:
=====
... various html ....
<% for contact in @contacts
     # location = Location.find(contact.location_id)
     %>
    <tr>
      <td><%= link_to h(contact.lastname+','+contact.firstname), :action
=> 'edit_contact', :id => contact.id %></td>
      <td><%=         h(contact.title) %></td>
      <td><%=         h(contact.email1) %></td>
      <td><%=         h(contact.phone1) %></td>
      <td><%=   h(contact.location.nickname) %></td>
        ... various html ...
<% end %>

# Notice the "Location.find(contact.location_id) ... this works...

Tks again...
Brian

On Jul 24, 12:02 am, Jean N. <removed_email_address@domain.invalid>
Chris (Guest)
on 2007-07-24 11:27
(Received via mailing list)
You have 2 columns locations.contact_id and contacts.location_id. Of
these, only locations.contact_id is used by the associations you have
defined.

class Location < AR::Base
  # This will lookup locations.contact_id to find the association
  belongs_to :contact
end

class Contact < AR::Base
  # This will also lookup locations.contact_id to find the association
  has_one :location
end

Make sure that locations.contact_id is populated in your DB, and that
you haven't mistakenly populated contacts.location_id instead.

BTW, if you need to query a list of contacts, think about the
performance of using associations.

Option 1:
contacts = Contact.find(:all)
# Each call to c.location triggers a DB query to delay load the
location for that contact
contacts.each { |c| c.location.nickname }

Option 2:
contacts = Contact.find(:all, :includes => [:location])
# All locations are loaded upfront, so there is only ever 1 DB call
contacts.each { |c| c.location.nickname }

Cheers,
Chris

On Jul 24, 3:02 pm, Jean N. <removed_email_address@domain.invalid>
Jean N. (Guest)
on 2007-07-24 19:55
Chris wrote:
>
> Option 1:
> contacts = Contact.find(:all)
> # Each call to c.location triggers a DB query to delay load the
> location for that contact
> contacts.each { |c| c.location.nickname }
>
> Option 2:
> contacts = Contact.find(:all, :includes => [:location])
> # All locations are loaded upfront, so there is only ever 1 DB call
> contacts.each { |c| c.location.nickname }
>
> Cheers,
> Chris
>
> On Jul 24, 3:02 pm, Jean N. <removed_email_address@domain.invalid>

Adding to this, remove any DB calls in your view. this breaks the model
/ view/ controller architecture as you're having a view interact
directly WITH the Database.

Encapsulate ALL 'business logic / use cases' and database access in your
controller and let your view determine how all the data 'sent' to it is
displayed. Even using a loop and querying the db for your location,
although a minor infraction, is considered logic and not display.
This topic is locked and can not be replied to.