Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nested associations, how to prepare variables for views, rails

Running Rails 3.1.3...

I'll use a simple example of nested associations (not sure if this is correct term). Basically I'm modelling databases - each database has its own tables and each table has its own columns:

class Database < ActiveRecord::Base
  has_many :tables
end

class Table < ActiveRecord::Base
  belongs_to :database
  has_many :columns
end

class Column < ActiveRecord::Base
  belongs_to :table
end

My question is, say I want to display a database's tables and columns in a view, what would be a good way of bundling this data before passing it to the view. Basically, what would my controller and view look like?

I've come up with the following, but I would be surprised if there is not a much better way of doing this:

My controller:

class DatabasesController < ApplicationController
  def show
    @database = Database.find_by_id(params[:id])
    @tables = @database.tables
    @columns = @database.tables.columns
  end
end

My view:

Database: <%= @database.database_name %><br />
<% @tables.each do |table| %>
  Table: <%= table.table_name %><br />
  <% table.columns.each do |column| %>
    Column: <%= column.column_name %><br />
  <% end %>
<% end %>

I've also played around with using this in the controller:

@database = Database.where(:id => params[:id]).includes(:tables => [:columns])

However trying to access the table and column names from @database has driven me mad.


UPDATE:

Typically, I have spent many hours trying to figure this out and shortly after I post here, I think I get it. Thanks for the suggestion miked - this worked for me. Also, if I amend my own method by using the first! method it works as follows:

Controller:

def show
  @database = Database.where(:id => params[:id]).includes(:tables => [:columns]).first!
end

View:

Database: <%= @database.database_name %><br />
<% @database.tables.each do |table| %>
  Table: <%= table.table_name %><br />
  <% table.columns.each do |column| %>
    Column: <%= column.column_name %><br />
  <% end %>
<% end %>
like image 658
DavB Avatar asked Feb 03 '12 13:02

DavB


1 Answers

Unless I'm missing something, this actually looks okay to me, though you don't need the @tables and @columns in the controller unless you are really using them for something in the view.

controller:

class DatabasesController < ApplicationController
  def show
    @database = Database.find(params[:id], :include=>{:tables => [:columns]}) #eager load
    #or: @database = Database.where(:id => params[:id]).includes(:tables => [:columns]).first #eager load
    #or: @database = Database.find(params[:id]) #queries will be executed in the view
  end
end

view:

Database: <%= @database.database_name %><br />
<% @database.tables.each do |table| %>
  Table: <%= table.table_name %><br />
  <% table.columns.each do |column| %>
    Column: <%= column.column_name %><br />
  <% end %>
<% end %>
like image 189
miked Avatar answered Nov 09 '22 16:11

miked